[library] Add action to library_schedule_callback()

Makes it possible for the caller to request that a previous callback is
replaced, so we don't end up with more and more callbacks. Also add other
options for future use.
This commit is contained in:
ejurgensen 2020-03-23 23:17:26 +01:00
parent 2af7296723
commit 2d8521139c
3 changed files with 71 additions and 21 deletions

View File

@ -54,6 +54,7 @@ struct library_callback_register
{
library_cb cb;
void *arg;
struct event *ev;
};
struct playlist_item_add_param
@ -170,44 +171,71 @@ static void
scheduled_cb(int fd, short what, void *arg)
{
struct library_callback_register *cbreg = arg;
library_cb cb = cbreg->cb;
void *cb_arg = cbreg->arg;
DPRINTF(E_DBG, L_LIB, "Executing library callback to %p\n", cbreg->cb);
cbreg->cb(cbreg->arg);
// Must reset the register before calling back, otherwise it won't work if the
// callback reschedules by calling library_callback_schedule()
event_free(cbreg->ev);
memset(cbreg, 0, sizeof(struct library_callback_register));
DPRINTF(E_DBG, L_LIB, "Executing library callback to %p\n", cb);
cb(cb_arg);
}
int
library_callback_schedule(library_cb cb, void *arg, struct timeval *wait)
library_callback_schedule(library_cb cb, void *arg, struct timeval *wait, enum library_cb_action action)
{
struct library_callback_register *cbreg;
int callback_id;
bool replace_done;
int idx_available;
int i;
// Find a free slot in the queue
for (callback_id = 0; callback_id < ARRAY_SIZE(library_cb_register); callback_id++)
for (i = 0, idx_available = -1, replace_done = false; i < ARRAY_SIZE(library_cb_register); i++)
{
if (library_cb_register[callback_id].cb == NULL)
break;
if (idx_available == -1 && library_cb_register[i].cb == NULL)
idx_available = i;
if (library_cb_register[i].cb != cb)
continue;
if (action == LIBRARY_CB_REPLACE || action == LIBRARY_CB_ADD_OR_REPLACE)
{
event_add(library_cb_register[i].ev, wait);
library_cb_register[i].arg = arg;
replace_done = true;
}
else if (action == LIBRARY_CB_DELETE)
{
event_free(library_cb_register[i].ev);
memset(&library_cb_register[i], 0, sizeof(struct library_callback_register));
}
}
if (callback_id == ARRAY_SIZE(library_cb_register))
if (action == LIBRARY_CB_REPLACE || action == LIBRARY_CB_DELETE || (action == LIBRARY_CB_ADD_OR_REPLACE && replace_done))
{
DPRINTF(E_LOG, L_LIB, "Library callback register is full! (size is %d)\n", LIBRARY_MAX_CALLBACKS);
return 0; // All done
}
else if (idx_available == -1)
{
DPRINTF(E_LOG, L_LIB, "Error scheduling callback, register full (size=%d, action=%d)\n", LIBRARY_MAX_CALLBACKS, action);
return -1;
}
cbreg = &library_cb_register[callback_id];
cbreg = &library_cb_register[idx_available];
cbreg->cb = cb;
cbreg->arg = arg;
// One-time event, freed automatically by libevent
CHECK_ERR(L_LIB, event_base_once(evbase_lib, -1, EV_TIMEOUT, scheduled_cb, cbreg, wait));
if (!cbreg->ev)
cbreg->ev = evtimer_new(evbase_lib, scheduled_cb, cbreg);
DPRINTF(E_DBG, L_LIB, "Added library callback to %p (id %d)\n", cbreg->cb, callback_id);
CHECK_NULL(L_LIB, cbreg->ev);
return callback_id;
event_add(cbreg->ev, wait);
DPRINTF(E_DBG, L_LIB, "Added library callback to %p (id %d), wait %ld.%06ld\n", cbreg->cb, idx_available, wait->tv_sec, wait->tv_usec);
return idx_available;
}
@ -853,6 +881,12 @@ library_deinit()
sources[i]->deinit();
}
for (i = 0; i < ARRAY_SIZE(library_cb_register); i++)
{
if (library_cb_register[i].ev)
event_free(library_cb_register[i].ev);
}
event_free(updateev);
event_base_free(evbase_lib);
}

View File

@ -32,6 +32,21 @@
typedef void (*library_cb)(void *arg);
/*
* Argument to library_callback_schedule()
*/
enum library_cb_action
{
// Add as new callback
LIBRARY_CB_ADD,
// Replace callback if it already exists
LIBRARY_CB_REPLACE,
// Replace callback if it already exists, otherwise add as new
LIBRARY_CB_ADD_OR_REPLACE,
// Delete a callback
LIBRARY_CB_DELETE,
};
/*
* Definition of a library source
*
@ -123,10 +138,11 @@ library_playlist_save(struct playlist_info *pli);
* @param cb Callback to call
* @param arg Argument to call back with
* @param timeval How long to wait before calling back
* @param action (see enum)
* @return id of the scheduled event, -1 on failure
*/
int
library_callback_schedule(library_cb cb, void *arg, struct timeval *wait);
library_callback_schedule(library_cb cb, void *arg, struct timeval *wait, enum library_cb_action action);
/*
* @return true if a running scan should be aborted due to imminent shutdown

View File

@ -549,7 +549,7 @@ rss_scan_all(enum rss_scan_type scan_type)
if (count == 0)
return;
library_callback_schedule(rss_refresh, NULL, &rss_refresh_interval);
library_callback_schedule(rss_refresh, NULL, &rss_refresh_interval, LIBRARY_CB_ADD_OR_REPLACE);
DPRINTF(E_INFO, L_LIB, "Refreshed %d RSS feeds in %.f sec (scan type %d)\n", count, difftime(end, start), scan_type);
}
@ -601,7 +601,7 @@ rss_add(const char *path)
if (ret < 0)
return LIBRARY_PATH_INVALID;
library_callback_schedule(rss_refresh, NULL, &rss_refresh_interval);
library_callback_schedule(rss_refresh, NULL, &rss_refresh_interval, LIBRARY_CB_ADD_OR_REPLACE);
return LIBRARY_OK;
}