events.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include <sys/time.h>
  2. #include <signal.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "mpool.h"
  6. #include "events.h"
  7. #include "events_internal.h"
  8. /* Event structure. */
  9. struct eventrec {
  10. int (* func)(void *);
  11. void * cookie;
  12. };
  13. MPOOL(eventrec, struct eventrec, 4096);
  14. /* Zero timeval, for use with non-blocking event runs. */
  15. static const struct timeval tv_zero = {0, 0};
  16. /* We want to interrupt a running event loop. */
  17. static volatile sig_atomic_t interrupt_requested = 0;
  18. /**
  19. * events_mkrec(func, cookie):
  20. * Package ${func}, ${cookie} into a struct eventrec.
  21. */
  22. struct eventrec *
  23. events_mkrec(int (* func)(void *), void * cookie)
  24. {
  25. struct eventrec * r;
  26. /* Allocate structure. */
  27. if ((r = mpool_eventrec_malloc()) == NULL)
  28. goto err0;
  29. /* Initialize. */
  30. r->func = func;
  31. r->cookie = cookie;
  32. /* Success! */
  33. return (r);
  34. err0:
  35. /* Failure! */
  36. return (NULL);
  37. }
  38. /**
  39. * events_freerec(r):
  40. * Free the eventrec ${r}.
  41. */
  42. void
  43. events_freerec(struct eventrec * r)
  44. {
  45. mpool_eventrec_free(r);
  46. }
  47. /* Do an event. This makes events_run cleaner. */
  48. static inline int
  49. doevent(struct eventrec * r)
  50. {
  51. int rc;
  52. /* Invoke the callback. */
  53. rc = (r->func)(r->cookie);
  54. /* Free the event record. */
  55. mpool_eventrec_free(r);
  56. /* Return the status code from the callback. */
  57. return (rc);
  58. }
  59. /**
  60. * events_run(void):
  61. * Run events. Events registered via events_immediate_register() will be run
  62. * first, in order of increasing ${prio} values; then events associated with
  63. * ready sockets registered via events_network_register(); finally, events
  64. * associated with expired timers registered via events_timer_register() will
  65. * be run. If any event function returns a non-zero result, no further events
  66. * will be run and said non-zero result will be returned; on error,
  67. * -1 will be returned. May be interrupted by events_interrupt(), in which
  68. * case 0 will be returned. If there are runnable events, events_run() is
  69. * guaranteed to run at least one; but it may return while there are still
  70. * more runnable events.
  71. */
  72. static int
  73. events_run_internal(void)
  74. {
  75. struct eventrec * r;
  76. struct timeval * tv;
  77. struct timeval tv2;
  78. int rc = 0;
  79. /* If we have any immediate events, process them and return. */
  80. if ((r = events_immediate_get()) != NULL) {
  81. while (r != NULL) {
  82. /* Process the event. */
  83. if ((rc = doevent(r)) != 0)
  84. goto done;
  85. /* Interrupt loop if requested. */
  86. if (interrupt_requested)
  87. goto done;
  88. /* Get the next event. */
  89. r = events_immediate_get();
  90. }
  91. /* We've processed at least one event; time to return. */
  92. goto done;
  93. }
  94. /*
  95. * Figure out the maximum duration to block, and wait up to that
  96. * duration for network events to become available.
  97. */
  98. if (events_timer_min(&tv))
  99. goto err0;
  100. if (events_network_select(tv, &interrupt_requested))
  101. goto err1;
  102. free(tv);
  103. /*
  104. * Check for available immediate events, network events, and timer
  105. * events, in that order of priority; exit only when no more events
  106. * are available or when interrupted.
  107. */
  108. do {
  109. /* Interrupt loop if requested. */
  110. if (interrupt_requested)
  111. goto done;
  112. /* Run an immediate event, if one is available. */
  113. if ((r = events_immediate_get()) != NULL) {
  114. if ((rc = doevent(r)) != 0)
  115. goto done;
  116. continue;
  117. }
  118. /* Run a network event, if one is available. */
  119. if ((r = events_network_get()) != NULL) {
  120. if ((rc = doevent(r)) != 0)
  121. goto done;
  122. continue;
  123. }
  124. /* Check if any new network events are available. */
  125. memcpy(&tv2, &tv_zero, sizeof(struct timeval));
  126. if (events_network_select(&tv2, &interrupt_requested))
  127. goto err0;
  128. if ((r = events_network_get()) != NULL) {
  129. if ((rc = doevent(r)) != 0)
  130. goto done;
  131. continue;
  132. }
  133. /* Run a timer event, if one is available. */
  134. if (events_timer_get(&r))
  135. goto err0;
  136. if (r != NULL) {
  137. if ((rc = doevent(r)) != 0)
  138. goto done;
  139. continue;
  140. }
  141. /* No events available. */
  142. break;
  143. } while (1);
  144. done:
  145. /* Success! */
  146. return (rc);
  147. err1:
  148. free(tv);
  149. err0:
  150. /* Failure! */
  151. return (-1);
  152. }
  153. /* Wrapper function for events_run to reset interrupt_requested. */
  154. int
  155. events_run(void)
  156. {
  157. int rc;
  158. /* Call the real function. */
  159. rc = events_run_internal();
  160. /* Reset interrupt_requested after quitting the loop. */
  161. interrupt_requested = 0;
  162. /* Return status. */
  163. return (rc);
  164. }
  165. /**
  166. * events_spin(done):
  167. * Call events_run() until ${done} is non-zero (and return 0), an error occurs
  168. * (and return -1), or a callback returns a non-zero status (and return the
  169. * status code from the callback). May be interrupted by events_interrupt()
  170. * (and return 0).
  171. */
  172. int
  173. events_spin(const int * done)
  174. {
  175. int rc = 0;
  176. /* Loop until we're done or have a non-zero status. */
  177. while ((done[0] == 0) && (rc == 0) && (interrupt_requested == 0)) {
  178. /* Run events. */
  179. rc = events_run_internal();
  180. }
  181. /* Reset interrupt_requested after quitting the loop. */
  182. interrupt_requested = 0;
  183. /* Return status code. */
  184. return (rc);
  185. }
  186. /**
  187. * events_interrupt(void):
  188. * Halt the event loop after finishing the current event. This function can
  189. * be safely called from within a signal handler.
  190. */
  191. void
  192. events_interrupt(void)
  193. {
  194. /* Interrupt the event loop. */
  195. interrupt_requested = 1;
  196. }
  197. /**
  198. * events_shutdown(void):
  199. * Deprecated function; does nothing.
  200. */
  201. void
  202. events_shutdown(void)
  203. {
  204. }