libobs/callback: Add global callback to signal handler

A global callback allows capturing all signals from a signal handler
rather than just a specific signal.
This commit is contained in:
jp9000 2017-12-25 12:08:16 -08:00
parent b8bb60c83b
commit c8a0f661fb
2 changed files with 107 additions and 3 deletions

View file

@ -86,9 +86,19 @@ static inline size_t signal_get_callback_idx(struct signal_info *si,
return DARRAY_INVALID;
}
struct global_callback_info {
global_signal_callback_t callback;
void *data;
long signaling;
bool remove;
};
struct signal_handler {
struct signal_info *first;
pthread_mutex_t mutex;
DARRAY(struct global_callback_info) global_callbacks;
pthread_mutex_t global_callbacks_mutex;
};
static struct signal_info *getsignal(signal_handler_t *handler,
@ -114,11 +124,24 @@ static struct signal_info *getsignal(signal_handler_t *handler,
signal_handler_t *signal_handler_create(void)
{
struct signal_handler *handler = bmalloc(sizeof(struct signal_handler));
struct signal_handler *handler = bzalloc(sizeof(struct signal_handler));
handler->first = NULL;
pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr) != 0)
return NULL;
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
return NULL;
if (pthread_mutex_init(&handler->mutex, NULL) != 0) {
blog(LOG_ERROR, "Couldn't create signal handler!");
blog(LOG_ERROR, "Couldn't create signal handler mutex!");
bfree(handler);
return NULL;
}
if (pthread_mutex_init(&handler->global_callbacks_mutex, &attr) != 0) {
blog(LOG_ERROR, "Couldn't create signal handler global "
"callbacks mutex!");
pthread_mutex_destroy(&handler->mutex);
bfree(handler);
return NULL;
}
@ -136,6 +159,8 @@ void signal_handler_destroy(signal_handler_t *handler)
sig = next;
}
da_free(handler->global_callbacks);
pthread_mutex_destroy(&handler->global_callbacks_mutex);
pthread_mutex_destroy(&handler->mutex);
bfree(handler);
}
@ -199,7 +224,7 @@ void signal_handler_connect(signal_handler_t *handler, const char *signal,
idx = signal_get_callback_idx(sig, callback, data);
if (idx == DARRAY_INVALID)
da_push_back(sig->callbacks, &cb_data);
pthread_mutex_unlock(&sig->mutex);
}
@ -241,11 +266,14 @@ void signal_handler_disconnect(signal_handler_t *handler, const char *signal,
}
static THREAD_LOCAL struct signal_callback *current_signal_cb = NULL;
static THREAD_LOCAL struct global_callback_info *current_global_cb = NULL;
void signal_handler_remove_current(void)
{
if (current_signal_cb)
current_signal_cb->remove = true;
else if (current_global_cb)
current_global_cb->remove = true;
}
void signal_handler_signal(signal_handler_t *handler, const char *signal,
@ -276,4 +304,74 @@ void signal_handler_signal(signal_handler_t *handler, const char *signal,
sig->signalling = false;
pthread_mutex_unlock(&sig->mutex);
pthread_mutex_lock(&handler->global_callbacks_mutex);
if (handler->global_callbacks.num) {
for (size_t i = 0; i < handler->global_callbacks.num; i++) {
struct global_callback_info *cb =
handler->global_callbacks.array + i;
if (!cb->remove) {
cb->signaling++;
current_global_cb = cb;
cb->callback(cb->data, signal, params);
current_global_cb = NULL;
cb->signaling--;
}
}
for (size_t i = handler->global_callbacks.num; i > 0; i--) {
struct global_callback_info *cb =
handler->global_callbacks.array + (i - 1);
if (cb->remove && !cb->signaling)
da_erase(handler->global_callbacks, i - 1);
}
}
pthread_mutex_unlock(&handler->global_callbacks_mutex);
}
void signal_handler_connect_global(signal_handler_t *handler,
global_signal_callback_t callback, void *data)
{
struct global_callback_info cb_data = {callback, data, 0, false};
size_t idx;
if (!handler || !callback)
return;
pthread_mutex_lock(&handler->global_callbacks_mutex);
idx = da_find(handler->global_callbacks, &cb_data, 0);
if (idx == DARRAY_INVALID)
da_push_back(handler->global_callbacks, &cb_data);
pthread_mutex_unlock(&handler->global_callbacks_mutex);
}
void signal_handler_disconnect_global(signal_handler_t *handler,
global_signal_callback_t callback, void *data)
{
struct global_callback_info cb_data = {callback, data, false};
size_t idx;
if (!handler || !callback)
return;
pthread_mutex_lock(&handler->global_callbacks_mutex);
idx = da_find(handler->global_callbacks, &cb_data, 0);
if (idx != DARRAY_INVALID) {
struct global_callback_info *cb =
handler->global_callbacks.array + idx;
if (cb->signaling)
cb->remove = true;
else
da_erase(handler->global_callbacks, idx);
}
pthread_mutex_unlock(&handler->global_callbacks_mutex);
}

View file

@ -33,6 +33,7 @@ extern "C" {
struct signal_handler;
typedef struct signal_handler signal_handler_t;
typedef void (*global_signal_callback_t)(void*, const char*, calldata_t*);
typedef void (*signal_callback_t)(void*, calldata_t*);
EXPORT signal_handler_t *signal_handler_create(void);
@ -60,6 +61,11 @@ EXPORT void signal_handler_connect(signal_handler_t *handler,
EXPORT void signal_handler_disconnect(signal_handler_t *handler,
const char *signal, signal_callback_t callback, void *data);
EXPORT void signal_handler_connect_global(signal_handler_t *handler,
global_signal_callback_t callback, void *data);
EXPORT void signal_handler_disconnect_global(signal_handler_t *handler,
global_signal_callback_t callback, void *data);
EXPORT void signal_handler_remove_current(void);
EXPORT void signal_handler_signal(signal_handler_t *handler, const char *signal,