summaryrefslogtreecommitdiff
path: root/apps/playlist.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-08-30 14:01:45 +0000
committerThomas Martitz <kugel@rockbox.org>2011-08-30 14:01:45 +0000
commitbaa070cca6d459a7c5aed81f29e4cc4f6c7410b3 (patch)
tree5123360aea420b96e4a97a8e88cf51b4277152d9 /apps/playlist.c
parentd0b72e25903574acb1cf9184a6052cdd646dbc37 (diff)
downloadrockbox-baa070cca6d459a7c5aed81f29e4cc4f6c7410b3.tar.gz
rockbox-baa070cca6d459a7c5aed81f29e4cc4f6c7410b3.zip
GSoC/Buflib: Enable compaction in buflib.
This enables the ability to allocate (and free) memory dynamically without fragmentation, through compaction. This means allocations can move and fragmentation be reduced. Most changes are preparing Rockbox for this, which many times means adding a move callback which can temporarily disable movement when the corresponding code is in a critical section. For now, the audio buffer allocation has a central role, because it's the one having allocated most. This buffer is able to shrink itself, for which it needs to stop playback for a very short moment. For this, audio_buffer_available() returns the size of the audio buffer which can possibly be used by other allocations because the audio buffer can shrink. lastfm scrobbling and timestretch can now be toggled at runtime without requiring a reboot. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30381 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/playlist.c')
-rw-r--r--apps/playlist.c95
1 files changed, 63 insertions, 32 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index 77d8141af8..f6dda977f4 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -993,14 +993,14 @@ static int sort_playlist(struct playlist_info* playlist, bool start_current,
993 unsigned int current = playlist->indices[playlist->index]; 993 unsigned int current = playlist->indices[playlist->index];
994 994
995 if (playlist->amount > 0) 995 if (playlist->amount > 0)
996 qsort(playlist->indices, playlist->amount, 996 qsort((void*)playlist->indices, playlist->amount,
997 sizeof(playlist->indices[0]), compare); 997 sizeof(playlist->indices[0]), compare);
998 998
999#ifdef HAVE_DIRCACHE 999#ifdef HAVE_DIRCACHE
1000 /** We need to re-check the song names from disk because qsort can't 1000 /** We need to re-check the song names from disk because qsort can't
1001 * sort two arrays at once :/ 1001 * sort two arrays at once :/
1002 * FIXME: Please implement a better way to do this. */ 1002 * FIXME: Please implement a better way to do this. */
1003 memset(playlist->filenames, 0xff, playlist->max_playlist_size * sizeof(int)); 1003 memset((void*)playlist->filenames, 0xff, playlist->max_playlist_size * sizeof(int));
1004 queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); 1004 queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0);
1005#endif 1005#endif
1006 1006
@@ -1378,7 +1378,7 @@ static int get_filename(struct playlist_info* playlist, int index, int seek,
1378 1378
1379 if (playlist->in_ram && !control_file && max < 0) 1379 if (playlist->in_ram && !control_file && max < 0)
1380 { 1380 {
1381 max = strlcpy(tmp_buf, &playlist->buffer[seek], sizeof(tmp_buf)); 1381 max = strlcpy(tmp_buf, (char*)&playlist->buffer[seek], sizeof(tmp_buf));
1382 } 1382 }
1383 else if (max < 0) 1383 else if (max < 0)
1384 { 1384 {
@@ -1534,9 +1534,10 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
1534 break; 1534 break;
1535 } 1535 }
1536 1536
1537 files = tc->cache.entries; 1537 files = tree_get_entries(tc);
1538 num_files = tc->filesindir; 1538 num_files = tc->filesindir;
1539 1539
1540 tree_lock_cache(tc);
1540 for (i=0; i<num_files; i++) 1541 for (i=0; i<num_files; i++)
1541 { 1542 {
1542 /* user abort */ 1543 /* user abort */
@@ -1562,6 +1563,7 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
1562 start_dir = NULL; 1563 start_dir = NULL;
1563 } 1564 }
1564 } 1565 }
1566 tree_unlock_cache(tc);
1565 1567
1566 if (!exit) 1568 if (!exit)
1567 { 1569 {
@@ -1612,7 +1614,7 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
1612 return -2; 1614 return -2;
1613 } 1615 }
1614 1616
1615 files = tc->cache.entries; 1617 files = tree_get_entries(tc);
1616 num_files = tc->filesindir; 1618 num_files = tc->filesindir;
1617 1619
1618 for (i=0; i<num_files; i++) 1620 for (i=0; i<num_files; i++)
@@ -1629,6 +1631,7 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
1629 if (has_music) 1631 if (has_music)
1630 return 0; 1632 return 0;
1631 1633
1634 tree_lock_cache(tc);
1632 if (has_subdir && recurse) 1635 if (has_subdir && recurse)
1633 { 1636 {
1634 for (i=0; i<num_files; i++) 1637 for (i=0; i<num_files; i++)
@@ -1647,6 +1650,7 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
1647 } 1650 }
1648 } 1651 }
1649 } 1652 }
1653 tree_unlock_cache(tc);
1650 1654
1651 if (result < 0) 1655 if (result < 0)
1652 { 1656 {
@@ -1925,6 +1929,31 @@ static int rotate_index(const struct playlist_info* playlist, int index)
1925} 1929}
1926 1930
1927/* 1931/*
1932 * Need no movement protection since all 3 allocations are not passed to
1933 * other functions which can yield().
1934 */
1935static int move_callback(int handle, void* current, void* new)
1936{
1937 (void)handle;
1938 struct playlist_info* playlist = &current_playlist;
1939 if (current == playlist->indices)
1940 playlist->indices = new;
1941 else if (current == playlist->filenames)
1942 playlist->filenames = new;
1943 /* buffer can possibly point to a new buffer temporarily (playlist_save()).
1944 * just don't overwrite the pointer to that temp buffer */
1945 else if (current == playlist->buffer)
1946 playlist->buffer = new;
1947
1948 return BUFLIB_CB_OK;
1949}
1950
1951
1952static struct buflib_callbacks ops = {
1953 .move_callback = move_callback,
1954 .shrink_callback = NULL,
1955};
1956/*
1928 * Initialize playlist entries at startup 1957 * Initialize playlist entries at startup
1929 */ 1958 */
1930void playlist_init(void) 1959void playlist_init(void)
@@ -1941,20 +1970,23 @@ void playlist_init(void)
1941 playlist->fd = -1; 1970 playlist->fd = -1;
1942 playlist->control_fd = -1; 1971 playlist->control_fd = -1;
1943 playlist->max_playlist_size = global_settings.max_files_in_playlist; 1972 playlist->max_playlist_size = global_settings.max_files_in_playlist;
1944 handle = core_alloc("playlist idx", playlist->max_playlist_size * sizeof(int)); 1973 handle = core_alloc_ex("playlist idx",
1974 playlist->max_playlist_size * sizeof(int), &ops);
1945 playlist->indices = core_get_data(handle); 1975 playlist->indices = core_get_data(handle);
1946 playlist->buffer_size = 1976 playlist->buffer_size =
1947 AVERAGE_FILENAME_LENGTH * global_settings.max_files_in_dir; 1977 AVERAGE_FILENAME_LENGTH * global_settings.max_files_in_dir;
1948 handle = core_alloc("playlist buf", playlist->buffer_size); 1978 handle = core_alloc_ex("playlist buf",
1979 playlist->buffer_size, &ops);
1949 playlist->buffer = core_get_data(handle); 1980 playlist->buffer = core_get_data(handle);
1950 playlist->control_mutex = &current_playlist_mutex; 1981 playlist->control_mutex = &current_playlist_mutex;
1951 1982
1952 empty_playlist(playlist, true); 1983 empty_playlist(playlist, true);
1953 1984
1954#ifdef HAVE_DIRCACHE 1985#ifdef HAVE_DIRCACHE
1955 handle = core_alloc("playlist dc", playlist->max_playlist_size * sizeof(int)); 1986 handle = core_alloc_ex("playlist dc",
1987 playlist->max_playlist_size * sizeof(int), &ops);
1956 playlist->filenames = core_get_data(handle); 1988 playlist->filenames = core_get_data(handle);
1957 memset(playlist->filenames, 0xff, 1989 memset((void*)playlist->filenames, 0xff,
1958 playlist->max_playlist_size * sizeof(int)); 1990 playlist->max_playlist_size * sizeof(int));
1959 create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), 1991 create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack),
1960 0, playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND) 1992 0, playlist_thread_name IF_PRIO(, PRIORITY_BACKGROUND)
@@ -2404,7 +2436,7 @@ int playlist_add(const char *filename)
2404#endif 2436#endif
2405 playlist->amount++; 2437 playlist->amount++;
2406 2438
2407 strcpy(&playlist->buffer[playlist->buffer_end_pos], filename); 2439 strcpy((char*)&playlist->buffer[playlist->buffer_end_pos], filename);
2408 playlist->buffer_end_pos += len; 2440 playlist->buffer_end_pos += len;
2409 playlist->buffer[playlist->buffer_end_pos++] = '\0'; 2441 playlist->buffer[playlist->buffer_end_pos++] = '\0';
2410 2442
@@ -2731,6 +2763,7 @@ int playlist_create_ex(struct playlist_info* playlist,
2731 } 2763 }
2732 2764
2733 playlist->buffer_size = 0; 2765 playlist->buffer_size = 0;
2766 playlist->buffer_handle = -1;
2734 playlist->buffer = NULL; 2767 playlist->buffer = NULL;
2735 playlist->control_mutex = &created_playlist_mutex; 2768 playlist->control_mutex = &created_playlist_mutex;
2736 } 2769 }
@@ -2779,10 +2812,10 @@ int playlist_set_current(struct playlist_info* playlist)
2779 2812
2780 if (playlist->indices && playlist->indices != current_playlist.indices) 2813 if (playlist->indices && playlist->indices != current_playlist.indices)
2781 { 2814 {
2782 memcpy(current_playlist.indices, playlist->indices, 2815 memcpy((void*)current_playlist.indices, (void*)playlist->indices,
2783 playlist->max_playlist_size*sizeof(int)); 2816 playlist->max_playlist_size*sizeof(int));
2784#ifdef HAVE_DIRCACHE 2817#ifdef HAVE_DIRCACHE
2785 memcpy(current_playlist.filenames, playlist->filenames, 2818 memcpy((void*)current_playlist.filenames, (void*)playlist->filenames,
2786 playlist->max_playlist_size*sizeof(int)); 2819 playlist->max_playlist_size*sizeof(int));
2787#endif 2820#endif
2788 } 2821 }
@@ -3358,6 +3391,7 @@ int playlist_save(struct playlist_info* playlist, char *filename)
3358 char tmp_buf[MAX_PATH+1]; 3391 char tmp_buf[MAX_PATH+1];
3359 int result = 0; 3392 int result = 0;
3360 bool overwrite_current = false; 3393 bool overwrite_current = false;
3394 int old_handle = -1;
3361 char* old_buffer = NULL; 3395 char* old_buffer = NULL;
3362 size_t old_buffer_size = 0; 3396 size_t old_buffer_size = 0;
3363 3397
@@ -3380,15 +3414,16 @@ int playlist_save(struct playlist_info* playlist, char *filename)
3380 { 3414 {
3381 /* not enough buffer space to store updated indices */ 3415 /* not enough buffer space to store updated indices */
3382 /* Try to get a buffer */ 3416 /* Try to get a buffer */
3383 old_buffer = playlist->buffer; 3417 old_handle = playlist->buffer_handle;
3418 /* can ignore volatile here, because core_get_data() is called later */
3419 old_buffer = (char*)playlist->buffer;
3384 old_buffer_size = playlist->buffer_size; 3420 old_buffer_size = playlist->buffer_size;
3385 playlist->buffer = plugin_get_buffer((size_t*)&playlist->buffer_size); 3421 playlist->buffer = plugin_get_buffer((size_t*)&playlist->buffer_size);
3386 if (playlist->buffer_size < (int)(playlist->amount * sizeof(int))) 3422 if (playlist->buffer_size < (int)(playlist->amount * sizeof(int)))
3387 { 3423 {
3388 playlist->buffer = old_buffer;
3389 playlist->buffer_size = old_buffer_size;
3390 splash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); 3424 splash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR));
3391 return -1; 3425 result = -1;
3426 goto reset_old_buffer;
3392 } 3427 }
3393 } 3428 }
3394 3429
@@ -3409,12 +3444,8 @@ int playlist_save(struct playlist_info* playlist, char *filename)
3409 if (fd < 0) 3444 if (fd < 0)
3410 { 3445 {
3411 splash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); 3446 splash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR));
3412 if (old_buffer != NULL) 3447 result = -1;
3413 { 3448 goto reset_old_buffer;
3414 playlist->buffer = old_buffer;
3415 playlist->buffer_size = old_buffer_size;
3416 }
3417 return -1;
3418 } 3449 }
3419 3450
3420 display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), false); 3451 display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), false);
@@ -3514,11 +3545,12 @@ int playlist_save(struct playlist_info* playlist, char *filename)
3514 } 3545 }
3515 3546
3516 cpu_boost(false); 3547 cpu_boost(false);
3517 if (old_buffer != NULL) 3548
3518 { 3549reset_old_buffer:
3519 playlist->buffer = old_buffer; 3550 if (old_handle > 0)
3520 playlist->buffer_size = old_buffer_size; 3551 old_buffer = core_get_data(old_handle);
3521 } 3552 playlist->buffer = old_buffer;
3553 playlist->buffer_size = old_buffer_size;
3522 3554
3523 return result; 3555 return result;
3524} 3556}
@@ -3534,9 +3566,9 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
3534 char buf[MAX_PATH+1]; 3566 char buf[MAX_PATH+1];
3535 int result = 0; 3567 int result = 0;
3536 int num_files = 0; 3568 int num_files = 0;
3537 int i; 3569 int i;;
3538 struct entry *files;
3539 struct tree_context* tc = tree_get_context(); 3570 struct tree_context* tc = tree_get_context();
3571 struct tree_cache* cache = &tc->cache;
3540 int old_dirfilter = *(tc->dirfilter); 3572 int old_dirfilter = *(tc->dirfilter);
3541 3573
3542 if (!callback) 3574 if (!callback)
@@ -3552,7 +3584,6 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
3552 return -1; 3584 return -1;
3553 } 3585 }
3554 3586
3555 files = tc->cache.entries;
3556 num_files = tc->filesindir; 3587 num_files = tc->filesindir;
3557 3588
3558 /* we've overwritten the dircache so tree browser will need to be 3589 /* we've overwritten the dircache so tree browser will need to be
@@ -3568,6 +3599,7 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
3568 break; 3599 break;
3569 } 3600 }
3570 3601
3602 struct entry *files = core_get_data(cache->entries_handle);
3571 if (files[i].attr & ATTR_DIRECTORY) 3603 if (files[i].attr & ATTR_DIRECTORY)
3572 { 3604 {
3573 if (recurse) 3605 if (recurse)
@@ -3586,8 +3618,7 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
3586 result = -1; 3618 result = -1;
3587 break; 3619 break;
3588 } 3620 }
3589 3621
3590 files = tc->cache.entries;
3591 num_files = tc->filesindir; 3622 num_files = tc->filesindir;
3592 if (!num_files) 3623 if (!num_files)
3593 { 3624 {