浏览代码

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.
jp9000 7 年之前
父节点
当前提交
c8a0f661fb
共有 2 个文件被更改,包括 107 次插入3 次删除
  1. 101 3
      libobs/callback/signal.c
  2. 6 0
      libobs/callback/signal.h

+ 101 - 3
libobs/callback/signal.c

@@ -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);
 }

+ 6 - 0
libobs/callback/signal.h

@@ -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,