summaryrefslogtreecommitdiff
path: root/apps/playlist.c
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2023-01-21 18:18:37 +0000
committerAidan MacDonald <amachronic@protonmail.com>2023-01-23 12:24:12 +0000
commit2a40d420120c051b9ee79a0086059b5f2059a013 (patch)
tree95014cc2dd1817e9e7cb24203745c9a151e8ac52 /apps/playlist.c
parent551e6aac500553bdd1732f20259bb09533227338 (diff)
downloadrockbox-2a40d420120c051b9ee79a0086059b5f2059a013.tar.gz
rockbox-2a40d420120c051b9ee79a0086059b5f2059a013.zip
playlist: Refactor control cache flush
Make background control file flushing work on non-dircache targets. It has nothing to do with dircache and doesn't belong in the dircache scan thread. Change-Id: I3f39261ccaebb5dce69e7db3d2e0c0c0c54f640b
Diffstat (limited to 'apps/playlist.c')
-rw-r--r--apps/playlist.c101
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
371static int flush_cached_control_unlocked(struct playlist_info* playlist);
372
373#if USING_STORAGE_CALLBACK
374static 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 */
375static int flush_cached_control(struct playlist_info* playlist) 393static 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
1888static void dc_flush_playlist_callback(void)
1889{
1890 struct playlist_info *playlist;
1891 playlist = &current_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 */
1906static void dc_thread_playlist(void) 1916static 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 = &current_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 = &current_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)
2110void playlist_shutdown(void) 2113void playlist_shutdown(void)
2111{ 2114{
2112 struct playlist_info* playlist = &current_playlist; 2115 struct playlist_info* playlist = &current_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/*