Index: apps/playback.c =================================================================== --- apps/playback.c (revision 30927) +++ apps/playback.c (working copy) @@ -2557,6 +2557,9 @@ wipe_track_metadata(true); + /* reset when stopped to get maximum free memory */ + audio_reset_buffer(); + /* Go idle */ filling = STATE_IDLE; cancel_cpu_boost(); Index: apps/debug_menu.c =================================================================== --- apps/debug_menu.c (revision 30927) +++ apps/debug_menu.c (working copy) @@ -454,7 +454,9 @@ static bool dbg_buflib_allocs(void) { struct simplelist_info info; - simplelist_info_init(&info, "mem allocs", core_get_num_blocks(), NULL); + char title_buf[100]; + snprintf(title_buf, 99, "mem allocs (x%d bytes)", (int)sizeof(union buflib_data)); + simplelist_info_init(&info, title_buf, core_get_num_blocks(), NULL); info.get_name = bf_getname; info.action_callback = bf_action_cb; info.timeout = TIMEOUT_BLOCK; Index: firmware/buflib.c =================================================================== --- firmware/buflib.c (revision 30927) +++ firmware/buflib.c (working copy) @@ -90,6 +90,8 @@ #endif static union buflib_data* find_first_free(struct buflib_context *ctx); +static union buflib_data* find_best_free(struct buflib_context *ctx, + int size); static union buflib_data* find_block_before(struct buflib_context *ctx, union buflib_data* block, bool is_free); @@ -450,33 +452,25 @@ /* need to re-evaluate last before the loop because the last allocation * possibly made room in its front to fit this, so last would be wrong */ last = false; - for (block = find_first_free(ctx);;block += block_len) + block = find_best_free(ctx, size); + if(block == NULL) /* no suitable freed blocks */ { /* If the last used block extends all the way to the handle table, the * block "after" it doesn't have a header. Because of this, it's easier * to always find the end of allocation by saving a pointer, and always * calculate the free space at the end by comparing it to the - * last_handle pointer. - */ - if(block == ctx->alloc_end) - { - last = true; - block_len = ctx->last_handle - block; - if ((size_t)block_len < size) - block = NULL; - break; - } - block_len = block->val; - /* blocks with positive length are already allocated. */ - if(block_len > 0) - continue; - block_len = -block_len; - /* The search is first-fit, any fragmentation this causes will be - * handled at compaction. - */ - if ((size_t)block_len >= size) - break; + * last_handle pointer. */ + block = ctx->alloc_end; + last = true; + block_len = ctx->last_handle - block; + if (block_len < (int)size) + block = NULL; } + else + { + block_len = abs(block->val); + } + if (!block) { /* Try compacting if allocation failed */ @@ -529,6 +523,29 @@ return ret; } +/* find the best sized match for request, size in * + * multiples of sizeof(union buflib_data) */ +static union buflib_data* +find_best_free(struct buflib_context *ctx, int size) +{ + union buflib_data *tmp = ctx->buf_start; + union buflib_data *ret = NULL; + int ret_size = 0; + + while(tmp < ctx->alloc_end) + { + /* unallocated & big enough & none found so far or better match */ + if( (tmp->val < 0 && -tmp->val >= size) && + (( ret == NULL ) || ( -tmp->val < ret_size ))) + { + ret = tmp; + ret_size = -tmp->val; + } + tmp += abs( tmp->val ); + } + return ret; +} + /* Finds the free block before block, and returns NULL if it's not free */ static union buflib_data* find_block_before(struct buflib_context *ctx, union buflib_data* block, Index: firmware/common/dircache.c =================================================================== --- firmware/common/dircache.c (revision 30927) +++ firmware/common/dircache.c (working copy) @@ -48,6 +48,7 @@ #endif #include "rbpaths.h" +#include "splash.h" /* Queue commands. */ #define DIRCACHE_BUILD 1 @@ -942,7 +943,10 @@ dircache_handle = core_alloc_ex("dircache", available, &ops); if (dircache_handle <= 0) + { + splashf(HZ,"dircache memory allocation failed"); return -1; /* that was not successful, should try rebooting */ + } char* buf = core_get_data(dircache_handle); dircache_root = (struct dircache_entry*)ALIGN_UP(buf, sizeof(struct dircache_entry*)); @@ -953,7 +957,10 @@ /* Start a non-transparent rebuild. */ int res = dircache_do_rebuild(); if (res < 0) + { + splashf(HZ,"dircache_do_rebuild() failded"); goto fail; + } /* now compact the dircache buffer */ char* dst = ((char*)&dircache_root[entry_count] + DIRCACHE_RESERVE); @@ -961,6 +968,7 @@ if (offset <= 0) /* something went wrong */ { res = -1; + splashf(HZ,"insufficient reserve"); goto fail; }