[Feature] resume TSR plugins after interruption WIP

save tsr plugin path for later

resume tsr plugin when user stops the interrupting plugin

expand return of tsr_exit function to allow
continue, suspend, terminate

tsr plugins check parameter at start to determine if
the plugin is being resumed

Change-Id: I6fc70de664c7771e7dbc9a1af7a831e7b50b1d15
This commit is contained in:
William Wilgus 2023-03-20 22:15:33 -04:00 committed by William Wilgus
parent 2e99e2175b
commit a2e5d9563f
6 changed files with 176 additions and 123 deletions

View file

@ -74,7 +74,7 @@ extern unsigned char pluginbuf[];
/* for actual plugins only, not for codecs */
static int plugin_size = 0;
static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */
static int (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */
static char current_plugin[MAX_PATH];
/* NULL if no plugin is loaded, otherwise the handle that lc_open() returned */
static void *current_plugin_handle;
@ -83,7 +83,7 @@ char *plugin_get_current_filename(void);
static void* plugin_get_audio_buffer(size_t *buffer_size);
static void plugin_release_audio_buffer(void);
static void plugin_tsr(bool (*exit_callback)(bool));
static void plugin_tsr(int (*exit_callback)(bool));
#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
/* File handle leak prophylaxis */
@ -183,6 +183,8 @@ static const struct plugin_api rockbox_api = {
/* lcd */
splash,
splashf,
splash_progress,
splash_progress_set_delay,
#ifdef HAVE_LCD_CONTRAST
lcd_set_contrast,
#endif
@ -436,6 +438,7 @@ static const struct plugin_api rockbox_api = {
set_current_file,
set_dirfilter,
onplay_show_playlist_menu,
onplay_show_playlist_cat_menu,
browse_id3,
/* talking */
@ -587,6 +590,7 @@ static const struct plugin_api rockbox_api = {
buflib_get_data,
/* sound */
adjust_volume,
sound_set,
sound_current, /*stub*/
sound_default,
@ -674,6 +678,7 @@ static const struct plugin_api rockbox_api = {
tagcache_fill_tags,
#endif
#endif
tagtree_subentries_do_action,
#endif /* HAVE_TAGCACHE */
#ifdef HAVE_ALBUMART
@ -685,6 +690,7 @@ static const struct plugin_api rockbox_api = {
playlist_amount,
playlist_resume,
playlist_resume_track,
playlist_set_modified,
playlist_start,
playlist_add,
playlist_sync,
@ -814,6 +820,7 @@ static const struct plugin_api rockbox_api = {
sys_reboot,
/* pathfuncs */
fix_path_part,
#ifdef HAVE_MULTIVOLUME
path_strip_volume,
#endif
@ -821,15 +828,6 @@ static const struct plugin_api rockbox_api = {
/* new stuff at the end, sort into place next time
the API gets incompatible */
splash_progress,
splash_progress_set_delay,
fix_path_part,
onplay_show_playlist_cat_menu,
#if defined(HAVE_TAGCACHE)
tagtree_subentries_do_action,
#endif
adjust_volume,
playlist_set_modified,
};
static int plugin_buffer_handle;
@ -839,17 +837,31 @@ int plugin_load(const char* plugin, const void* parameter)
{
struct plugin_header *p_hdr;
struct lc_header *hdr;
const char * resume_plugin = NULL;
if (!plugin)
return PLUGIN_ERROR;
if (current_plugin_handle && pfn_tsr_exit)
{ /* if we have a resident old plugin and a callback */
if (pfn_tsr_exit(!strcmp(current_plugin, plugin)) == false )
bool reenter = (strcmp(current_plugin, plugin) == 0);
int exit_status = pfn_tsr_exit(reenter);
if (exit_status == PLUGIN_TSR_CONTINUE)
{
/* not allowing another plugin to load */
return PLUGIN_OK;
}
else
{
lc_close(current_plugin_handle);
current_plugin_handle = pfn_tsr_exit = NULL;
plugin_buffer_handle = core_free(plugin_buffer_handle);
if (!reenter)
resume_plugin = strdupa(current_plugin);
else if (exit_status == PLUGIN_TSR_TERMINATE)
return PLUGIN_OK; /* don't even load the new plugin either */
}
}
#ifdef HAVE_DISK_STORAGE
@ -857,7 +869,6 @@ int plugin_load(const char* plugin, const void* parameter)
splash(0, ID2P(LANG_WAIT));
#endif
strcpy(current_plugin, plugin);
current_plugin_handle = lc_open(plugin, pluginbuf, PLUGIN_BUFFER_SIZE);
if (current_plugin_handle == NULL) {
splashf(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
@ -990,6 +1001,12 @@ int plugin_load(const char* plugin, const void* parameter)
if (rc == PLUGIN_ERROR)
splash(HZ*2, str(LANG_PLUGIN_ERROR));
if (resume_plugin && rc != PLUGIN_GOTO_PLUGIN && !pfn_tsr_exit)
{
/*plugin = resume_plugin;*/
/*parameter = rockbox_api.plugin_tsr;*/
return plugin_load(resume_plugin, rockbox_api.plugin_tsr);
}
return rc;
}
@ -1067,7 +1084,7 @@ static void plugin_release_audio_buffer(void)
/* The plugin wants to stay resident after leaving its main function, e.g.
runs from timer or own thread. The callback is registered to later
instruct it to free its resources before a new plugin gets loaded. */
static void plugin_tsr(bool (*exit_callback)(bool))
static void plugin_tsr(int (*exit_callback)(bool))
{
pfn_tsr_exit = exit_callback; /* remember the callback for later */
}

View file

@ -162,7 +162,7 @@ int plugin_open(const char *plugin, const char *parameter);
* when this happens please take the opportunity to sort in
* any new functions "waiting" at the end of the list.
*/
#define PLUGIN_API_VERSION 266
#define PLUGIN_API_VERSION 267
/* 239 Marks the removal of ARCHOS HWCODEC and CHARCELL */
@ -179,6 +179,12 @@ enum plugin_status {
PLUGIN_ERROR = -1,
};
enum plugin_tsr_status {
PLUGIN_TSR_CONTINUE = 0, /* TSR continues running */
PLUGIN_TSR_SUSPEND, /* TSR exits but will restart later */
PLUGIN_TSR_TERMINATE, /* TSR exits and will not be restarted */
};
/* NOTE: To support backwards compatibility, only add new functions at
the end of the structure. Every time you add a new function,
remember to increase PLUGIN_API_VERSION. If you make changes to the
@ -195,6 +201,8 @@ struct plugin_api {
/* lcd */
void (*splash)(int ticks, const char *str);
void (*splashf)(int ticks, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
void (*splash_progress)(int current, int total, const char *fmt, ...) ATTRIBUTE_PRINTF(3, 4);
void (*splash_progress_set_delay)(long delay_ticks);
#ifdef HAVE_LCD_CONTRAST
void (*lcd_set_contrast)(int x);
#endif
@ -488,6 +496,8 @@ struct plugin_api {
void (*set_dirfilter)(int l_dirfilter);
void (*onplay_show_playlist_menu)(const char* path, void (*playlist_insert_cb));
void (*onplay_show_playlist_cat_menu)(const char* track_name, int attr,
void (*add_to_pl_cb));
bool (*browse_id3)(struct mp3entry *id3,
int playlist_display_index, int playlist_amount,
struct tm *modified);
@ -660,6 +670,7 @@ struct plugin_api {
void* (*buflib_get_data)(struct buflib_context* ctx, int handle);
/* sound */
void (*adjust_volume)(int steps);
void (*sound_set)(int setting, int value);
int (*sound_current)(int setting); /*stub*/
int (*sound_default)(int setting);
@ -769,6 +780,7 @@ struct plugin_api {
bool (*tagcache_fill_tags)(struct mp3entry *id3, const char *filename);
#endif
#endif
bool (*tagtree_subentries_do_action)(bool (*action_cb)(const char *file_name));
#endif /* HAVE_TAGCACHE */
#ifdef HAVE_ALBUMART
@ -782,6 +794,7 @@ struct plugin_api {
int (*playlist_resume)(void);
void (*playlist_resume_track)(int start_index, unsigned int crc,
unsigned long elapsed, unsigned long offset);
void (*playlist_set_modified)(struct playlist_info *playlist, bool modified);
void (*playlist_start)(int start_index, unsigned long elapsed,
unsigned long offset);
int (*playlist_add)(const char *filename);
@ -932,29 +945,20 @@ struct plugin_api {
void* (*plugin_get_buffer)(size_t *buffer_size);
void* (*plugin_get_audio_buffer)(size_t *buffer_size);
void (*plugin_release_audio_buffer)(void);
void (*plugin_tsr)(bool (*exit_callback)(bool reenter));
void (*plugin_tsr)(int (*exit_callback)(bool reenter));
char* (*plugin_get_current_filename)(void);
size_t (*plugin_reserve_buffer)(size_t buffer_size);
/* reboot and poweroff */
void (*sys_poweroff)(void);
void (*sys_reboot)(void);
/* pathfuncs */
void (*fix_path_part)(char* path, int offset, int count);
#ifdef HAVE_MULTIVOLUME
int (*path_strip_volume)(const char *name, const char **nameptr, bool greedy);
#endif
/* new stuff at the end, sort into place next time
the API gets incompatible */
void (*splash_progress)(int current, int total, const char *fmt, ...) ATTRIBUTE_PRINTF(3, 4);
void (*splash_progress_set_delay)(long delay_ticks);
void (*fix_path_part)(char* path, int offset, int count);
void (*onplay_show_playlist_cat_menu)(const char* track_name, int attr,
void (*add_to_pl_cb));
#ifdef HAVE_TAGCACHE
bool (*tagtree_subentries_do_action)(bool (*action_cb)(const char *file_name));
#endif
void (*adjust_volume)(int steps);
void (*playlist_set_modified)(struct playlist_info *playlist, bool modified);
};
/* plugin header */

View file

@ -97,6 +97,7 @@ enum plugin_status plugin_start(const void* parameter); /* entry */
static struct
{
bool exiting; /* signal to the thread that we want to exit */
bool resume;
unsigned int id; /* worker thread id */
struct event_queue queue; /* thread event queue */
long stack[THREAD_STACK_SIZE / sizeof(long)];
@ -393,7 +394,7 @@ static int settings_menu(void)
break;
case 4: /*sep*/
continue;
case 5:
case 5: /* quit the plugin */
return -1;
break;
case 6:
@ -433,6 +434,7 @@ void thread(void)
in_usb = false;
/*fall through*/
case EV_STARTUP:
if (!gThread.resume)
rb->beep_play(1500, 100, 1000);
break;
case EV_EXIT:
@ -479,17 +481,45 @@ void thread_quit(void)
}
}
static bool check_user_input(void)
{
int i = 0;
rb->button_clear_queue();
if (rb->button_get_w_tmo(HZ) > BUTTON_NONE)
{
while ((rb->button_get(false) & BUTTON_REL) != BUTTON_REL)
{
if (i & 1)
rb->beep_play(800, 100, 1000 - i * (1000 / 15));
if (++i > 15)
{
return true;
}
rb->sleep(HZ / 5);
}
}
return false;
}
/* callback to end the TSR plugin, called before a new one gets loaded */
static bool exit_tsr(bool reenter)
static int exit_tsr(bool reenter)
{
if (reenter)
{
rb->queue_post(&gThread.queue, EV_OTHINSTANCE, 0);
return false; /* dont let it start again */
/* quit the plugin if user holds a button */
if (check_user_input() == true)
{
if (settings_menu() < 0)
return PLUGIN_TSR_TERMINATE; /*kill TSR dont let it start again */
}
return PLUGIN_TSR_CONTINUE; /* dont let new plugin start*/
}
thread_quit();
return true;
return PLUGIN_TSR_SUSPEND;
}
@ -497,26 +527,18 @@ static bool exit_tsr(bool reenter)
int plugin_main(const void* parameter)
{
(void)parameter;
bool settings = false;
int i = 0;
rb->memset(&gThread, 0, sizeof(gThread));
gAnnounce.index = 0;
gAnnounce.timeout = 0;
rb->splash(HZ / 2, "Announce Status");
if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0)
/* Resume plugin ? */
if (parameter == rb->plugin_tsr)
{
/* If the loading failed, save a new config file */
config_set_defaults();
configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER);
rb->splash(HZ, ID2P(LANG_HOLD_FOR_SETTINGS));
gThread.resume = true;
}
else
{
rb->splash(HZ / 2, "Announce Status");
if (gAnnounce.show_prompt)
{
if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING)
@ -526,30 +548,15 @@ int plugin_main(const void* parameter)
rb->splash(HZ, ID2P(LANG_HOLD_FOR_SETTINGS));
}
rb->button_clear_queue();
if (rb->button_get_w_tmo(HZ) > BUTTON_NONE)
{
while ((rb->button_get(false) & BUTTON_REL) != BUTTON_REL)
{
if (i & 1)
rb->beep_play(800, 100, 1000);
if (++i > 15)
{
settings = true;
break;
}
rb->sleep(HZ / 5);
}
}
if (settings)
if (check_user_input() == true)
{
rb->splash(100, ID2P(LANG_SETTINGS));
int ret = settings_menu();
if (ret < 0)
return 0;
}
}
gAnnounce.timeout = *rb->current_tick;
rb->plugin_tsr(exit_tsr); /* stay resident */
@ -571,6 +578,16 @@ enum plugin_status plugin_start(const void* parameter)
/* now go ahead and have fun! */
if (rb->usb_inserted() == true)
return PLUGIN_USB_CONNECTED;
config_set_defaults();
if (configfile_load(CFG_FILE, config, gCfg_sz, CFG_VER) < 0)
{
/* If the loading failed, save a new config file */
config_set_defaults();
configfile_save(CFG_FILE, config, gCfg_sz, CFG_VER);
rb->splash(HZ, ID2P(LANG_HOLD_FOR_SETTINGS));
}
int ret = plugin_main(parameter);
return (ret==0) ? PLUGIN_OK : PLUGIN_ERROR;
}

View file

@ -289,11 +289,11 @@ static struct event_queue thread_q SHAREDBSS_ATTR;
static bool in_usb_mode;
static unsigned int buf_idx;
static bool exit_tsr(bool reenter)
static int exit_tsr(bool reenter)
{
bool is_exit;
int exit_status;
long button;
(void)reenter;
rb->lcd_clear_display();
rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
@ -313,16 +313,17 @@ static bool exit_tsr(bool reenter)
rb->thread_wait(gThread.id);
/* remove the thread's queue from the broadcast list */
rb->queue_delete(&thread_q);
is_exit = true;
exit_status = (reenter ? PLUGIN_TSR_TERMINATE : PLUGIN_TSR_SUSPEND);
}
else is_exit = false;
else exit_status = PLUGIN_TSR_CONTINUE;
break;
}
FOR_NB_SCREENS(idx)
rb->screens[idx]->scroll_stop();
return is_exit;
return exit_status;
}
#define BIT_CHARGER 0x1
@ -502,14 +503,19 @@ static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, in
enum plugin_status plugin_start(const void* parameter)
{
(void)parameter;
int button, fd;
bool resume = false;
bool on = false;
start_tick = *rb->current_tick;
int i;
const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
"for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
rb->lcd_clear_display();
if (parameter == rb->plugin_tsr)
{
resume = true;
on = true;
}
rb->lcd_clear_display();
rb->lcd_setfont(FONT_SYSFIXED);
@ -529,22 +535,23 @@ enum plugin_status plugin_start(const void* parameter)
rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
rb->lcd_remote_update();
#endif
if (!resume)
{
do
{
button = rb->button_get(true);
switch (button)
{
case BATTERY_ON:
#ifdef BATTERY_RC_ON
#ifdef BATTERY_RC_ON
case BATTERY_RC_ON:
#endif
#endif
on = true;
break;
case BATTERY_OFF:
#ifdef BATTERY_RC_OFF
#ifdef BATTERY_RC_OFF
case BATTERY_RC_OFF:
#endif
#endif
return PLUGIN_OK;
default:
@ -552,13 +559,14 @@ enum plugin_status plugin_start(const void* parameter)
return PLUGIN_USB_CONNECTED;
}
}while(!on);
}
fd = rb->open(BATTERY_LOG, O_RDONLY);
if (fd < 0)
{
fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT, 0666);
if (fd >= 0)
{
rb->fdprintf(fd,
"# This plugin will log your battery performance in a\n"
"# file (%s) every minute.\n"

View file

@ -98,7 +98,7 @@ static struct
bool force_flush;
} gCache;
static struct
static struct lastfm_config
{
int savepct;
int beeplvl;
@ -528,7 +528,7 @@ void thread_quit(void)
}
/* callback to end the TSR plugin, called before a new one gets loaded */
static bool exit_tsr(bool reenter)
static int exit_tsr(bool reenter)
{
MENUITEM_STRINGLIST(menu, ID2P(LANG_AUDIOSCROBBLER), NULL, ID2P(LANG_SETTINGS),
"Flush Cache", "Exit Plugin", ID2P(LANG_BACK));
@ -556,19 +556,13 @@ static bool exit_tsr(bool reenter)
case 2: /* exit plugin - quit */
if(rb->gui_syncyesno_run(&quit_prompt, NULL, NULL) == YESNO_YES)
{
scrobbler_flush_cache();
thread_quit();
if (reenter)
rb->plugin_tsr(NULL); /* remove TSR cb */
return !reenter;
return (reenter ? PLUGIN_TSR_TERMINATE : PLUGIN_TSR_SUSPEND);
}
if(!reenter)
return false;
break;
/* Fall Through */
case 3: /* back to menu */
return false;
return PLUGIN_TSR_CONTINUE;
}
}
}
@ -576,7 +570,17 @@ static bool exit_tsr(bool reenter)
/****************** main ******************/
static int plugin_main(const void* parameter)
{
(void)parameter;
struct lastfm_config cfg;
rb->memcpy(&cfg, & gConfig, sizeof(struct lastfm_config));
/* Resume plugin ? */
if (parameter == rb->plugin_tsr)
{
gConfig.beeplvl = 0;
gConfig.playback = false;
gConfig.verbose = false;
}
rb->memset(&gThread, 0, sizeof(gThread));
if (gConfig.verbose)
@ -586,9 +590,11 @@ static int plugin_main(const void* parameter)
rb->plugin_tsr(exit_tsr); /* stay resident */
thread_create();
rb->memcpy(&gConfig, &cfg, sizeof(struct lastfm_config));
if (gConfig.playback)
return PLUGIN_GOTO_WPS;
return PLUGIN_OK;
}

View file

@ -85,7 +85,7 @@ static void kill_tsr(void)
rb->queue_delete(&queue);
}
static bool exit_tsr(bool reenter)
static int exit_tsr(bool reenter)
{
MENUITEM_STRINGLIST(menu, "USB test menu", NULL,
"Status", "Stop plugin", "Back");
@ -100,9 +100,9 @@ static bool exit_tsr(bool reenter)
case 1:
rb->splashf(HZ, "Stopping USB test thread");
kill_tsr();
return true;
return (reenter ? PLUGIN_TSR_TERMINATE : PLUGIN_TSR_SUSPEND);
case 2:
return false;
return PLUGIN_TSR_CONTINUE;
}
}
}
@ -119,14 +119,15 @@ static void run_tsr(void)
enum plugin_status plugin_start(const void* parameter)
{
(void)parameter;
bool resume = (parameter == rb->plugin_tsr);
MENUITEM_STRINGLIST(menu, "USB test menu", NULL,
"Start", "Quit");
switch(rb->do_menu(&menu, NULL, NULL, false)) {
switch(!resume ? rb->do_menu(&menu, NULL, NULL, false) : 0) {
case 0:
run_tsr();
rb->splashf(HZ, "Thread started");
rb->splashf(HZ, "USB test thread started");
return PLUGIN_OK;
case 1:
return PLUGIN_OK;