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
This commit is contained in:
Thomas Martitz 2011-08-30 21:07:46 +00:00
parent c1ae789108
commit 7e14b935df
5 changed files with 77 additions and 41 deletions

View file

@ -189,16 +189,14 @@ static int dircache_callback(int action,const struct menu_item_ex *this_item)
switch (action) switch (action)
{ {
case ACTION_EXIT_MENUITEM: /* on exit */ case ACTION_EXIT_MENUITEM: /* on exit */
switch (global_settings.dircache) if (global_settings.dircache && !dircache_is_enabled())
{ {
case true: if (dircache_build(0) < 0)
if (!dircache_is_enabled()) splash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
splash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); }
break; else if (!global_settings.dircache && dircache_is_enabled())
case false: {
if (dircache_is_enabled()) dircache_disable();
dircache_disable();
break;
} }
break; break;
} }

View file

@ -3099,7 +3099,7 @@ static bool commit(void)
#ifdef HAVE_DIRCACHE #ifdef HAVE_DIRCACHE
/* Rebuild the dircache, if we stole the buffer. */ /* Rebuild the dircache, if we stole the buffer. */
if (dircache_buffer_stolen) if (dircache_buffer_stolen)
dircache_build(0); dircache_resume();
#endif #endif
#ifdef HAVE_TC_RAMCACHE #ifdef HAVE_TC_RAMCACHE

View file

@ -1216,7 +1216,7 @@ void tree_flush(void)
if (firmware_settings.initialized) if (firmware_settings.initialized)
dircache_save(); dircache_save();
# endif # endif
dircache_disable(); dircache_suspend();
} }
else else
{ {

View file

@ -41,6 +41,7 @@
#include "core_alloc.h" #include "core_alloc.h"
#include "dir.h" #include "dir.h"
#include "storage.h" #include "storage.h"
#include "audio.h"
#if CONFIG_RTC #if CONFIG_RTC
#include "time.h" #include "time.h"
#include "timefuncs.h" #include "timefuncs.h"
@ -845,7 +846,7 @@ static void dircache_thread(void)
case DIRCACHE_BUILD: case DIRCACHE_BUILD:
thread_enabled = true; thread_enabled = true;
if (dircache_do_rebuild() < 0) if (dircache_do_rebuild() < 0)
core_free(dircache_handle); dircache_handle = core_free(dircache_handle);
thread_enabled = false; thread_enabled = false;
break ; break ;
@ -887,8 +888,8 @@ int dircache_build(int last_size)
remove_dircache_file(); remove_dircache_file();
#endif #endif
/* Background build, dircache has been previously allocated */ /* Background build, dircache has been previously allocated and */
if (allocated_size > 0) if (allocated_size > MAX(last_size, 0))
{ {
d_names_start = d_names_end; d_names_start = d_names_end;
dircache_size = 0; dircache_size = 0;
@ -901,6 +902,9 @@ int dircache_build(int last_size)
return 2; return 2;
} }
if (dircache_handle > 0)
dircache_handle = core_free(dircache_handle);
if (last_size > DIRCACHE_RESERVE && last_size < DIRCACHE_LIMIT ) if (last_size > DIRCACHE_RESERVE && last_size < DIRCACHE_LIMIT )
{ {
allocated_size = last_size + DIRCACHE_RESERVE; allocated_size = last_size + DIRCACHE_RESERVE;
@ -922,12 +926,18 @@ int dircache_build(int last_size)
* and their corresponding d_name from the end * and their corresponding d_name from the end
* after generation the buffer will be compacted with DIRCACHE_RESERVE * after generation the buffer will be compacted with DIRCACHE_RESERVE
* free bytes inbetween */ * free bytes inbetween */
size_t got_size; size_t available = audio_buffer_available();
dircache_handle = core_alloc_maximum("dircache", &got_size, &ops); /* 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); char* buf = core_get_data(dircache_handle);
dircache_root = (struct dircache_entry*)ALIGN_UP(buf, dircache_root = (struct dircache_entry*)ALIGN_UP(buf,
sizeof(struct dircache_entry*)); 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; dircache_size = 0;
generate_dot_d_names(); generate_dot_d_names();
@ -967,29 +977,9 @@ int dircache_build(int last_size)
return res; return res;
fail: fail:
dircache_disable(); dircache_disable();
core_free(dircache_handle);
return res; 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 * Main initialization function that must be called before any other
* operations within the dircache. * operations within the dircache.
@ -1085,10 +1075,10 @@ int dircache_get_build_ticks(void)
} }
/** /**
* Disables the dircache. Usually called on shutdown or when * Disables dircache without freeing the buffer (so it can be re-enabled
* accepting a usb connection. * afterwards with dircache_resume() or dircache_build()), usually
*/ * called when accepting an usb connection */
void dircache_disable(void) void dircache_suspend(void)
{ {
int i; int i;
bool cache_in_use; bool cache_in_use;
@ -1117,6 +1107,52 @@ void dircache_disable(void)
entry_count = 0; 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. * Usermode function to return dircache_entry index to the given path.
*/ */

View file

@ -76,6 +76,8 @@ int dircache_get_cache_size(void);
int dircache_get_reserve_used(void); int dircache_get_reserve_used(void);
int dircache_get_build_ticks(void); int dircache_get_build_ticks(void);
void dircache_disable(void); void dircache_disable(void);
void dircache_suspend(void);
bool dircache_resume(void);
int dircache_get_entry_id(const char *filename); int dircache_get_entry_id(const char *filename);
size_t dircache_copy_path(int index, char *buf, size_t size); size_t dircache_copy_path(int index, char *buf, size_t size);