signal.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Copyright (c) 2013 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 "signal.h"
  19. struct signal_callback {
  20. void (*callback)(calldata_t, void*);
  21. void *data;
  22. };
  23. struct signal_info {
  24. char *name;
  25. DARRAY(struct signal_callback) callbacks;
  26. pthread_mutex_t mutex;
  27. struct signal_info *next;
  28. };
  29. static inline struct signal_info *signal_info_create(const char *name)
  30. {
  31. struct signal_info *si = bmalloc(sizeof(struct signal_info));
  32. si->name = bstrdup(name);
  33. si->next = NULL;
  34. da_init(si->callbacks);
  35. if (pthread_mutex_init(&si->mutex, NULL) != 0) {
  36. blog(LOG_ERROR, "Could not create signal!");
  37. bfree(si->name);
  38. bfree(si);
  39. return NULL;
  40. }
  41. return si;
  42. }
  43. static inline void signal_info_destroy(struct signal_info *si)
  44. {
  45. if (si) {
  46. pthread_mutex_destroy(&si->mutex);
  47. bfree(si->name);
  48. da_free(si->callbacks);
  49. bfree(si);
  50. }
  51. }
  52. static inline size_t signal_get_callback_idx(struct signal_info *si,
  53. void (*callback)(void*, calldata_t), void *data)
  54. {
  55. for (size_t i = 0; i < si->callbacks.num; i++) {
  56. struct signal_callback *sc = si->callbacks.array+i;
  57. if (sc->callback == callback && sc->data == data)
  58. return i;
  59. }
  60. return DARRAY_INVALID;
  61. }
  62. struct signal_handler {
  63. /* TODO: might be good to use hash table instead */
  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->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. void signal_handler_connect(signal_handler_t handler, const char *signal,
  108. void (*callback)(void*, calldata_t), void *data)
  109. {
  110. struct signal_info *sig, *last;
  111. struct signal_callback cb_data = {callback, data};
  112. size_t idx;
  113. pthread_mutex_lock(&handler->mutex);
  114. sig = getsignal(handler, signal, &last);
  115. if (!sig) {
  116. sig = signal_info_create(signal);
  117. if (!last)
  118. handler->first = sig;
  119. else
  120. last->next = sig;
  121. if (!sig)
  122. return;
  123. }
  124. pthread_mutex_unlock(&handler->mutex);
  125. /* -------------- */
  126. pthread_mutex_lock(&sig->mutex);
  127. idx = signal_get_callback_idx(sig, callback, data);
  128. if (idx == DARRAY_INVALID)
  129. da_push_back(sig->callbacks, &cb_data);
  130. pthread_mutex_unlock(&sig->mutex);
  131. }
  132. static inline struct signal_info *getsignal_locked(signal_handler_t handler,
  133. const char *name)
  134. {
  135. struct signal_info *sig;
  136. pthread_mutex_lock(&handler->mutex);
  137. sig = getsignal(handler, name, NULL);
  138. pthread_mutex_unlock(&handler->mutex);
  139. return sig;
  140. }
  141. void signal_handler_disconnect(signal_handler_t handler, const char *signal,
  142. void (*callback)(void*, calldata_t), void *data)
  143. {
  144. struct signal_info *sig = getsignal_locked(handler, signal);
  145. size_t idx;
  146. if (!sig)
  147. return;
  148. pthread_mutex_lock(&sig->mutex);
  149. idx = signal_get_callback_idx(sig, callback, data);
  150. if (idx != DARRAY_INVALID)
  151. da_erase(sig->callbacks, idx);
  152. pthread_mutex_unlock(&sig->mutex);
  153. }
  154. void signal_handler_signal(signal_handler_t handler, const char *signal,
  155. calldata_t params)
  156. {
  157. struct signal_info *sig = getsignal_locked(handler, signal);
  158. if (!sig)
  159. return;
  160. pthread_mutex_lock(&sig->mutex);
  161. for (size_t i = 0; i < sig->callbacks.num; i++) {
  162. struct signal_callback *cb = sig->callbacks.array+i;
  163. cb->callback(cb->data, params);
  164. }
  165. pthread_mutex_unlock(&sig->mutex);
  166. }