| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 | 
							- /*
 
-  * Copyright (c) 2013-2014 Hugh Bailey <[email protected]>
 
-  *
 
-  * Permission to use, copy, modify, and distribute this software for any
 
-  * purpose with or without fee is hereby granted, provided that the above
 
-  * copyright notice and this permission notice appear in all copies.
 
-  *
 
-  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 
-  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 
-  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 
-  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
-  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
-  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 
-  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-  */
 
- #include "../util/darray.h"
 
- #include "../util/threading.h"
 
- #include "decl.h"
 
- #include "signal.h"
 
- struct signal_callback {
 
- 	signal_callback_t callback;
 
- 	void              *data;
 
- 	bool              remove;
 
- };
 
- struct signal_info {
 
- 	struct decl_info               func;
 
- 	DARRAY(struct signal_callback) callbacks;
 
- 	pthread_mutex_t                mutex;
 
- 	bool                           signalling;
 
- 	struct signal_info             *next;
 
- };
 
- static inline struct signal_info *signal_info_create(struct decl_info *info)
 
- {
 
- 	pthread_mutexattr_t attr;
 
- 	struct signal_info *si;
 
- 	if (pthread_mutexattr_init(&attr) != 0)
 
- 		return NULL;
 
- 	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
 
- 		return NULL;
 
- 	si = bmalloc(sizeof(struct signal_info));
 
- 	si->func       = *info;
 
- 	si->next       = NULL;
 
- 	si->signalling = false;
 
- 	da_init(si->callbacks);
 
- 	if (pthread_mutex_init(&si->mutex, &attr) != 0) {
 
- 		blog(LOG_ERROR, "Could not create signal");
 
- 		decl_info_free(&si->func);
 
- 		bfree(si);
 
- 		return NULL;
 
- 	}
 
- 	return si;
 
- }
 
- static inline void signal_info_destroy(struct signal_info *si)
 
- {
 
- 	if (si) {
 
- 		pthread_mutex_destroy(&si->mutex);
 
- 		decl_info_free(&si->func);
 
- 		da_free(si->callbacks);
 
- 		bfree(si);
 
- 	}
 
- }
 
- static inline size_t signal_get_callback_idx(struct signal_info *si,
 
- 		signal_callback_t callback, void *data)
 
- {
 
- 	for (size_t i = 0; i < si->callbacks.num; i++) {
 
- 		struct signal_callback *sc = si->callbacks.array+i;
 
- 		if (sc->callback == callback && sc->data == data)
 
- 			return i;
 
- 	}
 
- 	return DARRAY_INVALID;
 
- }
 
- struct signal_handler {
 
- 	struct signal_info *first;
 
- 	pthread_mutex_t    mutex;
 
- };
 
- static struct signal_info *getsignal(signal_handler_t *handler,
 
- 		const char *name, struct signal_info **p_last)
 
- {
 
- 	struct signal_info *signal, *last= NULL;
 
- 	signal = handler->first;
 
- 	while (signal != NULL) {
 
- 		if (strcmp(signal->func.name, name) == 0)
 
- 			break;
 
- 		last = signal;
 
- 		signal = signal->next;
 
- 	}
 
- 	if (p_last)
 
- 		*p_last = last;
 
- 	return signal;
 
- }
 
- /* ------------------------------------------------------------------------- */
 
- signal_handler_t *signal_handler_create(void)
 
- {
 
- 	struct signal_handler *handler = bmalloc(sizeof(struct signal_handler));
 
- 	handler->first = NULL;
 
- 	if (pthread_mutex_init(&handler->mutex, NULL) != 0) {
 
- 		blog(LOG_ERROR, "Couldn't create signal handler!");
 
- 		bfree(handler);
 
- 		return NULL;
 
- 	}
 
- 	return handler;
 
- }
 
- void signal_handler_destroy(signal_handler_t *handler)
 
- {
 
- 	if (handler) {
 
- 		struct signal_info *sig = handler->first;
 
- 		while (sig != NULL) {
 
- 			struct signal_info *next = sig->next;
 
- 			signal_info_destroy(sig);
 
- 			sig = next;
 
- 		}
 
- 		pthread_mutex_destroy(&handler->mutex);
 
- 		bfree(handler);
 
- 	}
 
- }
 
- bool signal_handler_add(signal_handler_t *handler, const char *signal_decl)
 
- {
 
- 	struct decl_info func = {0};
 
- 	struct signal_info *sig, *last;
 
- 	bool success = true;
 
- 	if (!parse_decl_string(&func, signal_decl)) {
 
- 		blog(LOG_ERROR, "Signal declaration invalid: %s", signal_decl);
 
- 		return false;
 
- 	}
 
- 	pthread_mutex_lock(&handler->mutex);
 
- 	sig = getsignal(handler, func.name, &last);
 
- 	if (sig) {
 
- 		blog(LOG_WARNING, "Signal declaration '%s' exists", func.name);
 
- 		decl_info_free(&func);
 
- 		success = false;
 
- 	} else {
 
- 		sig = signal_info_create(&func);
 
- 		if (!last)
 
- 			handler->first = sig;
 
- 		else
 
- 			last->next = sig;
 
- 	}
 
- 	pthread_mutex_unlock(&handler->mutex);
 
- 	return success;
 
- }
 
- void signal_handler_connect(signal_handler_t *handler, const char *signal,
 
- 		signal_callback_t callback, void *data)
 
- {
 
- 	struct signal_info *sig, *last;
 
- 	struct signal_callback cb_data = {callback, data, false};
 
- 	size_t idx;
 
- 	if (!handler)
 
- 		return;
 
- 	pthread_mutex_lock(&handler->mutex);
 
- 	sig = getsignal(handler, signal, &last);
 
- 	pthread_mutex_unlock(&handler->mutex);
 
- 	if (!sig) {
 
- 		blog(LOG_WARNING, "signal_handler_connect: "
 
- 		                  "signal '%s' not found", signal);
 
- 		return;
 
- 	}
 
- 	/* -------------- */
 
- 	pthread_mutex_lock(&sig->mutex);
 
- 	idx = signal_get_callback_idx(sig, callback, data);
 
- 	if (idx == DARRAY_INVALID)
 
- 		da_push_back(sig->callbacks, &cb_data);
 
- 	
 
- 	pthread_mutex_unlock(&sig->mutex);
 
- }
 
- static inline struct signal_info *getsignal_locked(signal_handler_t *handler,
 
- 		const char *name)
 
- {
 
- 	struct signal_info *sig;
 
- 	if (!handler)
 
- 		return NULL;
 
- 	pthread_mutex_lock(&handler->mutex);
 
- 	sig = getsignal(handler, name, NULL);
 
- 	pthread_mutex_unlock(&handler->mutex);
 
- 	return sig;
 
- }
 
- void signal_handler_disconnect(signal_handler_t *handler, const char *signal,
 
- 		signal_callback_t callback, void *data)
 
- {
 
- 	struct signal_info *sig = getsignal_locked(handler, signal);
 
- 	size_t idx;
 
- 	if (!sig)
 
- 		return;
 
- 	pthread_mutex_lock(&sig->mutex);
 
- 	idx = signal_get_callback_idx(sig, callback, data);
 
- 	if (idx != DARRAY_INVALID) {
 
- 		if (sig->signalling)
 
- 			sig->callbacks.array[idx].remove = true;
 
- 		else
 
- 			da_erase(sig->callbacks, idx);
 
- 	}
 
- 	
 
- 	pthread_mutex_unlock(&sig->mutex);
 
- }
 
- void signal_handler_signal(signal_handler_t *handler, const char *signal,
 
- 		calldata_t *params)
 
- {
 
- 	struct signal_info *sig = getsignal_locked(handler, signal);
 
- 	if (!sig)
 
- 		return;
 
- 	pthread_mutex_lock(&sig->mutex);
 
- 	sig->signalling = true;
 
- 	for (size_t i = 0; i < sig->callbacks.num; i++) {
 
- 		struct signal_callback *cb = sig->callbacks.array+i;
 
- 		if (!cb->remove)
 
- 			cb->callback(cb->data, params);
 
- 	}
 
- 	for (size_t i = sig->callbacks.num; i > 0; i--) {
 
- 		struct signal_callback *cb = sig->callbacks.array+i-1;
 
- 		if (cb->remove)
 
- 			da_erase(sig->callbacks, i-1);
 
- 	}
 
- 	sig->signalling = false;
 
- 	pthread_mutex_unlock(&sig->mutex);
 
- }
 
 
  |