signal.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Copyright (c) 2013-2014 Hugh Bailey <[email protected]>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "../util/darray.h"
  17. #include "../util/threading.h"
  18. #include "decl.h"
  19. #include "signal.h"
  20. struct signal_callback {
  21. signal_callback_t callback;
  22. void *data;
  23. };
  24. struct signal_info {
  25. struct decl_info func;
  26. DARRAY(struct signal_callback) callbacks;
  27. pthread_mutex_t mutex;
  28. struct signal_info *next;
  29. };
  30. static inline struct signal_info *signal_info_create(struct decl_info *info)
  31. {
  32. struct signal_info *si = bmalloc(sizeof(struct signal_info));
  33. si->func = *info;
  34. si->next = NULL;
  35. da_init(si->callbacks);
  36. if (pthread_mutex_init(&si->mutex, NULL) != 0) {
  37. blog(LOG_ERROR, "Could not create signal");
  38. decl_info_free(&si->func);
  39. bfree(si);
  40. return NULL;
  41. }
  42. return si;
  43. }
  44. static inline void signal_info_destroy(struct signal_info *si)
  45. {
  46. if (si) {
  47. pthread_mutex_destroy(&si->mutex);
  48. decl_info_free(&si->func);
  49. da_free(si->callbacks);
  50. bfree(si);
  51. }
  52. }
  53. static inline size_t signal_get_callback_idx(struct signal_info *si,
  54. signal_callback_t callback, void *data)
  55. {
  56. for (size_t i = 0; i < si->callbacks.num; i++) {
  57. struct signal_callback *sc = si->callbacks.array+i;
  58. if (sc->callback == callback && sc->data == data)
  59. return i;
  60. }
  61. return DARRAY_INVALID;
  62. }
  63. struct signal_handler {
  64. struct signal_info *first;
  65. pthread_mutex_t mutex;
  66. };
  67. static struct signal_info *getsignal(signal_handler_t handler,
  68. const char *name, struct signal_info **p_last)
  69. {
  70. struct signal_info *signal, *last= NULL;
  71. signal = handler->first;
  72. while (signal != NULL) {
  73. if (strcmp(signal->func.name, name) == 0)
  74. break;
  75. last = signal;
  76. signal = signal->next;
  77. }
  78. if (p_last)
  79. *p_last = last;
  80. return signal;
  81. }
  82. /* ------------------------------------------------------------------------- */
  83. signal_handler_t signal_handler_create(void)
  84. {
  85. struct signal_handler *handler = bmalloc(sizeof(struct signal_handler));
  86. handler->first = NULL;
  87. if (pthread_mutex_init(&handler->mutex, NULL) != 0) {
  88. blog(LOG_ERROR, "Couldn't create signal handler!");
  89. bfree(handler);
  90. return NULL;
  91. }
  92. return handler;
  93. }
  94. void signal_handler_destroy(signal_handler_t handler)
  95. {
  96. if (handler) {
  97. struct signal_info *sig = handler->first;
  98. while (sig != NULL) {
  99. struct signal_info *next = sig->next;
  100. signal_info_destroy(sig);
  101. sig = next;
  102. }
  103. pthread_mutex_destroy(&handler->mutex);
  104. bfree(handler);
  105. }
  106. }
  107. bool signal_handler_add(signal_handler_t handler, const char *signal_decl)
  108. {
  109. struct decl_info func = {0};
  110. struct signal_info *sig, *last;
  111. bool success = true;
  112. if (!parse_decl_string(&func, signal_decl)) {
  113. blog(LOG_ERROR, "Signal declaration invalid: %s", signal_decl);
  114. return false;
  115. }
  116. pthread_mutex_lock(&handler->mutex);
  117. sig = getsignal(handler, func.name, &last);
  118. if (sig) {
  119. blog(LOG_WARNING, "Signal declaration '%s' exists", func.name);
  120. decl_info_free(&func);
  121. success = false;
  122. } else {
  123. sig = signal_info_create(&func);
  124. if (!last)
  125. handler->first = sig;
  126. else
  127. last->next = sig;
  128. }
  129. pthread_mutex_unlock(&handler->mutex);
  130. return success;
  131. }
  132. void signal_handler_connect(signal_handler_t handler, const char *signal,
  133. signal_callback_t callback, void *data)
  134. {
  135. struct signal_info *sig, *last;
  136. struct signal_callback cb_data = {callback, data};
  137. size_t idx;
  138. if (!handler)
  139. return;
  140. pthread_mutex_lock(&handler->mutex);
  141. sig = getsignal(handler, signal, &last);
  142. if (!sig)
  143. return;
  144. pthread_mutex_unlock(&handler->mutex);
  145. /* -------------- */
  146. pthread_mutex_lock(&sig->mutex);
  147. idx = signal_get_callback_idx(sig, callback, data);
  148. if (idx == DARRAY_INVALID)
  149. da_push_back(sig->callbacks, &cb_data);
  150. pthread_mutex_unlock(&sig->mutex);
  151. }
  152. static inline struct signal_info *getsignal_locked(signal_handler_t handler,
  153. const char *name)
  154. {
  155. struct signal_info *sig;
  156. if (!handler)
  157. return NULL;
  158. pthread_mutex_lock(&handler->mutex);
  159. sig = getsignal(handler, name, NULL);
  160. pthread_mutex_unlock(&handler->mutex);
  161. return sig;
  162. }
  163. void signal_handler_disconnect(signal_handler_t handler, const char *signal,
  164. signal_callback_t callback, void *data)
  165. {
  166. struct signal_info *sig = getsignal_locked(handler, signal);
  167. size_t idx;
  168. if (!sig)
  169. return;
  170. pthread_mutex_lock(&sig->mutex);
  171. idx = signal_get_callback_idx(sig, callback, data);
  172. if (idx != DARRAY_INVALID)
  173. da_erase(sig->callbacks, idx);
  174. pthread_mutex_unlock(&sig->mutex);
  175. }
  176. void signal_handler_signal(signal_handler_t handler, const char *signal,
  177. calldata_t params)
  178. {
  179. struct signal_info *sig = getsignal_locked(handler, signal);
  180. if (!sig)
  181. return;
  182. pthread_mutex_lock(&sig->mutex);
  183. for (size_t i = 0; i < sig->callbacks.num; i++) {
  184. struct signal_callback *cb = sig->callbacks.array+i;
  185. cb->callback(cb->data, params);
  186. }
  187. pthread_mutex_unlock(&sig->mutex);
  188. }