From 7e14b935dfdcd808cfb0703d19a43efd11eeef16 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Tue, 30 Aug 2011 21:07:46 +0000 Subject: Dircache: Allow dircache to be enabled without reboot. Also add two dircache function, one of which does what dircache_disable() did previously as this now also frees the dircache buffer. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30393 a1c6a512-1295-4272-9138-f99709370657 --- firmware/common/dircache.c | 96 +++++++++++++++++++++++++++++++-------------- firmware/include/dircache.h | 2 + 2 files changed, 68 insertions(+), 30 deletions(-) (limited to 'firmware') diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 6b2260def3..c544abc567 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c @@ -41,6 +41,7 @@ #include "core_alloc.h" #include "dir.h" #include "storage.h" +#include "audio.h" #if CONFIG_RTC #include "time.h" #include "timefuncs.h" @@ -845,7 +846,7 @@ static void dircache_thread(void) case DIRCACHE_BUILD: thread_enabled = true; if (dircache_do_rebuild() < 0) - core_free(dircache_handle); + dircache_handle = core_free(dircache_handle); thread_enabled = false; break ; @@ -887,8 +888,8 @@ int dircache_build(int last_size) remove_dircache_file(); #endif - /* Background build, dircache has been previously allocated */ - if (allocated_size > 0) + /* Background build, dircache has been previously allocated and */ + if (allocated_size > MAX(last_size, 0)) { d_names_start = d_names_end; dircache_size = 0; @@ -901,6 +902,9 @@ int dircache_build(int last_size) return 2; } + if (dircache_handle > 0) + dircache_handle = core_free(dircache_handle); + if (last_size > DIRCACHE_RESERVE && last_size < DIRCACHE_LIMIT ) { allocated_size = last_size + DIRCACHE_RESERVE; @@ -922,12 +926,18 @@ int dircache_build(int last_size) * and their corresponding d_name from the end * after generation the buffer will be compacted with DIRCACHE_RESERVE * free bytes inbetween */ - size_t got_size; - dircache_handle = core_alloc_maximum("dircache", &got_size, &ops); + size_t available = audio_buffer_available(); + /* try to allocate at least 1MB, the more the better */ + if (available < 1<<20) available = 1<<20; + if (available > DIRCACHE_LIMIT) available = DIRCACHE_LIMIT; + + dircache_handle = core_alloc_ex("dircache", available, &ops); + if (dircache_handle <= 0) + 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*)); - d_names_start = d_names_end = buf + got_size - 1; + d_names_start = d_names_end = buf + available - 1; dircache_size = 0; generate_dot_d_names(); @@ -967,29 +977,9 @@ int dircache_build(int last_size) return res; fail: dircache_disable(); - core_free(dircache_handle); return res; } -/** - * Steal the allocated dircache buffer and disable dircache. - */ -void* dircache_steal_buffer(size_t *size) -{ - dircache_disable(); - if (dircache_size == 0) - { - *size = 0; - return NULL; - } - - /* since we give up the buffer (without freeing), it must not move anymore */ - dont_move = true; - *size = dircache_size + (DIRCACHE_RESERVE-reserve_used); - - return dircache_root; -} - /** * Main initialization function that must be called before any other * operations within the dircache. @@ -1085,10 +1075,10 @@ int dircache_get_build_ticks(void) } /** - * Disables the dircache. Usually called on shutdown or when - * accepting a usb connection. - */ -void dircache_disable(void) + * Disables dircache without freeing the buffer (so it can be re-enabled + * afterwards with dircache_resume() or dircache_build()), usually + * called when accepting an usb connection */ +void dircache_suspend(void) { int i; bool cache_in_use; @@ -1117,6 +1107,52 @@ void dircache_disable(void) entry_count = 0; } +/** + * Re-enables the dircache if previous suspended by dircache_suspend + * or dircache_steal_buffer(), re-using the already allocated buffer + * + * Returns true if the background build is started, false otherwise + * (e.g. if no buffer was previously allocated) + */ +bool dircache_resume(void) +{ + bool ret = allocated_size > 0; + if (ret) /* only resume if already allocated */ + ret = (dircache_build(0) > 0); + + return (allocated_size > 0); +} + +/** + * Disables the dircache entirely. Usually called on shutdown or when + * deactivated + */ +void dircache_disable(void) +{ + dircache_suspend(); + dircache_handle = core_free(dircache_handle); + dircache_size = allocated_size = 0; +} + +/** + * Steal the allocated dircache buffer and disable dircache. + */ +void* dircache_steal_buffer(size_t *size) +{ + dircache_suspend(); + if (dircache_size == 0) + { + *size = 0; + return NULL; + } + + /* since we give up the buffer (without freeing), it must not move anymore */ + dont_move = true; + *size = dircache_size + (DIRCACHE_RESERVE-reserve_used); + + return dircache_root; +} + /** * Usermode function to return dircache_entry index to the given path. */ diff --git a/firmware/include/dircache.h b/firmware/include/dircache.h index 6beeeb6c23..019ccf49b7 100644 --- a/firmware/include/dircache.h +++ b/firmware/include/dircache.h @@ -76,6 +76,8 @@ int dircache_get_cache_size(void); int dircache_get_reserve_used(void); int dircache_get_build_ticks(void); void dircache_disable(void); +void dircache_suspend(void); +bool dircache_resume(void); int dircache_get_entry_id(const char *filename); size_t dircache_copy_path(int index, char *buf, size_t size); -- cgit v1.2.3