From 23cda97a545b8a2a21661fce0c9e589cab5a58e7 Mon Sep 17 00:00:00 2001 From: tt2468 Date: Thu, 2 Sep 2021 08:23:56 -0700 Subject: [PATCH] libobs/callback: Make proc_handler_t threadsafe Add mutexes to protect against multi-threaded memory access violations. --- libobs/callback/proc.c | 70 +++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/libobs/callback/proc.c b/libobs/callback/proc.c index 80b4537ba..e8a650510 100644 --- a/libobs/callback/proc.c +++ b/libobs/callback/proc.c @@ -15,6 +15,7 @@ */ #include "../util/darray.h" +#include "../util/threading.h" #include "decl.h" #include "proc.h" @@ -32,24 +33,50 @@ static inline void proc_info_free(struct proc_info *pi) struct proc_handler { /* TODO: replace with hash table lookup? */ + pthread_mutex_t mutex; DARRAY(struct proc_info) procs; }; +static struct proc_info *getproc(proc_handler_t *handler, const char *name) +{ + for (size_t i = 0; i < handler->procs.num; i++) { + struct proc_info *info = handler->procs.array + i; + + if (strcmp(info->func.name, name) == 0) { + return info; + } + } + + return NULL; +} + +/* ------------------------------------------------------------------------- */ + proc_handler_t *proc_handler_create(void) { struct proc_handler *handler = bmalloc(sizeof(struct proc_handler)); + + if (pthread_mutex_init_recursive(&handler->mutex) != 0) { + blog(LOG_ERROR, "Couldn't create proc_handler mutex"); + bfree(handler); + return NULL; + } + da_init(handler->procs); return handler; } void proc_handler_destroy(proc_handler_t *handler) { - if (handler) { - for (size_t i = 0; i < handler->procs.num; i++) - proc_info_free(handler->procs.array + i); - da_free(handler->procs); - bfree(handler); - } + if (!handler) + return; + + for (size_t i = 0; i < handler->procs.num; i++) + proc_info_free(handler->procs.array + i); + + da_free(handler->procs); + pthread_mutex_destroy(&handler->mutex); + bfree(handler); } void proc_handler_add(proc_handler_t *handler, const char *decl_string, @@ -70,7 +97,18 @@ void proc_handler_add(proc_handler_t *handler, const char *decl_string, pi.callback = proc; pi.data = data; - da_push_back(handler->procs, &pi); + pthread_mutex_lock(&handler->mutex); + + struct proc_info *existing = getproc(handler, pi.func.name); + if (existing) { + blog(LOG_WARNING, "Procedure '%s' already exists", + pi.func.name); + proc_info_free(&pi); + } else { + da_push_back(handler->procs, &pi); + } + + pthread_mutex_unlock(&handler->mutex); } bool proc_handler_call(proc_handler_t *handler, const char *name, @@ -79,14 +117,16 @@ bool proc_handler_call(proc_handler_t *handler, const char *name, if (!handler) return false; - for (size_t i = 0; i < handler->procs.num; i++) { - struct proc_info *info = handler->procs.array + i; + pthread_mutex_lock(&handler->mutex); + struct proc_info *info = getproc(handler, name); + struct proc_info info_copy; + if (info) + info_copy = *info; + pthread_mutex_unlock(&handler->mutex); - if (strcmp(info->func.name, name) == 0) { - info->callback(info->data, params); - return true; - } - } + if (!info) + return false; - return false; + info_copy.callback(info_copy.data, params); + return true; }