timeout.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /* ==========================================================================
  2. * timeout.h - Tickless hierarchical timing wheel.
  3. * --------------------------------------------------------------------------
  4. * Copyright (c) 2013, 2014 William Ahern
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a
  7. * copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sublicense, and/or sell copies of the Software, and to permit
  11. * persons to whom the Software is furnished to do so, subject to the
  12. * following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  20. * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  21. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  22. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  23. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. * ==========================================================================
  25. */
  26. #ifndef TIMEOUT_H
  27. #define TIMEOUT_H
  28. #include <stdbool.h> /* bool */
  29. #include <stdio.h> /* FILE */
  30. #include <inttypes.h> /* PRIu64 PRIx64 PRIX64 uint64_t */
  31. #include "tor_queue.h" /* TAILQ(3) */
  32. /*
  33. * V E R S I O N I N T E R F A C E S
  34. *
  35. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  36. #if !defined TIMEOUT_PUBLIC
  37. #define TIMEOUT_PUBLIC
  38. #endif
  39. #define TIMEOUT_VERSION TIMEOUT_V_REL
  40. #define TIMEOUT_VENDOR "william@25thandClement.com"
  41. #define TIMEOUT_V_REL 0x20160226
  42. #define TIMEOUT_V_ABI 0x20160224
  43. #define TIMEOUT_V_API 0x20160226
  44. TIMEOUT_PUBLIC int timeout_version(void);
  45. TIMEOUT_PUBLIC const char *timeout_vendor(void);
  46. TIMEOUT_PUBLIC int timeout_v_rel(void);
  47. TIMEOUT_PUBLIC int timeout_v_abi(void);
  48. TIMEOUT_PUBLIC int timeout_v_api(void);
  49. /*
  50. * I N T E G E R T Y P E I N T E R F A C E S
  51. *
  52. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  53. #define TIMEOUT_C(n) UINT64_C(n)
  54. #define TIMEOUT_PRIu PRIu64
  55. #define TIMEOUT_PRIx PRIx64
  56. #define TIMEOUT_PRIX PRIX64
  57. #define TIMEOUT_mHZ TIMEOUT_C(1000)
  58. #define TIMEOUT_uHZ TIMEOUT_C(1000000)
  59. #define TIMEOUT_nHZ TIMEOUT_C(1000000000)
  60. typedef uint64_t timeout_t;
  61. #define timeout_error_t int /* for documentation purposes */
  62. /*
  63. * C A L L B A C K I N T E R F A C E
  64. *
  65. * Callback function parameters unspecified to make embedding into existing
  66. * applications easier.
  67. *
  68. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  69. #ifndef TIMEOUT_CB_OVERRIDE
  70. struct timeout_cb {
  71. void (*fn)(void);
  72. void *arg;
  73. }; /* struct timeout_cb */
  74. #endif
  75. /*
  76. * T I M E O U T I N T E R F A C E S
  77. *
  78. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  79. #ifndef TIMEOUT_DISABLE_INTERVALS
  80. #define TIMEOUT_INT 0x01 /* interval (repeating) timeout */
  81. #endif
  82. #define TIMEOUT_ABS 0x02 /* treat timeout values as absolute */
  83. #define TIMEOUT_INITIALIZER(flags) { (flags) }
  84. #define timeout_setcb(to, fn, arg) do { \
  85. (to)->callback.fn = (fn); \
  86. (to)->callback.arg = (arg); \
  87. } while (0)
  88. struct timeout {
  89. int flags;
  90. timeout_t expires;
  91. /* absolute expiration time */
  92. struct timeout_list *pending;
  93. /* timeout list if pending on wheel or expiry queue */
  94. TOR_TAILQ_ENTRY(timeout) tqe;
  95. /* entry member for struct timeout_list lists */
  96. #ifndef TIMEOUT_DISABLE_CALLBACKS
  97. struct timeout_cb callback;
  98. /* optional callback information */
  99. #endif
  100. #ifndef TIMEOUT_DISABLE_INTERVALS
  101. timeout_t interval;
  102. /* timeout interval if periodic */
  103. #endif
  104. #ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
  105. struct timeouts *timeouts;
  106. /* timeouts collection if member of */
  107. #endif
  108. }; /* struct timeout */
  109. TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *, int);
  110. /* initialize timeout structure (same as TIMEOUT_INITIALIZER) */
  111. #ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
  112. TIMEOUT_PUBLIC bool timeout_pending(struct timeout *);
  113. /* true if on timing wheel, false otherwise */
  114. TIMEOUT_PUBLIC bool timeout_expired(struct timeout *);
  115. /* true if on expired queue, false otherwise */
  116. TIMEOUT_PUBLIC void timeout_del(struct timeout *);
  117. /* remove timeout from any timing wheel (okay if not member of any) */
  118. #endif
  119. /*
  120. * T I M I N G W H E E L I N T E R F A C E S
  121. *
  122. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  123. struct timeouts;
  124. TIMEOUT_PUBLIC struct timeouts *timeouts_open(timeout_t, timeout_error_t *);
  125. /* open a new timing wheel, setting optional HZ (for float conversions) */
  126. TIMEOUT_PUBLIC void timeouts_close(struct timeouts *);
  127. /* destroy timing wheel */
  128. TIMEOUT_PUBLIC timeout_t timeouts_hz(struct timeouts *);
  129. /* return HZ setting (for float conversions) */
  130. TIMEOUT_PUBLIC void timeouts_update(struct timeouts *, timeout_t);
  131. /* update timing wheel with current absolute time */
  132. TIMEOUT_PUBLIC void timeouts_step(struct timeouts *, timeout_t);
  133. /* step timing wheel by relative time */
  134. TIMEOUT_PUBLIC timeout_t timeouts_get_curtime(struct timeouts *);
  135. /* Return the current tick. */
  136. TIMEOUT_PUBLIC timeout_t timeouts_timeout(struct timeouts *);
  137. /* return interval to next required update */
  138. TIMEOUT_PUBLIC void timeouts_add(struct timeouts *, struct timeout *, timeout_t);
  139. /* add timeout to timing wheel */
  140. TIMEOUT_PUBLIC void timeouts_del(struct timeouts *, struct timeout *);
  141. /* remove timeout from any timing wheel or expired queue (okay if on neither) */
  142. TIMEOUT_PUBLIC struct timeout *timeouts_get(struct timeouts *);
  143. /* return any expired timeout (caller should loop until NULL-return) */
  144. TIMEOUT_PUBLIC bool timeouts_pending(struct timeouts *);
  145. /* return true if any timeouts pending on timing wheel */
  146. TIMEOUT_PUBLIC bool timeouts_expired(struct timeouts *);
  147. /* return true if any timeouts on expired queue */
  148. TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *, FILE *);
  149. /* return true if invariants hold. describes failures to optional file handle. */
  150. #define TIMEOUTS_PENDING 0x10
  151. #define TIMEOUTS_EXPIRED 0x20
  152. #define TIMEOUTS_ALL (TIMEOUTS_PENDING|TIMEOUTS_EXPIRED)
  153. #define TIMEOUTS_CLEAR 0x40
  154. #define TIMEOUTS_IT_INITIALIZER(flags) { (flags), 0, 0, 0, 0 }
  155. #define TIMEOUTS_IT_INIT(cur, _flags) do { \
  156. (cur)->flags = (_flags); \
  157. (cur)->pc = 0; \
  158. } while (0)
  159. struct timeouts_it {
  160. int flags;
  161. unsigned pc, i, j;
  162. struct timeout *to;
  163. }; /* struct timeouts_it */
  164. TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *, struct timeouts_it *);
  165. /* return next timeout in pending wheel or expired queue. caller can delete
  166. * the returned timeout, but should not otherwise manipulate the timing
  167. * wheel. in particular, caller SHOULD NOT delete any other timeout as that
  168. * could invalidate cursor state and trigger a use-after-free.
  169. */
  170. #define TIMEOUTS_FOREACH(var, T, flags) \
  171. struct timeouts_it _it = TIMEOUTS_IT_INITIALIZER((flags)); \
  172. while (((var) = timeouts_next((T), &_it)))
  173. /*
  174. * B O N U S W H E E L I N T E R F A C E S
  175. *
  176. * I usually use floating point timeouts in all my code, but it's cleaner to
  177. * separate it to keep the core algorithmic code simple.
  178. *
  179. * Using macros instead of static inline routines where <math.h> routines
  180. * might be used to keep -lm linking optional.
  181. *
  182. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  183. #include <math.h> /* ceil(3) */
  184. #define timeouts_f2i(T, f) \
  185. ((timeout_t)ceil((f) * timeouts_hz((T)))) /* prefer late expiration over early */
  186. #define timeouts_i2f(T, i) \
  187. ((double)(i) / timeouts_hz((T)))
  188. #define timeouts_addf(T, to, timeout) \
  189. timeouts_add((T), (to), timeouts_f2i((T), (timeout)))
  190. #endif /* TIMEOUT_H */