summaryrefslogtreecommitdiff
path: root/firmware/common/dircache.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-08-30 21:07:46 +0000
committerThomas Martitz <kugel@rockbox.org>2011-08-30 21:07:46 +0000
commit7e14b935dfdcd808cfb0703d19a43efd11eeef16 (patch)
tree57834f71db1bbaaabf7872d8609f8254371377cf /firmware/common/dircache.c
parentc1ae789108942f3270fb90bd5a088adfee126333 (diff)
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
Diffstat (limited to 'firmware/common/dircache.c')
-rw-r--r--firmware/common/dircache.c96
1 files changed, 66 insertions, 30 deletions
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,30 +977,10 @@ 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;
@@ -1118,6 +1108,52 @@ void dircache_disable(void)
}
/**
+ * 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.
*/
static int dircache_get_entry_id_ex(const char *filename, bool go_down)