diff options
author | Thomas Martitz <kugel@rockbox.org> | 2011-08-30 14:01:45 +0000 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2011-08-30 14:01:45 +0000 |
commit | baa070cca6d459a7c5aed81f29e4cc4f6c7410b3 (patch) | |
tree | 5123360aea420b96e4a97a8e88cf51b4277152d9 /apps/playlist.c | |
parent | d0b72e25903574acb1cf9184a6052cdd646dbc37 (diff) | |
download | rockbox-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.c | 95 |
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 | */ | ||
1935 | static int move_callback(int handle, void* current, void* new) | ||
1936 | { | ||
1937 | (void)handle; | ||
1938 | struct playlist_info* playlist = ¤t_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 | |||
1952 | static 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 | */ |
1930 | void playlist_init(void) | 1959 | void 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 = ¤t_playlist_mutex; | 1981 | playlist->control_mutex = ¤t_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 | { | 3549 | reset_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 | { |