summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/lang/english.lang13
-rw-r--r--apps/misc.c8
-rw-r--r--apps/tagcache.c72
-rw-r--r--apps/tagtree.c78
-rw-r--r--firmware/common/dircache.c33
-rw-r--r--firmware/export/powermgmt.h1
-rw-r--r--firmware/include/dircache.h1
-rw-r--r--firmware/powermgmt.c6
8 files changed, 165 insertions, 47 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index a388884d69..f56c6aae90 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -8474,3 +8474,16 @@
*: ""
</voice>
</phrase>
+<phrase>
+ id: LANG_TAGCACHE_BUSY
+ desc: when trying to shutdown and tagcache is committing
+ <source>
+ *: "Tagcache is not ready"
+ </source>
+ <dest>
+ *: "Tagcache is not ready"
+ </dest>
+ <voice>
+ *: "Tagcache is not ready"
+ </voice>
+</phrase>
diff --git a/apps/misc.c b/apps/misc.c
index 6493e7b46f..ba360e5a91 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -44,6 +44,7 @@
#include "version.h"
#include "font.h"
#include "splash.h"
+#include "tagcache.h"
#ifdef HAVE_MMC
#include "ata_mmc.h"
#endif
@@ -487,6 +488,13 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter)
(void)parameter;
exit(0);
#else
+ if (tagcache_get_commit_step() > 0)
+ {
+ cancel_shutdown();
+ gui_syncsplash(HZ, true, str(LANG_TAGCACHE_BUSY));
+ return false;
+ }
+
#if defined(HAVE_CHARGING) && !defined(HAVE_POWEROFF_WHILE_CHARGING)
if(!charger_inserted())
#endif
diff --git a/apps/tagcache.c b/apps/tagcache.c
index b992a0d586..1c4ab6f3af 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -78,6 +78,8 @@ static int init_step;
/* Tag Cache Header version 'TCHxx' */
#define TAGCACHE_MAGIC 0x54434802
+#define TAGCACHE_RESERVE 32768
+
/* Tag database structures. */
/* Variable-length tag entry in tag files. */
@@ -575,6 +577,9 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
tagcache_search_finish(tcs);
memset(tcs, 0, sizeof(struct tagcache_search));
+ if (tagcache_get_commit_step() > 0)
+ return false;
+
tcs->position = sizeof(struct tagcache_header);
tcs->fd = -1;
tcs->type = tag;
@@ -1453,6 +1458,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
* table when the index gets resorted.
*/
tempbuf_insert(buf, loc + TAGFILE_MAX_ENTRIES, entry.idx_id);
+ yield();
}
}
else
@@ -1592,6 +1598,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
/* Skip to next. */
lseek(tmpfd, entry.data_length - entry.tag_offset[index_type] -
entry.tag_length[index_type], SEEK_CUR);
+ yield();
}
/* Sort the buffer data and write it to the index file. */
@@ -1634,6 +1641,7 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
error = true;
goto error_exit;
}
+ yield();
}
}
@@ -1730,7 +1738,8 @@ static bool build_index(int index_type, struct tagcache_header *h, int tmpfd)
error = true;
break ;
}
-
+
+ yield();
}
/* Finally write the uniqued tag index file. */
@@ -1796,6 +1805,25 @@ static bool commit(void)
return true;
}
+ /* Try to steal every buffer we can :) */
+#ifdef HAVE_TC_RAMCACHE
+ if (tempbuf_size == 0 && tagcache_size > 0)
+ {
+ ramcache = false;
+ tempbuf = (char *)(hdr + 1);
+ tempbuf_size = tagcache_size - sizeof(struct ramcache_header);
+ }
+#endif
+
+#ifdef HAVE_DIRCACHE
+ if (tempbuf_size == 0)
+ {
+ /* Try to steal the dircache buffer. */
+ tempbuf = dircache_steal_buffer(&tempbuf_size);
+ }
+#endif
+
+ /* And finally fail if there are no buffers available. */
if (tempbuf_size == 0)
{
logf("delaying commit until next boot");
@@ -1855,6 +1883,17 @@ static bool commit(void)
logf("tagcache committed");
remove(TAGCACHE_FILE_TEMP);
+#ifdef HAVE_DIRCACHE
+ /* Rebuild the dircache, if we stole the buffer. */
+ dircache_build(0);
+#endif
+
+#ifdef HAVE_TC_RAMCACHE
+ /* Reload tagcache. */
+ if (tagcache_size > 0 && !ramcache)
+ tagcache_start_scan();
+#endif
+
return true;
}
@@ -1912,7 +1951,7 @@ static bool allocate_tagcache(void)
* Now calculate the required cache size plus
* some extra space for alignment fixes.
*/
- tagcache_size = hdr->h.datasize + 128 +
+ tagcache_size = hdr->h.datasize + 128 + TAGCACHE_RESERVE +
sizeof(struct index_entry) * hdr->h.entry_count +
sizeof(struct ramcache_header) + TAG_COUNT*sizeof(void *);
logf("tagcache: %d bytes allocated.", tagcache_size);
@@ -1932,8 +1971,8 @@ static bool load_tagcache(void)
int i;
/* We really need the dircache for this. */
- while (!dircache_is_enabled())
- sleep(HZ);
+ if (!dircache_is_enabled())
+ return false;
logf("loading tagcache to ram...");
@@ -1943,6 +1982,14 @@ static bool load_tagcache(void)
logf("tagcache open failed");
return false;
}
+
+ if (read(fd, &hdr->h, sizeof(struct tagcache_header))
+ != sizeof(struct tagcache_header)
+ || hdr->h.magic != TAGCACHE_MAGIC)
+ {
+ logf("incorrect header");
+ return false;
+ }
lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
@@ -2252,17 +2299,13 @@ static void tagcache_thread(void)
bool check_done = false;
/* If the previous cache build/update was interrupted, commit
- * the changes first. */
+ * the changes first in foreground. */
cpu_boost(true);
allocate_tempbuf();
commit();
free_tempbuf();
cpu_boost(false);
-#ifdef HAVE_TC_RAMCACHE
- /* Allocate space for the tagcache if found on disk. */
- allocate_tagcache();
-#endif
tagcache_init_done = true;
while (1)
@@ -2288,7 +2331,7 @@ static void tagcache_thread(void)
if (!ramcache && global_settings.tagcache_ram)
load_ramcache();
- if (global_settings.tagcache_ram)
+ if (ramcache)
build_tagcache();
check_done = true;
@@ -2303,6 +2346,7 @@ static void tagcache_thread(void)
#ifndef SIMULATOR
case SYS_USB_CONNECTED:
+ logf("USB: TagCache");
usb_acknowledge(SYS_USB_CONNECTED_ACK);
usb_wait_for_disconnect(&tagcache_queue);
break ;
@@ -2322,7 +2366,7 @@ int tagcache_get_progress(void)
}
else
{
- if (hdr)
+ if (hdr && ramcache)
total_count = hdr->h.entry_count;
}
#endif
@@ -2362,6 +2406,12 @@ void tagcache_init(void)
{
tagcache_init_done = false;
init_step = 0;
+
+#ifdef HAVE_TC_RAMCACHE
+ /* Allocate space for the tagcache if found on disk. */
+ allocate_tagcache();
+#endif
+
queue_init(&tagcache_queue);
create_thread(tagcache_thread, tagcache_stack,
sizeof(tagcache_stack), tagcache_thread_name);
diff --git a/apps/tagtree.c b/apps/tagtree.c
index ccf926163a..875065a4ea 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -399,7 +399,9 @@ int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
0, csi->name);
}
- tagcache_search(tcs, csi->tagorder[extra]);
+ if (!tagcache_search(tcs, csi->tagorder[extra]))
+ return -1;
+
for (i = 0; i < extra; i++)
{
tagcache_search_add_filter(tcs, csi->tagorder[i], csi->result_seek[i]);
@@ -502,10 +504,29 @@ int retrieve_entries(struct tree_context *c, struct tagcache_search *tcs,
return total_count;
}
-int tagtree_load(struct tree_context* c)
+static int load_root(struct tree_context *c)
{
- int i;
struct tagentry *dptr = (struct tagentry *)c->dircache;
+ int i;
+
+ c->currtable = root;
+ for (i = 0; i < si_count; i++)
+ {
+ dptr->name = (si+i)->name;
+ dptr->newtable = navibrowse;
+ dptr->extraseek = i;
+ dptr++;
+ }
+
+ current_offset = 0;
+ current_entry_count = i;
+
+ return i;
+}
+
+int tagtree_load(struct tree_context* c)
+{
+ int count;
int table = c->currtable;
c->dentry_size = sizeof(struct tagentry);
@@ -517,25 +538,15 @@ int tagtree_load(struct tree_context* c)
c->currtable = table;
}
- switch (table) {
- case root: {
- for (i = 0; i < si_count; i++)
- {
- dptr->name = (si+i)->name;
- dptr->newtable = navibrowse;
- dptr->extraseek = i;
- dptr++;
- }
- c->dirlength = c->filesindir = i;
- current_offset = 0;
- current_entry_count = i;
-
- return c->dirlength;
- }
+ switch (table)
+ {
+ case root:
+ count = load_root(c);
+ break;
case navibrowse:
logf("navibrowse...");
- i = retrieve_entries(c, &tcs, 0, true);
+ count = retrieve_entries(c, &tcs, 0, true);
break;
default:
@@ -543,11 +554,17 @@ int tagtree_load(struct tree_context* c)
return -1;
}
+ if (count < 0)
+ {
+ c->dirlevel = 0;
+ count = load_root(c);
+ gui_syncsplash(HZ, true, str(LANG_TAGCACHE_BUSY));
+ }
/* The _total_ numer of entries available. */
- c->dirlength = c->filesindir = i;
+ c->dirlength = c->filesindir = count;
- return i;
+ return count;
}
int tagtree_enter(struct tree_context* c)
@@ -654,13 +671,15 @@ int tagtree_get_filename(struct tree_context* c, char *buf, int buflen)
entry = tagtree_get_entry(c, c->selected_item);
- tagcache_search(&tcs, tag_filename);
+ if (!tagcache_search(&tcs, tag_filename))
+ return -1;
+
tagcache_search_add_filter(&tcs, tag_title, entry->newtable);
if (!tagcache_get_next(&tcs))
{
tagcache_search_finish(&tcs);
- return -1;
+ return -2;
}
strncpy(buf, tcs.result, buflen-1);
@@ -681,7 +700,12 @@ static int tagtree_play_folder(struct tree_context* c)
}
cpu_boost(true);
- tagcache_search(&tcs, tag_filename);
+ if (!tagcache_search(&tcs, tag_filename))
+ {
+ gui_syncsplash(HZ, true, str(LANG_TAGCACHE_BUSY));
+ return -1;
+ }
+
for (i=0; i < c->filesindir; i++)
{
if (!show_search_progress(false, i))
@@ -717,7 +741,11 @@ struct tagentry* tagtree_get_entry(struct tree_context *c, int id)
/* Load the next chunk if necessary. */
if (realid >= current_entry_count || realid < 0)
{
- retrieve_entries(c, &tcs, MAX(0, id - (current_entry_count / 2)), false);
+ if (retrieve_entries(c, &tcs, MAX(0, id - (current_entry_count / 2)),
+ false) < 0)
+ {
+ return NULL;
+ }
realid = id - current_offset;
}
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c
index 9a0bcb631f..e5ee77c311 100644
--- a/firmware/common/dircache.c
+++ b/firmware/common/dircache.c
@@ -567,6 +567,7 @@ static int dircache_do_rebuild(void)
audiobuf += (long)((dircache_size & ~0x03) + 0x04);
audiobuf += DIRCACHE_RESERVE;
allocated_size = dircache_size + DIRCACHE_RESERVE;
+ reserve_used = 0;
}
return 1;
@@ -612,27 +613,20 @@ static void dircache_thread(void)
*/
int dircache_build(int last_size)
{
- if (dircache_initialized)
+ if (dircache_initialized || thread_enabled)
return -3;
- while (thread_enabled)
- sleep(1);
-
logf("Building directory cache");
if (dircache_size > 0)
{
- allocated_size = dircache_size + (DIRCACHE_RESERVE-reserve_used);
thread_enabled = true;
queue_post(&dircache_queue, DIRCACHE_BUILD, 0);
return 2;
}
- else
- {
- dircache_root = (struct dircache_entry *)(((long)audiobuf & ~0x03) + 0x04);
- dircache_size = 0;
- }
+
+ dircache_root = (struct dircache_entry *)(((long)audiobuf & ~0x03) + 0x04);
- if (last_size > DIRCACHE_RESERVE && last_size < DIRCACHE_LIMIT)
+ if (last_size > DIRCACHE_RESERVE && last_size < DIRCACHE_LIMIT )
{
allocated_size = last_size + DIRCACHE_RESERVE;
@@ -650,6 +644,23 @@ int dircache_build(int last_size)
}
/**
+ * Steal the allocated dircache buffer and disable dircache.
+ */
+void* dircache_steal_buffer(long *size)
+{
+ dircache_disable();
+ if (dircache_size == 0)
+ {
+ *size = 0;
+ return NULL;
+ }
+
+ *size = dircache_size + (DIRCACHE_RESERVE-reserve_used);
+
+ return dircache_root;
+}
+
+/**
* Main initialization function that must be called before any other
* operations within the dircache.
*/
diff --git a/firmware/export/powermgmt.h b/firmware/export/powermgmt.h
index da78857072..6c31aeec52 100644
--- a/firmware/export/powermgmt.h
+++ b/firmware/export/powermgmt.h
@@ -139,6 +139,7 @@ void set_sleep_timer(int seconds);
int get_sleep_timer(void);
void set_car_adapter_mode(bool setting);
void reset_poweroff_timer(void);
+void cancel_shutdown(void);
void shutdown_hw(void);
void sys_poweroff(void);
diff --git a/firmware/include/dircache.h b/firmware/include/dircache.h
index bd7308da68..6c214a9073 100644
--- a/firmware/include/dircache.h
+++ b/firmware/include/dircache.h
@@ -83,6 +83,7 @@ void dircache_init(void);
int dircache_load(const char *path);
int dircache_save(const char *path);
int dircache_build(int last_size);
+void* dircache_steal_buffer(long *size);
bool dircache_is_enabled(void);
int dircache_get_entry_count(void);
int dircache_get_cache_size(void);
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index 4c6db6d44c..15977caed6 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -1019,6 +1019,12 @@ void sys_poweroff(void)
queue_post(&button_queue, SYS_POWEROFF, NULL);
}
+void cancel_shutdown(void)
+{
+ logf("sys_cancel_shutdown()");
+ shutdown_timeout = 0;
+}
+
/* Various hardware housekeeping tasks relating to shutting down the jukebox */
void shutdown_hw(void)
{