timeout.c 20 KB

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