summaryrefslogtreecommitdiff
path: root/apps/plugins/tagcache/tagcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/tagcache/tagcache.c')
-rw-r--r--apps/plugins/tagcache/tagcache.c583
1 files changed, 511 insertions, 72 deletions
diff --git a/apps/plugins/tagcache/tagcache.c b/apps/plugins/tagcache/tagcache.c
index 55ca2e2695..cce9efbed9 100644
--- a/apps/plugins/tagcache/tagcache.c
+++ b/apps/plugins/tagcache/tagcache.c
@@ -22,16 +22,19 @@
22/*Plugin Includes*/ 22/*Plugin Includes*/
23 23
24#include "plugin.h" 24#include "plugin.h"
25#include "errno.h"
26
25/* Redefinitons of ANSI C functions. */ 27/* Redefinitons of ANSI C functions. */
26#include "lib/wrappers.h" 28#include "lib/wrappers.h"
27#include "lib/helper.h" 29#include "lib/helper.h"
28 30
29static void thread_create(void); 31static void thread_create(void);
30static void thread(void); /* the thread running it all */ 32static void thread(void); /* the thread running commit*/
31static void allocate_tempbuf(void); 33static void allocate_tempbuf(void);
32static void free_tempbuf(void); 34static void free_tempbuf(void);
33static bool do_timed_yield(void); 35static bool do_timed_yield(void);
34static void _log(const char *fmt, ...); 36static void _log(const char *fmt, ...);
37static bool logdump(bool append);
35/*Aliases*/ 38/*Aliases*/
36#if 0 39#if 0
37#ifdef ROCKBOX_HAS_LOGF 40#ifdef ROCKBOX_HAS_LOGF
@@ -41,7 +44,6 @@ static void _log(const char *fmt, ...);
41#endif 44#endif
42#endif 45#endif
43 46
44
45#define logf _log 47#define logf _log
46#define sleep rb->sleep 48#define sleep rb->sleep
47#define qsort rb->qsort 49#define qsort rb->qsort
@@ -49,6 +51,7 @@ static void _log(const char *fmt, ...);
49#define write(x,y,z) rb->write(x,y,z) 51#define write(x,y,z) rb->write(x,y,z)
50#define ftruncate rb->ftruncate 52#define ftruncate rb->ftruncate
51#define remove rb->remove 53#define remove rb->remove
54#define rename rb->rename
52 55
53#define vsnprintf rb->vsnprintf 56#define vsnprintf rb->vsnprintf
54#define mkdir rb->mkdir 57#define mkdir rb->mkdir
@@ -60,20 +63,26 @@ static void _log(const char *fmt, ...);
60 63
61#define current_tick (*rb->current_tick) 64#define current_tick (*rb->current_tick)
62#define crc_32(x,y,z) rb->crc_32(x,y,z) 65#define crc_32(x,y,z) rb->crc_32(x,y,z)
66#define plugin_get_buffer rb->plugin_get_buffer
63 67
64
65#if !defined(SIMULATOR) && !defined(APPLICATION)
66
67#define errno (*rb->__errno())
68#endif
69#define ENOENT 2 /* No such file or directory */
70#define EEXIST 17 /* File exists */
71#define MAX_LOG_SIZE 16384 68#define MAX_LOG_SIZE 16384
72 69
73#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF) 70#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF)
74#define EV_ACTION MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x02)
75#define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01) 71#define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01)
76 72
73#define BACKUP_DIRECTORY PLUGIN_APPS_DATA_DIR "/db_commit"
74
75#define RC_SUCCESS 0
76#define RC_USER_CANCEL 2
77
78enum fcpy_op_flags
79{
80 FCPY_MOVE = 0x00, /* Is a move operation (default) */
81 FCPY_COPY = 0x01, /* Is a copy operation */
82 FCPY_OVERWRITE = 0x02, /* Overwrite destination */
83 FCPY_EXDEV = 0x04, /* Actually copy/move across volumes */
84};
85
77/* communication to the worker thread */ 86/* communication to the worker thread */
78static struct 87static struct
79{ 88{
@@ -85,6 +94,23 @@ static struct
85 long last_useraction_tick; 94 long last_useraction_tick;
86} gThread; 95} gThread;
87 96
97/* status of db and commit */
98static struct
99{
100 long last_check;
101 bool do_commit;
102 bool auto_commit;
103 bool commit_ready;
104 bool db_exists;
105 bool have_backup;
106 bool bu_exists;
107} gStatus;
108
109static unsigned char logbuffer[MAX_LOG_SIZE + 1];
110static int log_font_h = -1;
111static int logindex;
112static bool logwrap;
113static bool logenabled = true;
88 114
89/*Support Fns*/ 115/*Support Fns*/
90/* open but with a builtin printf for assembling the path */ 116/* open but with a builtin printf for assembling the path */
@@ -103,8 +129,6 @@ int open_pathfmt(char *buf, size_t size, int oflag, const char *pathfmt, ...)
103 129
104static void sleep_yield(void) 130static void sleep_yield(void)
105{ 131{
106 rb->queue_remove_from_head(&gThread.queue, EV_ACTION);
107 rb->queue_post(&gThread.queue, EV_ACTION, 0);
108 sleep(1); 132 sleep(1);
109 #undef yield 133 #undef yield
110 rb->yield(); 134 rb->yield();
@@ -159,18 +183,10 @@ bool user_check_tag(int index_type, char* build_idx_buf)
159/* paste the whole tagcache.c file */ 183/* paste the whole tagcache.c file */
160#include "../tagcache.c" 184#include "../tagcache.c"
161 185
162static bool logdump(bool append);
163static unsigned char logbuffer[MAX_LOG_SIZE + 1];
164static int log_font_h = -1;
165static int logindex;
166static bool logwrap;
167static bool logenabled = true;
168
169static void check_logindex(void) 186static void check_logindex(void)
170{ 187{
171 if(logindex >= MAX_LOG_SIZE) 188 if(logindex >= MAX_LOG_SIZE)
172 { 189 {
173 /* wrap */
174 logdump(true); 190 logdump(true);
175 //logwrap = true; 191 //logwrap = true;
176 logindex = 0; 192 logindex = 0;
@@ -196,7 +212,6 @@ static void _log(const char *fmt, ...)
196 return; 212 return;
197 } 213 }
198 214
199
200 #ifdef USB_ENABLE_SERIAL 215 #ifdef USB_ENABLE_SERIAL
201 int old_logindex = logindex; 216 int old_logindex = logindex;
202 #endif 217 #endif
@@ -291,13 +306,11 @@ static bool logdisplay(void)
291 /* if negative, will be set 0 to zero later */ 306 /* if negative, will be set 0 to zero later */
292 } 307 }
293 308
294
295 rb->lcd_clear_display(); 309 rb->lcd_clear_display();
296 310
297 if(gThread.user_index < 0 || gThread.user_index >= MAX_LOG_SIZE) 311 if(gThread.user_index < 0 || gThread.user_index >= MAX_LOG_SIZE)
298 gThread.user_index = 0; 312 gThread.user_index = 0;
299 313
300
301 if(logwrap) 314 if(logwrap)
302 i = logindex; 315 i = logindex;
303 else 316 else
@@ -373,7 +386,7 @@ static bool logdump(bool append)
373 /* nothing is logged just yet */ 386 /* nothing is logged just yet */
374 return false; 387 return false;
375 } 388 }
376 if (!append) 389 if (append)
377 { 390 {
378 flags = O_CREAT|O_WRONLY|O_APPEND; 391 flags = O_CREAT|O_WRONLY|O_APPEND;
379 } 392 }
@@ -431,7 +444,6 @@ static bool do_timed_yield(void)
431 static long wakeup_tick = 0; 444 static long wakeup_tick = 0;
432 if (TIME_AFTER(current_tick, wakeup_tick)) 445 if (TIME_AFTER(current_tick, wakeup_tick))
433 { 446 {
434
435 yield(); 447 yield();
436 448
437 wakeup_tick = current_tick + (HZ/5); 449 wakeup_tick = current_tick + (HZ/5);
@@ -440,6 +452,402 @@ static bool do_timed_yield(void)
440 return false; 452 return false;
441} 453}
442 454
455/* copy/move a file */
456static int fcpy(const char *src, const char *target,
457 unsigned int flags, bool (*poll_cancel)(const char *))
458{
459 int rc = -1;
460
461 while (!(flags & (FCPY_COPY | FCPY_EXDEV))) {
462 if ((flags & FCPY_OVERWRITE) || !file_exists(target)) {
463 /* Rename and possibly overwrite the file */
464 if (poll_cancel && poll_cancel(src)) {
465 rc = RC_USER_CANCEL;
466 } else {
467 rc = rename(src, target);
468 }
469
470 #ifdef HAVE_MULTIVOLUME
471 if (rc < 0 && errno == EXDEV) {
472 /* Failed because cross volume rename doesn't work; force
473 a move instead */
474 flags |= FCPY_EXDEV;
475 break;
476 }
477 #endif /* HAVE_MULTIVOLUME */
478 }
479
480 return rc;
481 }
482
483 /* See if we can get the plugin buffer for the file copy buffer */
484 size_t buffersize;
485 char *buffer = (char *) plugin_get_buffer(&buffersize);
486 if (buffer == NULL || buffersize < 512) {
487 /* Not large enough, try for a disk sector worth of stack
488 instead */
489 buffersize = 512;
490 buffer = (char *)alloca(buffersize);
491 }
492
493 if (buffer == NULL) {
494 return -1;
495 }
496
497 buffersize &= ~0x1ff; /* Round buffer size to multiple of sector
498 size */
499
500 int src_fd = open(src, O_RDONLY);
501 if (src_fd >= 0) {
502 int oflag = O_WRONLY|O_CREAT;
503
504 if (!(flags & FCPY_OVERWRITE)) {
505 oflag |= O_EXCL;
506 }
507
508 int target_fd = open(target, oflag, 0666);
509 if (target_fd >= 0) {
510 off_t total_size = 0;
511 off_t next_cancel_test = 0; /* No excessive button polling */
512
513 rc = RC_SUCCESS;
514
515 while (rc == RC_SUCCESS) {
516 if (total_size >= next_cancel_test) {
517 next_cancel_test = total_size + 0x10000;
518 if (poll_cancel && poll_cancel(src)) {
519 rc = RC_USER_CANCEL;
520 break;
521 }
522 }
523
524 ssize_t bytesread = read(src_fd, buffer, buffersize);
525 if (bytesread <= 0) {
526 if (bytesread < 0) {
527 rc = -1;
528 }
529 /* else eof on buffer boundary; nothing to write */
530 break;
531 }
532
533 ssize_t byteswritten = write(target_fd, buffer, bytesread);
534 if (byteswritten < bytesread) {
535 /* Some I/O error */
536 rc = -1;
537 break;
538 }
539
540 total_size += byteswritten;
541
542 if (bytesread < (ssize_t)buffersize) {
543 /* EOF with trailing bytes */
544 break;
545 }
546 }
547
548 if (rc == RC_SUCCESS) {
549 /* If overwriting, set the correct length if original was
550 longer */
551 rc = ftruncate(target_fd, total_size);
552 }
553
554 close(target_fd);
555
556 if (rc != RC_SUCCESS) {
557 /* Copy failed. Cleanup. */
558 remove(target);
559 }
560 }
561
562 close(src_fd);
563 }
564
565 if (rc == RC_SUCCESS && !(flags & FCPY_COPY)) {
566 /* Remove the source file */
567 rc = remove(src);
568 }
569
570 return rc;
571}
572
573static bool backup_restore_tagcache(bool backup)
574{
575 struct master_header tcmh;
576 char path[MAX_PATH];
577 char bu_path[MAX_PATH];
578 int fd;
579 int rc;
580
581 if (backup)
582 {
583 if (!rb->dir_exists(BACKUP_DIRECTORY))
584 mkdir(BACKUP_DIRECTORY);
585 snprintf(path, sizeof(path), "%s/"TAGCACHE_FILE_MASTER, tc_stat.db_path);
586 snprintf(bu_path, sizeof(bu_path), "%s/"TAGCACHE_FILE_MASTER, BACKUP_DIRECTORY);
587 }
588 else
589 {
590 if (!rb->dir_exists(BACKUP_DIRECTORY))
591 return false;
592 snprintf(path, sizeof(path), "%s/"TAGCACHE_FILE_MASTER, BACKUP_DIRECTORY);
593 snprintf(bu_path, sizeof(bu_path), "%s/"TAGCACHE_FILE_MASTER, tc_stat.db_path);
594 }
595
596 fd = open(path, O_RDONLY, 0666);
597
598 if (fd >= 0)
599 {
600 rc = read(fd, &tcmh, sizeof(struct master_header));
601 close(fd);
602 if (rc != sizeof(struct master_header))
603 {
604 logf("master file read failed");
605 return false;
606 }
607 int entries = tcmh.tch.entry_count;
608
609 logf("master file %d entries", entries);
610 if (backup)
611 logf("backup db to %s", BACKUP_DIRECTORY);
612 else
613 logf("restore db to %s", tc_stat.db_path);
614
615 if (entries > 0)
616 {
617 logf("%s", path);
618 fcpy(path, bu_path, FCPY_COPY|FCPY_OVERWRITE, NULL);
619
620 for (int i = 0; i < TAG_COUNT; i++)
621 {
622 if (TAGCACHE_IS_NUMERIC(i))
623 continue;
624 snprintf(path, sizeof(path),
625 "%s/"TAGCACHE_FILE_INDEX, tc_stat.db_path, i);
626
627 snprintf(bu_path, sizeof(bu_path),
628 "%s/"TAGCACHE_FILE_INDEX, BACKUP_DIRECTORY, i);
629 /* Note: above we swapped paths in the snprintf call here we swap variables */
630 if (backup)
631 {
632 logf("%s", path);
633 if (fcpy(path, bu_path, FCPY_COPY|FCPY_OVERWRITE, NULL) < 0)
634 goto failed;
635 gStatus.have_backup = true;
636 }
637 else
638 {
639 logf("%s", bu_path);
640 if (fcpy(bu_path, path, FCPY_COPY|FCPY_OVERWRITE, NULL) < 0)
641 goto failed;
642 }
643 }
644 }
645 return true;
646 }
647failed:
648 if (backup)
649 {
650 logf("failed backup");
651 }
652
653 return false;
654}
655
656/* asks the user if they wish to quit */
657static bool confirm_quit(void)
658{
659 const struct text_message prompt =
660 { (const char*[]) {"Are you sure?", "This will abort commit."}, 2};
661 enum yesno_res response = rb->gui_syncyesno_run(&prompt, NULL, NULL);
662 return (response == YESNO_YES);
663}
664
665/* asks the user if they wish to backup/restore */
666static bool prompt_backup_restore(bool backup)
667{
668 const struct text_message bu_prompt = { (const char*[]) {"Backup database?"}, 1};
669 const struct text_message re_prompt =
670 { (const char*[]) {"Error committing,", "Restore database?"}, 2};
671 enum yesno_res response =
672 rb->gui_syncyesno_run(backup ? &bu_prompt:&re_prompt, NULL, NULL);
673 if(response == YESNO_YES)
674 return backup_restore_tagcache(backup);
675 return true;
676}
677
678static const char* list_get_name_cb(int selected_item, void* data,
679 char* buf, size_t buf_len)
680{
681 (void) data;
682 (void) buf;
683 (void) buf_len;
684
685 /* buf supplied isn't used so lets use it for a filename buffer */
686 if (TIME_AFTER(current_tick, gStatus.last_check))
687 {
688 snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_NOCOMMIT, tc_stat.db_path);
689 gStatus.auto_commit = !file_exists(buf);
690 snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_TEMP, tc_stat.db_path);
691 gStatus.commit_ready = file_exists(buf);
692 snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_MASTER, tc_stat.db_path);
693 gStatus.db_exists = file_exists(buf);
694 snprintf(buf, buf_len, "%s/"TAGCACHE_FILE_MASTER, BACKUP_DIRECTORY);
695 gStatus.bu_exists = file_exists(buf);
696 gStatus.last_check = current_tick + HZ;
697 buf[0] = '\0';
698 }
699
700 switch(selected_item)
701 {
702
703 case 0: /* exit */
704 return ID2P(LANG_MENU_QUIT);
705 case 1: /*sep*/
706 return ID2P(VOICE_BLANK);
707 case 2: /*backup*/
708 if (!gStatus.db_exists)
709 return ID2P(VOICE_BLANK);
710 return "Backup";
711 case 3: /*restore*/
712 if (!gStatus.bu_exists)
713 return ID2P(VOICE_BLANK);
714 return "Restore";
715 case 4: /*sep*/
716 return ID2P(VOICE_BLANK);
717 case 5: /*auto commit*/
718 if (gStatus.auto_commit)
719 return "Disable auto commit";
720 else
721 return "Enable auto commit";
722 case 6: /*destroy*/
723 if (gStatus.db_exists)
724 return "Delete database";
725 /*fall through*/
726 case 7: /*sep*/
727 return ID2P(VOICE_BLANK);
728 case 8: /*commit*/
729 if (gStatus.commit_ready)
730 return "Commit";
731 else
732 return "Nothing to commit";
733 default:
734 return "?";
735 }
736}
737
738static int list_voice_cb(int list_index, void* data)
739{
740 #define MAX_MENU_NAME 32
741 if (!rb->global_settings->talk_menu)
742 return -1;
743 else
744 {
745 char buf[MAX_MENU_NAME];
746 const char* name = list_get_name_cb(list_index, data, buf, sizeof(buf));
747 long id = P2ID((const unsigned char *)name);
748 if(id>=0)
749 rb->talk_id(id, true);
750 else
751 rb->talk_spell(name, true);
752 }
753 return 0;
754}
755
756static int commit_menu(void)
757{
758 struct gui_synclist lists;
759 bool exit = false;
760 int button,i;
761 int selection, ret = 0;
762
763 rb->gui_synclist_init(&lists,list_get_name_cb,0, false, 1, NULL);
764 rb->gui_synclist_set_icon_callback(&lists, NULL);
765 rb->gui_synclist_set_nb_items(&lists, 9);
766 rb->gui_synclist_select_item(&lists, 0);
767
768 while (!exit)
769 {
770 rb->gui_synclist_draw(&lists);
771 button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
772 if (rb->gui_synclist_do_button(&lists, &button))
773 continue;
774 selection = rb->gui_synclist_get_sel_pos(&lists);
775
776 if (button == ACTION_STD_CANCEL)
777 return 0;
778 else if (button == ACTION_STD_OK)
779 {
780 switch(selection)
781 {
782 case 0: /* exit */
783 exit = true;
784 break;
785 case 1: /*sep*/
786 continue;
787 case 2: /*backup*/
788 if (!gStatus.db_exists)
789 break;
790 if (!backup_restore_tagcache(true))
791 rb->splash(HZ, "Backup failed!");
792 else
793 {
794 rb->splash(HZ, "Backup success!");
795 gStatus.bu_exists = true;
796 }
797 break;
798 case 3: /*restore*/
799 if (!gStatus.bu_exists)
800 break;
801 if (!backup_restore_tagcache(false))
802 rb->splash(HZ, "Restore failed!");
803 else
804 rb->splash(HZ, "Restore success!");
805 break;
806 case 4: /*sep*/
807 continue;
808 case 5: /*auto commit*/
809 {
810 /* build_idx_buf supplied by tagcache.c isn't being used
811 * so lets use it for a filename buffer */
812 snprintf(build_idx_buf, build_idx_bufsz,
813 "%s/" TAGCACHE_FILE_NOCOMMIT, tc_stat.db_path);
814 if(gStatus.auto_commit)
815 close(open(build_idx_buf, O_WRONLY | O_CREAT | O_TRUNC, 0666));
816 else
817 remove(build_idx_buf);
818 gStatus.auto_commit = !file_exists(build_idx_buf);
819 break;
820 }
821 case 6: /*destroy*/
822 {
823 if (!gStatus.db_exists)
824 break;
825 const struct text_message prompt =
826 { (const char*[]) {"Are you sure?", "This will destroy database."}, 2};
827 if (rb->gui_syncyesno_run(&prompt, NULL, NULL) == YESNO_YES)
828 remove_files();
829 break;
830 }
831 case 7: /*sep*/
832 continue;
833 case 8: /*commit*/
834 if (gStatus.commit_ready)
835 {
836 gStatus.do_commit = true;
837 exit = true;
838 }
839 break;
840
841 case MENU_ATTACHED_USB:
842 return PLUGIN_USB_CONNECTED;
843 default:
844 return 0;
845 }
846 }
847 } /*while*/
848 return ret;
849}
850
443/*-----------------------------------------------------------------------------*/ 851/*-----------------------------------------------------------------------------*/
444/******* plugin_start ******* */ 852/******* plugin_start ******* */
445/*-----------------------------------------------------------------------------*/ 853/*-----------------------------------------------------------------------------*/
@@ -451,6 +859,8 @@ enum plugin_status plugin_start(const void* parameter)
451 /* Turn off backlight timeout */ 859 /* Turn off backlight timeout */
452 backlight_ignore_timeout(); 860 backlight_ignore_timeout();
453 861
862 memset(&gThread, 0, sizeof(gThread));
863 memset(&gStatus, 0, sizeof(gStatus));
454 memset(&tc_stat, 0, sizeof(struct tagcache_stat)); 864 memset(&tc_stat, 0, sizeof(struct tagcache_stat));
455 memset(&current_tcmh, 0, sizeof(struct master_header)); 865 memset(&current_tcmh, 0, sizeof(struct master_header));
456 filenametag_fd = -1; 866 filenametag_fd = -1;
@@ -459,62 +869,32 @@ enum plugin_status plugin_start(const void* parameter)
459 if (!rb->dir_exists(tc_stat.db_path)) /* on fail use default DB path */ 869 if (!rb->dir_exists(tc_stat.db_path)) /* on fail use default DB path */
460 strlcpy(tc_stat.db_path, ROCKBOX_DIR, sizeof(tc_stat.db_path)); 870 strlcpy(tc_stat.db_path, ROCKBOX_DIR, sizeof(tc_stat.db_path));
461 tc_stat.initialized = true; 871 tc_stat.initialized = true;
872 tc_stat.commit_step = -1;
462 873
463 memset(&gThread, 0, sizeof(gThread));
464 logf("started"); 874 logf("started");
465 logdump(false);
466 875
876 int result = commit_menu();
877
878 if (!gStatus.do_commit)
879 {
880 /* Turn on backlight timeout (revert to settings) */
881 backlight_use_settings();
882 return PLUGIN_OK;
883 }
884
885 logdump(false);
886 allocate_tempbuf();
887 if (gStatus.db_exists && !gStatus.have_backup && !prompt_backup_restore(true))
888 rb->splash(HZ, "Backup failed!");
467 thread_create(); 889 thread_create();
468 gThread.user_index = 0; 890 gThread.user_index = 0;
469 logdisplay(); /* get something on the screen while user waits */ 891 logdisplay(); /* get something on the screen while user waits */
470 892
471 allocate_tempbuf();
472
473 commit();
474
475 if (tc_stat.ready)
476 rb->tagcache_commit_finalize();
477
478 free_tempbuf();
479
480 logdump(true);
481 gThread.user_index++;
482 logdisplay();
483 rb->thread_wait(gThread.id);
484 rb->queue_delete(&gThread.queue);
485
486 /* Turn on backlight timeout (revert to settings) */
487 backlight_use_settings();
488 return PLUGIN_OK;
489}
490
491/****************** main thread + helper ******************/
492static void thread(void)
493{
494 struct queue_event ev;
495 while (!gThread.exiting) 893 while (!gThread.exiting)
496 { 894 {
497 rb->queue_wait_w_tmo(&gThread.queue, &ev, 1);
498 switch (ev.id)
499 {
500 case SYS_USB_CONNECTED:
501 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
502 logenabled = false;
503 break;
504 case SYS_USB_DISCONNECTED:
505 logenabled = true;
506 /*fall through*/
507 case EV_STARTUP:
508 logf("Thread Started");
509 break;
510 case EV_EXIT:
511 return;
512 default:
513 break;
514 }
515 logdisplay(); 895 logdisplay();
516 896
517 int action = rb->get_action(CONTEXT_STD, HZ/10); 897 int action = rb->get_action(CONTEXT_STD, HZ/20);
518 898
519 switch( action ) 899 switch( action )
520 { 900 {
@@ -536,8 +916,15 @@ static void thread(void)
536 break; 916 break;
537 case SYS_POWEROFF: 917 case SYS_POWEROFF:
538 case ACTION_STD_CANCEL: 918 case ACTION_STD_CANCEL:
539 gThread.exiting = true; 919 if (tc_stat.commit_step >= 0 && !tc_stat.ready)
540 return; 920 {
921 if (!confirm_quit())
922 break;
923 tc_stat.commit_delayed = true; /* Cancel the commit */
924 }
925 rb->queue_remove_from_head(&gThread.queue, EV_EXIT);
926 rb->queue_post(&gThread.queue, EV_EXIT, 0);
927 break;
541#ifdef HAVE_TOUCHSCREEN 928#ifdef HAVE_TOUCHSCREEN
542 case ACTION_TOUCHSCREEN: 929 case ACTION_TOUCHSCREEN:
543 { 930 {
@@ -561,8 +948,60 @@ static void thread(void)
561 default: 948 default:
562 break; 949 break;
563 } 950 }
951 yield();
952 }
953
954 rb->thread_wait(gThread.id);
955 rb->queue_delete(&gThread.queue);
956 free_tempbuf();
957
958 if (tc_stat.commit_delayed || !tc_stat.ready)
959 {
960 remove_files();
961 if (gStatus.bu_exists && !prompt_backup_restore(false))
962 rb->splash(HZ, "Restore failed!");
963 }
964
965 if (tc_stat.ready)
966 rb->tagcache_commit_finalize();
564 967
968 /* Turn on backlight timeout (revert to settings) */
969 backlight_use_settings();
970 return PLUGIN_OK;
971}
565 972
973/****************** main thread + helper ******************/
974static void thread(void)
975{
976 struct queue_event ev;
977 while (!gThread.exiting)
978 {
979 rb->queue_wait_w_tmo(&gThread.queue, &ev, 1);
980 switch (ev.id)
981 {
982 case SYS_USB_CONNECTED:
983 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
984 logenabled = false;
985 break;
986 case SYS_USB_DISCONNECTED:
987 logenabled = true;
988 /*fall through*/
989 case EV_STARTUP:
990 logf("Thread Started");
991 cpu_boost(true);
992 if (commit())
993 tc_stat.ready = true;
994 cpu_boost(false);
995 logdump(true);
996 gThread.user_index++;
997 logdisplay();
998 break;
999 case EV_EXIT:
1000 gThread.exiting = true;
1001 return;
1002 default:
1003 break;
1004 }
566 yield(); 1005 yield();
567 } 1006 }
568} 1007}