events_timer.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include <sys/time.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "monoclock.h"
  5. #include "timerqueue.h"
  6. #include "events.h"
  7. #include "events_internal.h"
  8. struct timerrec {
  9. struct eventrec * r;
  10. void * cookie;
  11. struct timeval tv_orig;
  12. };
  13. /* This also tracks whether we've initialized the atexit function. */
  14. static struct timerqueue * Q = NULL;
  15. static void events_timer_shutdown(void);
  16. /* Set tv := <current time> + tdelta. */
  17. static int
  18. gettimeout(struct timeval * tv, const struct timeval * tdelta)
  19. {
  20. if (monoclock_get(tv))
  21. goto err0;
  22. tv->tv_sec += tdelta->tv_sec;
  23. if ((tv->tv_usec += tdelta->tv_usec) >= 1000000) {
  24. tv->tv_usec -= 1000000;
  25. tv->tv_sec += 1;
  26. }
  27. /* Success! */
  28. return (0);
  29. err0:
  30. /* Failure! */
  31. return (-1);
  32. }
  33. /**
  34. * events_timer_register(func, cookie, timeo):
  35. * Register ${func}(${cookie}) to be run ${timeo} in the future. Return a
  36. * cookie which can be passed to events_timer_cancel() or events_timer_reset().
  37. */
  38. void *
  39. events_timer_register(int (* func)(void *), void * cookie,
  40. const struct timeval * timeo)
  41. {
  42. struct eventrec * r;
  43. struct timerrec * t;
  44. struct timeval tv;
  45. /* Create the timer queue if it doesn't exist yet. */
  46. if (Q == NULL) {
  47. if ((Q = timerqueue_init()) == NULL)
  48. goto err0;
  49. /* Clean up the timer queue at exit. */
  50. if (atexit(events_timer_shutdown))
  51. goto err0;
  52. }
  53. /* Bundle into an eventrec record. */
  54. if ((r = events_mkrec(func, cookie)) == NULL)
  55. goto err0;
  56. /* Create a timer record. */
  57. if ((t = malloc(sizeof(struct timerrec))) == NULL)
  58. goto err1;
  59. t->r = r;
  60. memcpy(&t->tv_orig, timeo, sizeof(struct timeval));
  61. /* Compute the absolute timeout. */
  62. if (gettimeout(&tv, &t->tv_orig))
  63. goto err2;
  64. /* Add this to the timer queue. */
  65. if ((t->cookie = timerqueue_add(Q, &tv, t)) == NULL)
  66. goto err2;
  67. /* Success! */
  68. return (t);
  69. err2:
  70. free(t);
  71. err1:
  72. events_freerec(r);
  73. err0:
  74. /* Failure! */
  75. return (NULL);
  76. }
  77. /**
  78. * events_timer_register_double(func, cookie, timeo):
  79. * As events_timer_register(), but ${timeo} is a double-precision
  80. * floating-point value specifying a number of seconds.
  81. */
  82. void *
  83. events_timer_register_double(int (* func)(void *), void * cookie,
  84. double timeo)
  85. {
  86. struct timeval tv;
  87. /* Convert timeo to a struct timeval. */
  88. tv.tv_sec = (time_t)timeo;
  89. tv.tv_usec = (suseconds_t)((timeo - (double)tv.tv_sec) * 1000000.0);
  90. /* Schedule the timeout. */
  91. return (events_timer_register(func, cookie, &tv));
  92. }
  93. /**
  94. * events_timer_cancel(cookie):
  95. * Cancel the timer for which the cookie ${cookie} was returned by
  96. * events_timer_register().
  97. */
  98. void
  99. events_timer_cancel(void * cookie)
  100. {
  101. struct timerrec * t = cookie;
  102. /* Remove from the timer queue. */
  103. timerqueue_delete(Q, t->cookie);
  104. /* Free the eventrec and timer records. */
  105. events_freerec(t->r);
  106. free(t);
  107. }
  108. /**
  109. * events_timer_reset(cookie):
  110. * Reset the timer for which the cookie ${cookie} was returned by
  111. * events_timer_register() to its initial value.
  112. */
  113. int
  114. events_timer_reset(void * cookie)
  115. {
  116. struct timerrec * t = cookie;
  117. struct timeval tv;
  118. /* Compute the new timeout. */
  119. if (gettimeout(&tv, &t->tv_orig))
  120. goto err0;
  121. /* Adjust the timer. */
  122. timerqueue_increase(Q, t->cookie, &tv);
  123. /* Success! */
  124. return (0);
  125. err0:
  126. /* Failure! */
  127. return (-1);
  128. }
  129. /**
  130. * events_timer_min(timeo):
  131. * Return via ${timeo} a pointer to the minimum time which must be waited
  132. * before a timer will expire; or to NULL if there are no timers. The caller
  133. * is responsible for freeing the returned pointer.
  134. */
  135. int
  136. events_timer_min(struct timeval ** timeo)
  137. {
  138. struct timeval tnow;
  139. const struct timeval * tv;
  140. /* If we have no queue, we have no timers; return NULL. */
  141. if (Q == NULL) {
  142. *timeo = NULL;
  143. goto done;
  144. }
  145. /* Get the minimum timer from the queue. */
  146. tv = timerqueue_getmin(Q);
  147. /* If there are no timers, return NULL. */
  148. if (tv == NULL) {
  149. *timeo = NULL;
  150. goto done;
  151. }
  152. /* Allocate space for holding the returned timeval. */
  153. if ((*timeo = malloc(sizeof(struct timeval))) == NULL)
  154. goto err0;
  155. /* Get the current time... */
  156. if (monoclock_get(&tnow))
  157. goto err1;
  158. /* ... and compare it to the minimum timer. */
  159. if ((tnow.tv_sec > tv->tv_sec) ||
  160. ((tnow.tv_sec == tv->tv_sec) && (tnow.tv_usec > tv->tv_usec))) {
  161. /* The timer has already expired, so return zero. */
  162. (*timeo)->tv_sec = 0;
  163. (*timeo)->tv_usec = 0;
  164. } else {
  165. /* Compute the difference. */
  166. (*timeo)->tv_sec = tv->tv_sec - tnow.tv_sec;
  167. (*timeo)->tv_usec = tv->tv_usec - tnow.tv_usec;
  168. if (tv->tv_usec < tnow.tv_usec) {
  169. (*timeo)->tv_usec += 1000000;
  170. (*timeo)->tv_sec -= 1;
  171. }
  172. }
  173. done:
  174. /* Success! */
  175. return (0);
  176. err1:
  177. free(*timeo);
  178. err0:
  179. /* Failure! */
  180. return (-1);
  181. }
  182. /**
  183. * events_timer_get(r):
  184. * Return via ${r} a pointer to an eventrec structure corresponding to an
  185. * expired timer, and delete said timer; or to NULL if there are no expired
  186. * timers. The caller is responsible for freeing the returned pointer.
  187. */
  188. int
  189. events_timer_get(struct eventrec ** r)
  190. {
  191. struct timeval tnow;
  192. struct timerrec * t;
  193. /* If we have no queue, we have no timers; return NULL. */
  194. if (Q == NULL) {
  195. *r = NULL;
  196. goto done;
  197. }
  198. /* Get current time. */
  199. if (monoclock_get(&tnow))
  200. goto err0;
  201. /* Get an expired timer, if there is one. */
  202. t = timerqueue_getptr(Q, &tnow);
  203. /* If there is an expired timer... */
  204. if (t != NULL) {
  205. /* ... pass back the eventrec and free the timer. */
  206. *r = t->r;
  207. free(t);
  208. } else {
  209. /* Otherwise, return NULL. */
  210. *r = NULL;
  211. }
  212. done:
  213. /* Success! */
  214. return (0);
  215. err0:
  216. /* Failure! */
  217. return (-1);
  218. }
  219. /**
  220. * events_timer_shutdown(void):
  221. * Clean up and free memory. This should run automatically via atexit.
  222. */
  223. static void
  224. events_timer_shutdown(void)
  225. {
  226. /* If we have a queue and it is empty, free it. */
  227. if ((Q != NULL) && (timerqueue_getmin(Q) == NULL)) {
  228. timerqueue_free(Q);
  229. Q = NULL;
  230. }
  231. }