diff options
-rw-r--r-- | apps/playlist.c | 101 |
1 files changed, 53 insertions, 48 deletions
diff --git a/apps/playlist.c b/apps/playlist.c index 77e3d20151..48933664a0 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -368,26 +368,40 @@ static void sync_control(struct playlist_info* playlist, bool force) | |||
368 | } | 368 | } |
369 | } | 369 | } |
370 | 370 | ||
371 | static int flush_cached_control_unlocked(struct playlist_info* playlist); | ||
372 | |||
373 | #if USING_STORAGE_CALLBACK | ||
374 | static void flush_control_cache_idle_cb(unsigned short id, void *ev, void *ud) | ||
375 | { | ||
376 | (void)id; | ||
377 | (void)ev; | ||
378 | |||
379 | struct playlist_info *playlist = ud; | ||
380 | playlist_mutex_lock(&playlist->mutex); | ||
381 | |||
382 | if (playlist->control_fd >= 0) | ||
383 | flush_cached_control_unlocked(playlist); | ||
384 | |||
385 | playlist_mutex_unlock(&playlist->mutex); | ||
386 | } | ||
387 | #endif | ||
388 | |||
371 | /* | 389 | /* |
372 | * Flush any cached control commands to disk. Called when playlist is being | 390 | * Flush any cached control commands to disk. Called when playlist is being |
373 | * modified. Returns 0 on success and -1 on failure. | 391 | * modified. Returns 0 on success and -1 on failure. |
374 | */ | 392 | */ |
375 | static int flush_cached_control(struct playlist_info* playlist) | 393 | static int flush_cached_control_unlocked(struct playlist_info* playlist) |
376 | { | 394 | { |
377 | int result = 0; | 395 | int result = 0; |
378 | int i; | ||
379 | 396 | ||
380 | if (playlist->num_cached <= 0) | 397 | if (playlist->num_cached <= 0) |
381 | return 0; | 398 | return 0; |
382 | 399 | ||
383 | playlist_mutex_lock(&(playlist->mutex)); | ||
384 | |||
385 | lseek(playlist->control_fd, 0, SEEK_END); | 400 | lseek(playlist->control_fd, 0, SEEK_END); |
386 | 401 | ||
387 | for (i=0; i<playlist->num_cached; i++) | 402 | for (int i = 0; i < playlist->num_cached; i++) |
388 | { | 403 | { |
389 | struct playlist_control_cache* cache = &(playlist->control_cache[i]); | 404 | struct playlist_control_cache* cache = &playlist->control_cache[i]; |
390 | |||
391 | switch (cache->command) | 405 | switch (cache->command) |
392 | { | 406 | { |
393 | case PLAYLIST_COMMAND_PLAYLIST: | 407 | case PLAYLIST_COMMAND_PLAYLIST: |
@@ -432,16 +446,24 @@ static int flush_cached_control(struct playlist_info* playlist) | |||
432 | { | 446 | { |
433 | playlist->num_cached = 0; | 447 | playlist->num_cached = 0; |
434 | playlist->pending_control_sync = true; | 448 | playlist->pending_control_sync = true; |
435 | |||
436 | result = 0; | 449 | result = 0; |
437 | } | 450 | } |
438 | else | 451 | else |
439 | { | 452 | { |
453 | /* At this point the control file is likely corrupted. We still | ||
454 | * need to clear the cache to avoid a buffer overflow from the | ||
455 | * next command. It's unsafe to splash() because this function | ||
456 | * can be called off the main thread. | ||
457 | * | ||
458 | * TODO: recover from failed playlist control file writes. | ||
459 | */ | ||
460 | playlist->num_cached = 0; | ||
440 | result = -1; | 461 | result = -1; |
441 | splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); | ||
442 | } | 462 | } |
443 | 463 | ||
444 | playlist_mutex_unlock(&(playlist->mutex)); | 464 | #if USING_STORAGE_CALLBACK |
465 | remove_event_ex(DISK_EVENT_SPINUP, flush_control_cache_idle_cb, playlist); | ||
466 | #endif | ||
445 | return result; | 467 | return result; |
446 | } | 468 | } |
447 | 469 | ||
@@ -457,9 +479,8 @@ static int update_control(struct playlist_info* playlist, | |||
457 | struct playlist_control_cache* cache; | 479 | struct playlist_control_cache* cache; |
458 | bool flush = false; | 480 | bool flush = false; |
459 | 481 | ||
460 | playlist_mutex_lock(&(playlist->mutex)); | 482 | playlist_mutex_lock(&playlist->mutex); |
461 | 483 | cache = &playlist->control_cache[playlist->num_cached++]; | |
462 | cache = &(playlist->control_cache[playlist->num_cached++]); | ||
463 | 484 | ||
464 | cache->command = command; | 485 | cache->command = command; |
465 | cache->i1 = i1; | 486 | cache->i1 = i1; |
@@ -473,23 +494,26 @@ static int update_control(struct playlist_info* playlist, | |||
473 | case PLAYLIST_COMMAND_PLAYLIST: | 494 | case PLAYLIST_COMMAND_PLAYLIST: |
474 | case PLAYLIST_COMMAND_ADD: | 495 | case PLAYLIST_COMMAND_ADD: |
475 | case PLAYLIST_COMMAND_QUEUE: | 496 | case PLAYLIST_COMMAND_QUEUE: |
476 | #ifndef HAVE_DIRCACHE | 497 | /* |
477 | case PLAYLIST_COMMAND_DELETE: | 498 | * These commands can use s1/s2, which may point to |
478 | case PLAYLIST_COMMAND_RESET: | 499 | * stack allocated buffers, so flush them immediately. |
479 | #endif | 500 | */ |
480 | flush = true; | 501 | flush = true; |
481 | break; | 502 | break; |
482 | case PLAYLIST_COMMAND_SHUFFLE: | 503 | default: |
483 | case PLAYLIST_COMMAND_UNSHUFFLE: | ||
484 | default: /* only flush when needed */ | ||
485 | break; | 504 | break; |
486 | } | 505 | } |
487 | 506 | ||
488 | if (flush || playlist->num_cached == PLAYLIST_MAX_CACHE) | 507 | if (flush || playlist->num_cached == PLAYLIST_MAX_CACHE) |
489 | result = flush_cached_control(playlist); | 508 | result = flush_cached_control_unlocked(playlist); |
490 | 509 | else | |
491 | playlist_mutex_unlock(&(playlist->mutex)); | 510 | { |
511 | #if USING_STORAGE_CALLBACK | ||
512 | add_event_ex(DISK_EVENT_SPINUP, true, flush_control_cache_idle_cb, playlist); | ||
513 | #endif | ||
514 | } | ||
492 | 515 | ||
516 | playlist_mutex_unlock(&playlist->mutex); | ||
493 | return result; | 517 | return result; |
494 | } | 518 | } |
495 | 519 | ||
@@ -1885,30 +1909,16 @@ static int get_next_index(const struct playlist_info* playlist, int steps, | |||
1885 | } | 1909 | } |
1886 | 1910 | ||
1887 | #ifdef HAVE_DIRCACHE | 1911 | #ifdef HAVE_DIRCACHE |
1888 | static void dc_flush_playlist_callback(void) | ||
1889 | { | ||
1890 | struct playlist_info *playlist; | ||
1891 | playlist = ¤t_playlist; | ||
1892 | if (playlist->control_fd >= 0) | ||
1893 | { | ||
1894 | flush_cached_control(playlist); | ||
1895 | sync_control(playlist, true); | ||
1896 | } | ||
1897 | else if (playlist->control_fd < 0 || playlist->num_cached <= 0) | ||
1898 | unregister_storage_idle_func(dc_flush_playlist_callback, false); | ||
1899 | } | ||
1900 | |||
1901 | /** | 1912 | /** |
1902 | * Thread to update filename pointers to dircache on background | 1913 | * Thread to update filename pointers to dircache on background |
1903 | * without affecting playlist load up performance. This thread also flushes | 1914 | * without affecting playlist load up performance. |
1904 | * any pending control commands when the disk spins up. | ||
1905 | */ | 1915 | */ |
1906 | static void dc_thread_playlist(void) | 1916 | static void dc_thread_playlist(void) |
1907 | { | 1917 | { |
1908 | struct queue_event ev; | 1918 | struct queue_event ev; |
1909 | static char tmp[MAX_PATH+1]; | 1919 | static char tmp[MAX_PATH+1]; |
1910 | 1920 | ||
1911 | struct playlist_info *playlist; | 1921 | struct playlist_info *playlist = ¤t_playlist; |
1912 | struct dircache_fileref *dcfrefs; | 1922 | struct dircache_fileref *dcfrefs; |
1913 | int index; | 1923 | int index; |
1914 | int seek; | 1924 | int seek; |
@@ -1941,13 +1951,6 @@ static void dc_thread_playlist(void) | |||
1941 | timeout or 5s, whichever is less */ | 1951 | timeout or 5s, whichever is less */ |
1942 | case SYS_TIMEOUT: | 1952 | case SYS_TIMEOUT: |
1943 | { | 1953 | { |
1944 | playlist = ¤t_playlist; | ||
1945 | if (playlist->control_fd >= 0) | ||
1946 | { | ||
1947 | if (playlist->num_cached > 0) | ||
1948 | register_storage_idle_func(dc_flush_playlist_callback); | ||
1949 | } | ||
1950 | |||
1951 | if (!playlist->dcfrefs_handle || playlist->amount <= 0) | 1954 | if (!playlist->dcfrefs_handle || playlist->amount <= 0) |
1952 | break ; | 1955 | break ; |
1953 | 1956 | ||
@@ -2110,13 +2113,15 @@ void playlist_init(void) | |||
2110 | void playlist_shutdown(void) | 2113 | void playlist_shutdown(void) |
2111 | { | 2114 | { |
2112 | struct playlist_info* playlist = ¤t_playlist; | 2115 | struct playlist_info* playlist = ¤t_playlist; |
2116 | playlist_mutex_lock(&playlist->mutex); | ||
2113 | 2117 | ||
2114 | if (playlist->control_fd >= 0) | 2118 | if (playlist->control_fd >= 0) |
2115 | { | 2119 | { |
2116 | flush_cached_control(playlist); | 2120 | flush_cached_control_unlocked(playlist); |
2117 | |||
2118 | close_playlist_control_file(playlist); | 2121 | close_playlist_control_file(playlist); |
2119 | } | 2122 | } |
2123 | |||
2124 | playlist_mutex_unlock(&playlist->mutex); | ||
2120 | } | 2125 | } |
2121 | 2126 | ||
2122 | /* | 2127 | /* |