Kaynağa Gözat

libobs/callback: Make proc_handler_t threadsafe

Add mutexes to protect against multi-threaded memory access
violations.
tt2468 4 yıl önce
ebeveyn
işleme
23cda97a54
1 değiştirilmiş dosya ile 55 ekleme ve 15 silme
  1. 55 15
      libobs/callback/proc.c

+ 55 - 15
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;
 }