timeout.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. /* ==========================================================================
  2. * timeout.c - 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. #ifdef HAVE_CONFIG_H
  27. #include "orconfig.h"
  28. #endif
  29. #include <limits.h> /* CHAR_BIT */
  30. #include <stddef.h> /* NULL */
  31. #include <stdlib.h> /* malloc(3) free(3) */
  32. #include <stdio.h> /* FILE fprintf(3) */
  33. #include <inttypes.h> /* UINT64_C uint64_t */
  34. #include <string.h> /* memset(3) */
  35. #include <errno.h> /* errno */
  36. #include "tor_queue.h" /* TAILQ(3) */
  37. #include "timeout.h"
  38. #ifndef TIMEOUT_DEBUG
  39. #define TIMEOUT_DEBUG 0
  40. #endif
  41. #if TIMEOUT_DEBUG - 0
  42. #include "timeout-debug.h"
  43. #endif
  44. #ifdef TIMEOUT_DISABLE_RELATIVE_ACCESS
  45. #define TO_SET_TIMEOUTS(to, T) ((void)0)
  46. #else
  47. #define TO_SET_TIMEOUTS(to, T) ((to)->timeouts = (T))
  48. #endif
  49. /*
  50. * A N C I L L A R Y R O U T I N E S
  51. *
  52. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  53. #define abstime_t timeout_t /* for documentation purposes */
  54. #define reltime_t timeout_t /* "" */
  55. #if !defined countof
  56. #define countof(a) (sizeof (a) / sizeof *(a))
  57. #endif
  58. #if !defined endof
  59. #define endof(a) (&(a)[countof(a)])
  60. #endif
  61. #if !defined MIN
  62. #define MIN(a, b) (((a) < (b))? (a) : (b))
  63. #endif
  64. #if !defined MAX
  65. #define MAX(a, b) (((a) > (b))? (a) : (b))
  66. #endif
  67. #if !defined TOR_TAILQ_CONCAT
  68. #define TOR_TAILQ_CONCAT(head1, head2, field) do { \
  69. if (!TOR_TAILQ_EMPTY(head2)) { \
  70. *(head1)->tqh_last = (head2)->tqh_first; \
  71. (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
  72. (head1)->tqh_last = (head2)->tqh_last; \
  73. TOR_TAILQ_INIT((head2)); \
  74. } \
  75. } while (0)
  76. #endif
  77. #if !defined TOR_TAILQ_FOREACH_SAFE
  78. #define TOR_TAILQ_FOREACH_SAFE(var, head, field, tvar) \
  79. for ((var) = TOR_TAILQ_FIRST(head); \
  80. (var) && ((tvar) = TOR_TAILQ_NEXT(var, field), 1); \
  81. (var) = (tvar))
  82. #endif
  83. /*
  84. * B I T M A N I P U L A T I O N R O U T I N E S
  85. *
  86. * The macros and routines below implement wheel parameterization. The
  87. * inputs are:
  88. *
  89. * WHEEL_BIT - The number of value bits mapped in each wheel. The
  90. * lowest-order WHEEL_BIT bits index the lowest-order (highest
  91. * resolution) wheel, the next group of WHEEL_BIT bits the
  92. * higher wheel, etc.
  93. *
  94. * WHEEL_NUM - The number of wheels. WHEEL_BIT * WHEEL_NUM = the number of
  95. * value bits used by all the wheels. For the default of 6 and
  96. * 4, only the low 24 bits are processed. Any timeout value
  97. * larger than this will cycle through again.
  98. *
  99. * The implementation uses bit fields to remember which slot in each wheel
  100. * is populated, and to generate masks of expiring slots according to the
  101. * current update interval (i.e. the "tickless" aspect). The slots to
  102. * process in a wheel are (populated-set & interval-mask).
  103. *
  104. * WHEEL_BIT cannot be larger than 6 bits because 2^6 -> 64 is the largest
  105. * number of slots which can be tracked in a uint64_t integer bit field.
  106. * WHEEL_BIT cannot be smaller than 3 bits because of our rotr and rotl
  107. * routines, which only operate on all the value bits in an integer, and
  108. * there's no integer smaller than uint8_t.
  109. *
  110. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  111. #if !defined WHEEL_BIT
  112. #define WHEEL_BIT 6
  113. #endif
  114. #if !defined WHEEL_NUM
  115. #define WHEEL_NUM 4
  116. #endif
  117. #define WHEEL_LEN (1U << WHEEL_BIT)
  118. #define WHEEL_MAX (WHEEL_LEN - 1)
  119. #define WHEEL_MASK (WHEEL_LEN - 1)
  120. #define TIMEOUT_MAX ((TIMEOUT_C(1) << (WHEEL_BIT * WHEEL_NUM)) - 1)
  121. #include "timeout-bitops.c"
  122. #if WHEEL_BIT == 6
  123. #define ctz(n) ctz64(n)
  124. #define clz(n) clz64(n)
  125. #define fls(n) ((int)(64 - clz64(n)))
  126. #else
  127. #define ctz(n) ctz32(n)
  128. #define clz(n) clz32(n)
  129. #define fls(n) ((int)(32 - clz32(n)))
  130. #endif
  131. #if WHEEL_BIT == 6
  132. #define WHEEL_C(n) UINT64_C(n)
  133. #define WHEEL_PRIu PRIu64
  134. #define WHEEL_PRIx PRIx64
  135. typedef uint64_t wheel_t;
  136. #elif WHEEL_BIT == 5
  137. #define WHEEL_C(n) UINT32_C(n)
  138. #define WHEEL_PRIu PRIu32
  139. #define WHEEL_PRIx PRIx32
  140. typedef uint32_t wheel_t;
  141. #elif WHEEL_BIT == 4
  142. #define WHEEL_C(n) UINT16_C(n)
  143. #define WHEEL_PRIu PRIu16
  144. #define WHEEL_PRIx PRIx16
  145. typedef uint16_t wheel_t;
  146. #elif WHEEL_BIT == 3
  147. #define WHEEL_C(n) UINT8_C(n)
  148. #define WHEEL_PRIu PRIu8
  149. #define WHEEL_PRIx PRIx8
  150. typedef uint8_t wheel_t;
  151. #else
  152. #error invalid WHEEL_BIT value
  153. #endif
  154. static inline wheel_t rotl(const wheel_t v, int c) {
  155. if (!(c &= (sizeof v * CHAR_BIT - 1)))
  156. return v;
  157. return (v << c) | (v >> (sizeof v * CHAR_BIT - c));
  158. } /* rotl() */
  159. static inline wheel_t rotr(const wheel_t v, int c) {
  160. if (!(c &= (sizeof v * CHAR_BIT - 1)))
  161. return v;
  162. return (v >> c) | (v << (sizeof v * CHAR_BIT - c));
  163. } /* rotr() */
  164. /*
  165. * T I M E R R O U T I N E S
  166. *
  167. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  168. TOR_TAILQ_HEAD(timeout_list, timeout);
  169. struct timeouts {
  170. struct timeout_list wheel[WHEEL_NUM][WHEEL_LEN], expired;
  171. wheel_t pending[WHEEL_NUM];
  172. timeout_t curtime;
  173. timeout_t hertz;
  174. }; /* struct timeouts */
  175. static struct timeouts *timeouts_init(struct timeouts *T, timeout_t hz) {
  176. unsigned i, j;
  177. for (i = 0; i < countof(T->wheel); i++) {
  178. for (j = 0; j < countof(T->wheel[i]); j++) {
  179. TOR_TAILQ_INIT(&T->wheel[i][j]);
  180. }
  181. }
  182. TOR_TAILQ_INIT(&T->expired);
  183. for (i = 0; i < countof(T->pending); i++) {
  184. T->pending[i] = 0;
  185. }
  186. T->curtime = 0;
  187. T->hertz = (hz)? hz : TIMEOUT_mHZ;
  188. return T;
  189. } /* timeouts_init() */
  190. TIMEOUT_PUBLIC struct timeouts *timeouts_open(timeout_t hz, int *error) {
  191. struct timeouts *T;
  192. if ((T = malloc(sizeof *T)))
  193. return timeouts_init(T, hz);
  194. *error = errno;
  195. return NULL;
  196. } /* timeouts_open() */
  197. static void timeouts_reset(struct timeouts *T) {
  198. struct timeout_list reset;
  199. struct timeout *to;
  200. unsigned i, j;
  201. TOR_TAILQ_INIT(&reset);
  202. for (i = 0; i < countof(T->wheel); i++) {
  203. for (j = 0; j < countof(T->wheel[i]); j++) {
  204. TOR_TAILQ_CONCAT(&reset, &T->wheel[i][j], tqe);
  205. }
  206. }
  207. TOR_TAILQ_CONCAT(&reset, &T->expired, tqe);
  208. TOR_TAILQ_FOREACH(to, &reset, tqe) {
  209. to->pending = NULL;
  210. TO_SET_TIMEOUTS(to, NULL);
  211. }
  212. } /* timeouts_reset() */
  213. TIMEOUT_PUBLIC void timeouts_close(struct timeouts *T) {
  214. /*
  215. * NOTE: Delete installed timeouts so timeout_pending() and
  216. * timeout_expired() worked as expected.
  217. */
  218. timeouts_reset(T);
  219. free(T);
  220. } /* timeouts_close() */
  221. TIMEOUT_PUBLIC timeout_t timeouts_hz(struct timeouts *T) {
  222. return T->hertz;
  223. } /* timeouts_hz() */
  224. TIMEOUT_PUBLIC void timeouts_del(struct timeouts *T, struct timeout *to) {
  225. if (to->pending) {
  226. TOR_TAILQ_REMOVE(to->pending, to, tqe);
  227. if (to->pending != &T->expired && TOR_TAILQ_EMPTY(to->pending)) {
  228. ptrdiff_t index_ = to->pending - &T->wheel[0][0];
  229. int wheel = (int) (index_ / WHEEL_LEN);
  230. int slot = index_ % WHEEL_LEN;
  231. T->pending[wheel] &= ~(WHEEL_C(1) << slot);
  232. }
  233. to->pending = NULL;
  234. TO_SET_TIMEOUTS(to, NULL);
  235. }
  236. } /* timeouts_del() */
  237. static inline reltime_t timeout_rem(struct timeouts *T, struct timeout *to) {
  238. return to->expires - T->curtime;
  239. } /* timeout_rem() */
  240. static inline int timeout_wheel(timeout_t timeout) {
  241. /* must be called with timeout != 0, so fls input is nonzero */
  242. return (fls(MIN(timeout, TIMEOUT_MAX)) - 1) / WHEEL_BIT;
  243. } /* timeout_wheel() */
  244. static inline int timeout_slot(int wheel, timeout_t expires) {
  245. return WHEEL_MASK & ((expires >> (wheel * WHEEL_BIT)) - !!wheel);
  246. } /* timeout_slot() */
  247. static void timeouts_sched(struct timeouts *T, struct timeout *to, timeout_t expires) {
  248. timeout_t rem;
  249. int wheel, slot;
  250. timeouts_del(T, to);
  251. to->expires = expires;
  252. TO_SET_TIMEOUTS(to, T);
  253. if (expires > T->curtime) {
  254. rem = timeout_rem(T, to);
  255. /* rem is nonzero since:
  256. * rem == timeout_rem(T,to),
  257. * == to->expires - T->curtime
  258. * and above we have expires > T->curtime.
  259. */
  260. wheel = timeout_wheel(rem);
  261. slot = timeout_slot(wheel, to->expires);
  262. to->pending = &T->wheel[wheel][slot];
  263. TOR_TAILQ_INSERT_TAIL(to->pending, to, tqe);
  264. T->pending[wheel] |= WHEEL_C(1) << slot;
  265. } else {
  266. to->pending = &T->expired;
  267. TOR_TAILQ_INSERT_TAIL(to->pending, to, tqe);
  268. }
  269. } /* timeouts_sched() */
  270. #ifndef TIMEOUT_DISABLE_INTERVALS
  271. static void timeouts_readd(struct timeouts *T, struct timeout *to) {
  272. to->expires += to->interval;
  273. if (to->expires <= T->curtime) {
  274. /* If we've missed the next firing of this timeout, reschedule
  275. * it to occur at the next multiple of its interval after
  276. * the last time that it fired.
  277. */
  278. timeout_t n = T->curtime - to->expires;
  279. timeout_t r = n % to->interval;
  280. to->expires = T->curtime + (to->interval - r);
  281. }
  282. timeouts_sched(T, to, to->expires);
  283. } /* timeouts_readd() */
  284. #endif
  285. TIMEOUT_PUBLIC void timeouts_add(struct timeouts *T, struct timeout *to, timeout_t timeout) {
  286. #ifndef TIMEOUT_DISABLE_INTERVALS
  287. if (to->flags & TIMEOUT_INT)
  288. to->interval = MAX(1, timeout);
  289. #endif
  290. if (to->flags & TIMEOUT_ABS)
  291. timeouts_sched(T, to, timeout);
  292. else
  293. timeouts_sched(T, to, T->curtime + timeout);
  294. } /* timeouts_add() */
  295. TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) {
  296. timeout_t elapsed = curtime - T->curtime;
  297. struct timeout_list todo;
  298. int wheel;
  299. TOR_TAILQ_INIT(&todo);
  300. /*
  301. * There's no avoiding looping over every wheel. It's best to keep
  302. * WHEEL_NUM smallish.
  303. */
  304. for (wheel = 0; wheel < WHEEL_NUM; wheel++) {
  305. wheel_t pending;
  306. /*
  307. * Calculate the slots expiring in this wheel
  308. *
  309. * If the elapsed time is greater than the maximum period of
  310. * the wheel, mark every position as expiring.
  311. *
  312. * Otherwise, to determine the expired slots fill in all the
  313. * bits between the last slot processed and the current
  314. * slot, inclusive of the last slot. We'll bitwise-AND this
  315. * with our pending set below.
  316. *
  317. * If a wheel rolls over, force a tick of the next higher
  318. * wheel.
  319. */
  320. if ((elapsed >> (wheel * WHEEL_BIT)) > WHEEL_MAX) {
  321. pending = (wheel_t)~WHEEL_C(0);
  322. } else {
  323. wheel_t _elapsed = WHEEL_MASK & (elapsed >> (wheel * WHEEL_BIT));
  324. int oslot, nslot;
  325. /*
  326. * TODO: It's likely that at least one of the
  327. * following three bit fill operations is redundant
  328. * or can be replaced with a simpler operation.
  329. */
  330. oslot = WHEEL_MASK & (T->curtime >> (wheel * WHEEL_BIT));
  331. pending = rotl(((UINT64_C(1) << _elapsed) - 1), oslot);
  332. nslot = WHEEL_MASK & (curtime >> (wheel * WHEEL_BIT));
  333. pending |= rotr(rotl(((WHEEL_C(1) << _elapsed) - 1), nslot), (int)_elapsed);
  334. pending |= WHEEL_C(1) << nslot;
  335. }
  336. while (pending & T->pending[wheel]) {
  337. /* ctz input cannot be zero: loop condition. */
  338. int slot = ctz(pending & T->pending[wheel]);
  339. TOR_TAILQ_CONCAT(&todo, &T->wheel[wheel][slot], tqe);
  340. T->pending[wheel] &= ~(UINT64_C(1) << slot);
  341. }
  342. if (!(0x1 & pending))
  343. break; /* break if we didn't wrap around end of wheel */
  344. /* if we're continuing, the next wheel must tick at least once */
  345. elapsed = MAX(elapsed, (WHEEL_LEN << (wheel * WHEEL_BIT)));
  346. }
  347. T->curtime = curtime;
  348. while (!TOR_TAILQ_EMPTY(&todo)) {
  349. struct timeout *to = TOR_TAILQ_FIRST(&todo);
  350. TOR_TAILQ_REMOVE(&todo, to, tqe);
  351. to->pending = NULL;
  352. timeouts_sched(T, to, to->expires);
  353. }
  354. return;
  355. } /* timeouts_update() */
  356. TIMEOUT_PUBLIC timeout_t timeouts_get_curtime(struct timeouts *T) {
  357. return T->curtime;
  358. } /* timeouts_get_curtime() */
  359. TIMEOUT_PUBLIC void timeouts_step(struct timeouts *T, reltime_t elapsed) {
  360. timeouts_update(T, T->curtime + elapsed);
  361. } /* timeouts_step() */
  362. TIMEOUT_PUBLIC bool timeouts_pending(struct timeouts *T) {
  363. wheel_t pending = 0;
  364. int wheel;
  365. for (wheel = 0; wheel < WHEEL_NUM; wheel++) {
  366. pending |= T->pending[wheel];
  367. }
  368. return !!pending;
  369. } /* timeouts_pending() */
  370. TIMEOUT_PUBLIC bool timeouts_expired(struct timeouts *T) {
  371. return !TOR_TAILQ_EMPTY(&T->expired);
  372. } /* timeouts_expired() */
  373. /*
  374. * Calculate the interval before needing to process any timeouts pending on
  375. * any wheel.
  376. *
  377. * (This is separated from the public API routine so we can evaluate our
  378. * wheel invariant assertions irrespective of the expired queue.)
  379. *
  380. * This might return a timeout value sooner than any installed timeout if
  381. * only higher-order wheels have timeouts pending. We can only know when to
  382. * process a wheel, not precisely when a timeout is scheduled. Our timeout
  383. * accuracy could be off by 2^(N*M)-1 units where N is the wheel number and
  384. * M is WHEEL_BIT. Only timeouts which have fallen through to wheel 0 can be
  385. * known exactly.
  386. *
  387. * We should never return a timeout larger than the lowest actual timeout.
  388. */
  389. static timeout_t timeouts_int(struct timeouts *T) {
  390. timeout_t timeout = ~TIMEOUT_C(0), _timeout;
  391. timeout_t relmask;
  392. int wheel, slot;
  393. relmask = 0;
  394. for (wheel = 0; wheel < WHEEL_NUM; wheel++) {
  395. if (T->pending[wheel]) {
  396. slot = WHEEL_MASK & (T->curtime >> (wheel * WHEEL_BIT));
  397. /* ctz input cannot be zero: T->pending[wheel] is
  398. * nonzero, so rotr() is nonzero. */
  399. _timeout = (ctz(rotr(T->pending[wheel], slot)) + !!wheel) << (wheel * WHEEL_BIT);
  400. /* +1 to higher order wheels as those timeouts are one rotation in the future (otherwise they'd be on a lower wheel or expired) */
  401. _timeout -= relmask & T->curtime;
  402. /* reduce by how much lower wheels have progressed */
  403. timeout = MIN(_timeout, timeout);
  404. }
  405. relmask <<= WHEEL_BIT;
  406. relmask |= WHEEL_MASK;
  407. }
  408. return timeout;
  409. } /* timeouts_int() */
  410. /*
  411. * Calculate the interval our caller can wait before needing to process
  412. * events.
  413. */
  414. TIMEOUT_PUBLIC timeout_t timeouts_timeout(struct timeouts *T) {
  415. if (!TOR_TAILQ_EMPTY(&T->expired))
  416. return 0;
  417. return timeouts_int(T);
  418. } /* timeouts_timeout() */
  419. TIMEOUT_PUBLIC struct timeout *timeouts_get(struct timeouts *T) {
  420. if (!TOR_TAILQ_EMPTY(&T->expired)) {
  421. struct timeout *to = TOR_TAILQ_FIRST(&T->expired);
  422. TOR_TAILQ_REMOVE(&T->expired, to, tqe);
  423. to->pending = NULL;
  424. TO_SET_TIMEOUTS(to, NULL);
  425. #ifndef TIMEOUT_DISABLE_INTERVALS
  426. if ((to->flags & TIMEOUT_INT) && to->interval > 0)
  427. timeouts_readd(T, to);
  428. #endif
  429. return to;
  430. } else {
  431. return 0;
  432. }
  433. } /* timeouts_get() */
  434. /*
  435. * Use dumb looping to locate the earliest timeout pending on the wheel so
  436. * our invariant assertions can check the result of our optimized code.
  437. */
  438. static struct timeout *timeouts_min(struct timeouts *T) {
  439. struct timeout *to, *min = NULL;
  440. unsigned i, j;
  441. for (i = 0; i < countof(T->wheel); i++) {
  442. for (j = 0; j < countof(T->wheel[i]); j++) {
  443. TOR_TAILQ_FOREACH(to, &T->wheel[i][j], tqe) {
  444. if (!min || to->expires < min->expires)
  445. min = to;
  446. }
  447. }
  448. }
  449. return min;
  450. } /* timeouts_min() */
  451. /*
  452. * Check some basic algorithm invariants. If these invariants fail then
  453. * something is definitely broken.
  454. */
  455. #define report(...) do { \
  456. if ((fp)) \
  457. fprintf(fp, __VA_ARGS__); \
  458. } while (0)
  459. #define check(expr, ...) do { \
  460. if (!(expr)) { \
  461. report(__VA_ARGS__); \
  462. return 0; \
  463. } \
  464. } while (0)
  465. TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *T, FILE *fp) {
  466. timeout_t timeout;
  467. struct timeout *to;
  468. if ((to = timeouts_min(T))) {
  469. check(to->expires > T->curtime, "missed timeout (expires:%" TIMEOUT_PRIu " <= curtime:%" TIMEOUT_PRIu ")\n", to->expires, T->curtime);
  470. timeout = timeouts_int(T);
  471. check(timeout <= to->expires - T->curtime, "wrong soft timeout (soft:%" TIMEOUT_PRIu " > hard:%" TIMEOUT_PRIu ") (expires:%" TIMEOUT_PRIu "; curtime:%" TIMEOUT_PRIu ")\n", timeout, (to->expires - T->curtime), to->expires, T->curtime);
  472. timeout = timeouts_timeout(T);
  473. check(timeout <= to->expires - T->curtime, "wrong soft timeout (soft:%" TIMEOUT_PRIu " > hard:%" TIMEOUT_PRIu ") (expires:%" TIMEOUT_PRIu "; curtime:%" TIMEOUT_PRIu ")\n", timeout, (to->expires - T->curtime), to->expires, T->curtime);
  474. } else {
  475. timeout = timeouts_timeout(T);
  476. if (!TOR_TAILQ_EMPTY(&T->expired))
  477. check(timeout == 0, "wrong soft timeout (soft:%" TIMEOUT_PRIu " != hard:%" TIMEOUT_PRIu ")\n", timeout, TIMEOUT_C(0));
  478. else
  479. check(timeout == ~TIMEOUT_C(0), "wrong soft timeout (soft:%" TIMEOUT_PRIu " != hard:%" TIMEOUT_PRIu ")\n", timeout, ~TIMEOUT_C(0));
  480. }
  481. return 1;
  482. } /* timeouts_check() */
  483. #define ENTER \
  484. do { \
  485. static const int pc0 = __LINE__; \
  486. switch (pc0 + it->pc) { \
  487. case __LINE__: (void)0
  488. #define SAVE_AND_DO(do_statement) \
  489. do { \
  490. it->pc = __LINE__ - pc0; \
  491. do_statement; \
  492. case __LINE__: (void)0; \
  493. } while (0)
  494. #define YIELD(rv) \
  495. SAVE_AND_DO(return (rv))
  496. #define LEAVE \
  497. SAVE_AND_DO(break); \
  498. } \
  499. } while (0)
  500. TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *T, struct timeouts_it *it) {
  501. struct timeout *to;
  502. ENTER;
  503. if (it->flags & TIMEOUTS_EXPIRED) {
  504. if (it->flags & TIMEOUTS_CLEAR) {
  505. while ((to = timeouts_get(T))) {
  506. YIELD(to);
  507. }
  508. } else {
  509. TOR_TAILQ_FOREACH_SAFE(to, &T->expired, tqe, it->to) {
  510. YIELD(to);
  511. }
  512. }
  513. }
  514. if (it->flags & TIMEOUTS_PENDING) {
  515. for (it->i = 0; it->i < countof(T->wheel); it->i++) {
  516. for (it->j = 0; it->j < countof(T->wheel[it->i]); it->j++) {
  517. TOR_TAILQ_FOREACH_SAFE(to, &T->wheel[it->i][it->j], tqe, it->to) {
  518. YIELD(to);
  519. }
  520. }
  521. }
  522. }
  523. LEAVE;
  524. return NULL;
  525. } /* timeouts_next */
  526. #undef LEAVE
  527. #undef YIELD
  528. #undef SAVE_AND_DO
  529. #undef ENTER
  530. /*
  531. * T I M E O U T R O U T I N E S
  532. *
  533. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  534. TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *to, int flags) {
  535. memset(to, 0, sizeof *to);
  536. to->flags = flags;
  537. return to;
  538. } /* timeout_init() */
  539. #ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
  540. TIMEOUT_PUBLIC bool timeout_pending(struct timeout *to) {
  541. return to->pending && to->pending != &to->timeouts->expired;
  542. } /* timeout_pending() */
  543. TIMEOUT_PUBLIC bool timeout_expired(struct timeout *to) {
  544. return to->pending && to->pending == &to->timeouts->expired;
  545. } /* timeout_expired() */
  546. TIMEOUT_PUBLIC void timeout_del(struct timeout *to) {
  547. timeouts_del(to->timeouts, to);
  548. } /* timeout_del() */
  549. #endif
  550. /*
  551. * V E R S I O N I N T E R F A C E S
  552. *
  553. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  554. TIMEOUT_PUBLIC int timeout_version(void) {
  555. return TIMEOUT_VERSION;
  556. } /* timeout_version() */
  557. TIMEOUT_PUBLIC const char *timeout_vendor(void) {
  558. return TIMEOUT_VENDOR;
  559. } /* timeout_version() */
  560. TIMEOUT_PUBLIC int timeout_v_rel(void) {
  561. return TIMEOUT_V_REL;
  562. } /* timeout_version() */
  563. TIMEOUT_PUBLIC int timeout_v_abi(void) {
  564. return TIMEOUT_V_ABI;
  565. } /* timeout_version() */
  566. TIMEOUT_PUBLIC int timeout_v_api(void) {
  567. return TIMEOUT_V_API;
  568. } /* timeout_version() */