timeout_ext 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/COPYING +510 -0
  4. data/MANIFEST +51 -0
  5. data/README +15 -0
  6. data/Rakefile +28 -0
  7. data/ext/timeout_ext/.gitignore +3 -0
  8. data/ext/timeout_ext/ccan-bits.c +7 -0
  9. data/ext/timeout_ext/ccan/array_size/LICENSE +28 -0
  10. data/ext/timeout_ext/ccan/array_size/_info +46 -0
  11. data/ext/timeout_ext/ccan/array_size/array_size.h +26 -0
  12. data/ext/timeout_ext/ccan/build_assert/LICENSE +28 -0
  13. data/ext/timeout_ext/ccan/build_assert/_info +49 -0
  14. data/ext/timeout_ext/ccan/build_assert/build_assert.h +40 -0
  15. data/ext/timeout_ext/ccan/check_type/LICENSE +28 -0
  16. data/ext/timeout_ext/ccan/check_type/_info +33 -0
  17. data/ext/timeout_ext/ccan/check_type/check_type.h +64 -0
  18. data/ext/timeout_ext/ccan/compiler/LICENSE +28 -0
  19. data/ext/timeout_ext/ccan/compiler/_info +64 -0
  20. data/ext/timeout_ext/ccan/compiler/compiler.h +231 -0
  21. data/ext/timeout_ext/ccan/container_of/LICENSE +28 -0
  22. data/ext/timeout_ext/ccan/container_of/_info +65 -0
  23. data/ext/timeout_ext/ccan/container_of/container_of.h +145 -0
  24. data/ext/timeout_ext/ccan/ilog/LICENSE +28 -0
  25. data/ext/timeout_ext/ccan/ilog/_info +50 -0
  26. data/ext/timeout_ext/ccan/ilog/ilog.c +141 -0
  27. data/ext/timeout_ext/ccan/ilog/ilog.h +151 -0
  28. data/ext/timeout_ext/ccan/list/LICENSE +17 -0
  29. data/ext/timeout_ext/ccan/list/_info +72 -0
  30. data/ext/timeout_ext/ccan/list/list.h +842 -0
  31. data/ext/timeout_ext/ccan/str/LICENSE +28 -0
  32. data/ext/timeout_ext/ccan/str/_info +52 -0
  33. data/ext/timeout_ext/ccan/str/str.h +228 -0
  34. data/ext/timeout_ext/ccan/str/str_debug.h +30 -0
  35. data/ext/timeout_ext/ccan/time/LICENSE +17 -0
  36. data/ext/timeout_ext/ccan/time/_info +57 -0
  37. data/ext/timeout_ext/ccan/time/time.c +138 -0
  38. data/ext/timeout_ext/ccan/time/time.h +753 -0
  39. data/ext/timeout_ext/ccan/timer/LICENSE +510 -0
  40. data/ext/timeout_ext/ccan/timer/_info +79 -0
  41. data/ext/timeout_ext/ccan/timer/design.txt +76 -0
  42. data/ext/timeout_ext/ccan/timer/timer.c +524 -0
  43. data/ext/timeout_ext/ccan/timer/timer.h +211 -0
  44. data/ext/timeout_ext/depend +17 -0
  45. data/ext/timeout_ext/extconf.rb +50 -0
  46. data/ext/timeout_ext/licenses/BSD-MIT +17 -0
  47. data/ext/timeout_ext/licenses/CC0 +28 -0
  48. data/ext/timeout_ext/licenses/LGPL-2.1 +510 -0
  49. data/ext/timeout_ext/missing/stdbool/stdbool.h +20 -0
  50. data/ext/timeout_ext/timeout_ext.c +114 -0
  51. data/test/test_timeout_ext.rb +44 -0
  52. data/timeout_ext.gemspec +30 -0
  53. metadata +126 -0
@@ -0,0 +1,79 @@
1
+ #include "config.h"
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+
5
+ /**
6
+ * timer - efficient implementation of rarely-expiring timers.
7
+ *
8
+ * This is a lazy implementation of timers: you can add and delete timers
9
+ * very quickly, and they are only sorted as their expiry approaches.
10
+ *
11
+ * This is a common case for timeouts, which must often be set, but
12
+ * rarely expire.
13
+ *
14
+ * Example:
15
+ * // Silly example which outputs strings until timers expire.
16
+ * #include <ccan/timer/timer.h>
17
+ * #include <ccan/time/time.h>
18
+ * #include <stdlib.h>
19
+ * #include <stdio.h>
20
+ *
21
+ * struct timed_string {
22
+ * struct list_node node;
23
+ * struct timer timer;
24
+ * const char *string;
25
+ * };
26
+ *
27
+ * int main(int argc, char *argv[])
28
+ * {
29
+ * struct timers timers;
30
+ * struct list_head strings;
31
+ * struct timer *t;
32
+ * struct timed_string *s;
33
+ *
34
+ * (void)argc;
35
+ * timers_init(&timers, time_mono());
36
+ * list_head_init(&strings);
37
+ *
38
+ * while (argv[1]) {
39
+ * s = malloc(sizeof(*s));
40
+ * s->string = argv[1];
41
+ * timer_addrel(&timers, &s->timer,
42
+ * time_from_msec(atol(argv[2])));
43
+ * list_add_tail(&strings, &s->node);
44
+ * argv += 2;
45
+ * }
46
+ *
47
+ * while (!list_empty(&strings)) {
48
+ * struct timemono now = time_mono();
49
+ * list_for_each(&strings, s, node)
50
+ * printf("%s", s->string);
51
+ * while ((t = timers_expire(&timers, now)) != NULL) {
52
+ * s = container_of(t, struct timed_string, timer);
53
+ * list_del_from(&strings, &s->node);
54
+ * free(s);
55
+ * }
56
+ * }
57
+ *
58
+ * exit(0);
59
+ * }
60
+ *
61
+ * License: LGPL (v2.1 or any later version)
62
+ * Author: Rusty Russell <rusty@rustcorp.com.au>
63
+ */
64
+ int main(int argc, char *argv[])
65
+ {
66
+ /* Expect exactly one argument */
67
+ if (argc != 2)
68
+ return 1;
69
+
70
+ if (strcmp(argv[1], "depends") == 0) {
71
+ printf("ccan/array_size\n");
72
+ printf("ccan/ilog\n");
73
+ printf("ccan/list\n");
74
+ printf("ccan/time\n");
75
+ return 0;
76
+ }
77
+
78
+ return 1;
79
+ }
@@ -0,0 +1,76 @@
1
+ Cascading timer design.
2
+
3
+ Inspired by the Linux kernel approach, documented roughly at:
4
+ https://lwn.net/Articles/152436/
5
+
6
+ For easy description, we use whole seconds and powers of 10: in the
7
+ implementation, we use powers of 2 (eg. 256 entries) and smaller
8
+ granularities.
9
+
10
+ We start with a simple data structure:
11
+
12
+ struct timer_level {
13
+ struct timer_level *next;
14
+
15
+ /* Ten buckets: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] */
16
+ struct list_head bucket[10];
17
+ };
18
+
19
+ struct timers {
20
+ /* We can never have a timer before this, aka "now". */
21
+ time_t offset;
22
+
23
+ struct timer_level *level;
24
+
25
+ /* Anything too far in the future. */
26
+ struct list_head far;
27
+ }
28
+
29
+ The first level of timers holds anything which will happen in the next
30
+ 10 seconds. The next level holds things which will happen in the next
31
+ 100 seconds. And so on.
32
+
33
+ When we want to add a new timer into the structure, we need to figure
34
+ out first what level it goes into, and second, which bucket. Say our
35
+ offset is 500,000,001 (about Tue Nov 5, 1985 in Unix time). And our
36
+ timer is set to go off in 5 seconds, ie. 500,000,006.
37
+
38
+ The level is easy: the difference between the timer and the offset is
39
+ 5, and that's less than 10, so it's in the first level. The position,
40
+ however, depends on the absolute time, in this case the last digit 6,
41
+ so it's in bucket 6.
42
+
43
+ Adding a timer at 500,000,123? The difference is > 100 and < 1000, so
44
+ it's in the third level. The bucket is 1. If there's no third level,
45
+ we just add it to the 'far' list for stuff which is in the far future.
46
+
47
+ Deleting a timer is as simple as removing it; there is no external
48
+ bookkeeping in this scheme. This matters, since timers used for
49
+ timeouts are almost always deleted before they expire.
50
+
51
+ Now, when a second passes, we need to know if there are any timers
52
+ which are due. We increment the offset to 500,000,002, and look in
53
+ the first level, bucket 2 for any timers, so lookup is simple.
54
+
55
+ We do this eight more times, and we increment the offset to
56
+ 500,000,010. We've swept around back to bucket 0, though it may not
57
+ be empty if we added more timers as we were going.
58
+
59
+ But we need to look into the next level since a timer at 500,000,010
60
+ added when the offset was 500,000,000 would have gone up there. We
61
+ empty bucket 1 (due to the '1' in 500,000,010) into these buckets,
62
+ which will contain timers between 500,000,010 and 500,000,019, which
63
+ all now are less than 10 seconds away, so belong in the bottom level.
64
+
65
+ Similarly, at 500,000,020 we will empty bucket 1 of the second level
66
+ into the first level. And at 500,000,100 we will empty bucket 1 of
67
+ the third level into the second level then bucket 0 of the second
68
+ level into the first level. We do it in this order, since emptying
69
+ bucket 1 on the third level (500,000,100 - 500,000,199) may put more
70
+ entries (500,000,100 - 500,000,109) into bucket 0 on the second level.
71
+
72
+ When we get to 500,001,000 we should empty the fourth level. If there
73
+ is no fourth level, that's when we sort through the 'far' list and
74
+ empty any which are less than 500,002,000. If there are many entries
75
+ in the far list, we should add more levels to reduce the number, or at
76
+ least the frequency we have to check it.
@@ -0,0 +1,524 @@
1
+ /* LGPL (v2.1 or any later version) - see LICENSE file for details */
2
+ #include <ccan/timer/timer.h>
3
+ #include <ccan/array_size/array_size.h>
4
+ #include <ccan/ilog/ilog.h>
5
+ #include <stdlib.h>
6
+ #include <stdio.h>
7
+
8
+ #define PER_LEVEL (1ULL << TIMER_LEVEL_BITS)
9
+
10
+ struct timer_level {
11
+ struct list_head list[PER_LEVEL];
12
+ };
13
+
14
+ static uint64_t time_to_grains(struct timemono t)
15
+ {
16
+ return t.ts.tv_sec * ((uint64_t)1000000000 / TIMER_GRANULARITY)
17
+ + (t.ts.tv_nsec / TIMER_GRANULARITY);
18
+ }
19
+
20
+ static struct timemono grains_to_time(uint64_t grains)
21
+ {
22
+ struct timemono t;
23
+
24
+ t.ts.tv_sec = grains / (1000000000 / TIMER_GRANULARITY);
25
+ t.ts.tv_nsec = (grains % (1000000000 / TIMER_GRANULARITY))
26
+ * TIMER_GRANULARITY;
27
+ return t;
28
+ }
29
+
30
+ void timers_init(struct timers *timers, struct timemono start)
31
+ {
32
+ unsigned int i;
33
+
34
+ list_head_init(&timers->far);
35
+ timers->base = time_to_grains(start);
36
+ timers->first = -1ULL;
37
+ memset(timers->firsts, 0xFF, sizeof(timers->firsts));
38
+ for (i = 0; i < ARRAY_SIZE(timers->level); i++)
39
+ timers->level[i] = NULL;
40
+ }
41
+
42
+ static unsigned int level_of(const struct timers *timers, uint64_t time)
43
+ {
44
+ uint64_t diff;
45
+
46
+ /* Level depends how far away it is. */
47
+ diff = time - timers->base;
48
+ return ilog64(diff / 2) / TIMER_LEVEL_BITS;
49
+ }
50
+
51
+ static void timer_add_raw(struct timers *timers, struct timer *t)
52
+ {
53
+ struct list_head *l;
54
+ unsigned int level = level_of(timers, t->time);
55
+ uint64_t *first;
56
+
57
+ if (!timers->level[level]) {
58
+ l = &timers->far;
59
+ first = &timers->firsts[ARRAY_SIZE(timers->level)];
60
+ } else {
61
+ int off = (t->time >> (level*TIMER_LEVEL_BITS)) & (PER_LEVEL-1);
62
+ l = &timers->level[level]->list[off];
63
+ first = &timers->firsts[level];
64
+ }
65
+
66
+ list_add_tail(l, &t->list);
67
+ if (t->time < *first)
68
+ *first = t->time;
69
+ }
70
+
71
+ void timer_init(struct timer *t)
72
+ {
73
+ list_node_init(&t->list);
74
+ }
75
+
76
+ static bool list_node_initted(const struct list_node *n)
77
+ {
78
+ return n->prev == n;
79
+ }
80
+
81
+ void timer_addrel(struct timers *timers, struct timer *t, struct timerel rel)
82
+ {
83
+ assert(list_node_initted(&t->list));
84
+
85
+ t->time = time_to_grains(timemono_add(time_mono(), rel));
86
+
87
+ #if TIME_HAVE_MONOTONIC
88
+ assert(t->time >= timers->base);
89
+ #else
90
+ /* Added in the past? Treat it as imminent. */
91
+ if (t->time < timers->base)
92
+ t->time = timers->base;
93
+ #endif
94
+ if (t->time < timers->first)
95
+ timers->first = t->time;
96
+
97
+ timer_add_raw(timers, t);
98
+ }
99
+
100
+ void timer_addmono(struct timers *timers, struct timer *t, struct timemono when)
101
+ {
102
+ assert(list_node_initted(&t->list));
103
+
104
+ t->time = time_to_grains(when);
105
+
106
+ /* Added in the past? Treat it as imminent. */
107
+ if (t->time < timers->base)
108
+ t->time = timers->base;
109
+ if (t->time < timers->first)
110
+ timers->first = t->time;
111
+
112
+ timer_add_raw(timers, t);
113
+ }
114
+
115
+ /* FIXME: inline */
116
+ void timer_del(struct timers *timers UNNEEDED, struct timer *t)
117
+ {
118
+ list_del_init(&t->list);
119
+ }
120
+
121
+ static void timers_far_get(struct timers *timers,
122
+ struct list_head *list,
123
+ uint64_t when)
124
+ {
125
+ struct timer *i, *next;
126
+
127
+ list_for_each_safe(&timers->far, i, next, list) {
128
+ if (i->time <= when) {
129
+ list_del_from(&timers->far, &i->list);
130
+ list_add_tail(list, &i->list);
131
+ }
132
+ }
133
+ }
134
+
135
+ static void add_level(struct timers *timers, unsigned int level)
136
+ {
137
+ struct timer_level *l;
138
+ struct timer *t;
139
+ unsigned int i;
140
+ struct list_head from_far;
141
+
142
+ l = malloc(sizeof(*l));
143
+ if (!l)
144
+ return;
145
+
146
+ for (i = 0; i < ARRAY_SIZE(l->list); i++)
147
+ list_head_init(&l->list[i]);
148
+ timers->level[level] = l;
149
+
150
+ list_head_init(&from_far);
151
+ timers_far_get(timers, &from_far,
152
+ timers->base + (1ULL << ((level+1)*TIMER_LEVEL_BITS)) - 1);
153
+
154
+ while ((t = list_pop(&from_far, struct timer, list)) != NULL)
155
+ timer_add_raw(timers, t);
156
+ }
157
+
158
+ /* We don't need to search past the first at level 0, since the
159
+ * bucket range is 1; they're all the same. */
160
+ static const struct timer *find_first(const struct list_head *list,
161
+ unsigned int level,
162
+ const struct timer *prev)
163
+ {
164
+ struct timer *t;
165
+
166
+ list_for_each(list, t, list) {
167
+ if (!prev || t->time < prev->time)
168
+ prev = t;
169
+ if (level == 0)
170
+ break;
171
+ }
172
+ return prev;
173
+ }
174
+
175
+ /* Update level's first watermark, and return overall first. */
176
+ static const struct timer *first_for_level(struct timers *timers,
177
+ size_t level,
178
+ const struct timer *level_first,
179
+ const struct timer *first)
180
+ {
181
+ if (level_first) {
182
+ timers->firsts[level] = level_first->time;
183
+ if (!first || level_first->time < first->time)
184
+ first = level_first;
185
+ } else {
186
+ timers->firsts[level] = -1ULL;
187
+ }
188
+ return first;
189
+ }
190
+
191
+ static bool level_may_beat(const struct timers *timers, size_t level,
192
+ const struct timer *first)
193
+ {
194
+ return !first || timers->firsts[level] < first->time;
195
+ }
196
+
197
+ /* FIXME: Suboptimal */
198
+ static const struct timer *brute_force_first(struct timers *timers)
199
+ {
200
+ unsigned int l, i;
201
+ const struct timer *found = NULL;
202
+
203
+ for (l = 0; l < ARRAY_SIZE(timers->level) && timers->level[l]; l++) {
204
+ const struct timer *t = NULL;
205
+
206
+ /* Do we know they don't have a better one? */
207
+ if (!level_may_beat(timers, l, found))
208
+ continue;
209
+
210
+ /* Find first timer on this level. */
211
+ for (i = 0; i < PER_LEVEL; i++)
212
+ t = find_first(&timers->level[l]->list[i], l, t);
213
+
214
+ found = first_for_level(timers, l, t, found);
215
+ }
216
+
217
+ /* Check (and update) far list if there's a chance. */
218
+ l = ARRAY_SIZE(timers->level);
219
+ if (level_may_beat(timers, l, found)) {
220
+ const struct timer *t = find_first(&timers->far, l, NULL);
221
+ found = first_for_level(timers, l, t, found);
222
+ }
223
+
224
+ return found;
225
+ }
226
+
227
+ static const struct timer *get_first(struct timers *timers)
228
+ {
229
+ /* We can have just far timers, for example. */
230
+ if (timers->level[0]) {
231
+ /* First search rest of lower buckets; we've already spilled
232
+ * so if we find one there we don't need to search further. */
233
+ unsigned int i, off = timers->base % PER_LEVEL;
234
+
235
+ for (i = off; i < PER_LEVEL; i++) {
236
+ struct list_head *h = &timers->level[0]->list[i];
237
+ if (!list_empty(h))
238
+ return find_first(h, 0, NULL);
239
+ }
240
+ }
241
+
242
+ /* From here on, we're searching non-normalized parts of the
243
+ * data structure, which is much subtler.
244
+ *
245
+ * So we brute force. */
246
+ return brute_force_first(timers);
247
+ }
248
+
249
+ static bool update_first(struct timers *timers)
250
+ {
251
+ const struct timer *found = get_first(timers);
252
+
253
+ if (!found) {
254
+ timers->first = -1ULL;
255
+ return false;
256
+ }
257
+
258
+ timers->first = found->time;
259
+ return true;
260
+ }
261
+
262
+ bool timer_earliest(struct timers *timers, struct timemono *first)
263
+ {
264
+ if (!update_first(timers))
265
+ return false;
266
+
267
+ *first = grains_to_time(timers->first);
268
+ return true;
269
+ }
270
+
271
+ /* Assume no timers before 'time', cascade down and update base time. */
272
+ static void timer_fast_forward(struct timers *timers, uint64_t time)
273
+ {
274
+ unsigned int level, changed;
275
+ int need_level = -1;
276
+ struct list_head list;
277
+ struct timer *i;
278
+
279
+ /* How many bits changed between base and time?
280
+ * Each time we wrap, we need to empty buckets from above. */
281
+ if (time == timers->base)
282
+ return;
283
+
284
+ changed = ilog64_nz(time ^ timers->base);
285
+ level = (changed - 1) / TIMER_LEVEL_BITS;
286
+
287
+ /* Buckets always empty downwards, so we could cascade manually,
288
+ * but it's rarely very many so we just remove and re-add */
289
+ list_head_init(&list);
290
+
291
+ do {
292
+ if (!timers->level[level]) {
293
+ /* We need any which belong on this level. */
294
+ timers_far_get(timers, &list,
295
+ timers->base
296
+ + (1ULL << ((level+1)*TIMER_LEVEL_BITS))-1);
297
+ need_level = level;
298
+ } else {
299
+ unsigned src;
300
+
301
+ /* Get all timers from this bucket. */
302
+ src = (time >> (level * TIMER_LEVEL_BITS)) % PER_LEVEL;
303
+ list_append_list(&list,
304
+ &timers->level[level]->list[src]);
305
+ }
306
+ } while (level--);
307
+
308
+ /* Did we hit the last level? If so, add. */
309
+ if (need_level != -1)
310
+ add_level(timers, need_level);
311
+
312
+ /* Fast-forward the time, and re-add everyone. */
313
+ timers->base = time;
314
+ while ((i = list_pop(&list, struct timer, list)) != NULL)
315
+ timer_add_raw(timers, i);
316
+ }
317
+
318
+ /* Returns an expired timer. */
319
+ struct timer *timers_expire(struct timers *timers, struct timemono expire)
320
+ {
321
+ uint64_t now = time_to_grains(expire);
322
+ unsigned int off;
323
+ struct timer *t;
324
+
325
+ assert(now >= timers->base);
326
+
327
+ if (!timers->level[0]) {
328
+ if (list_empty(&timers->far))
329
+ return NULL;
330
+ add_level(timers, 0);
331
+ }
332
+
333
+ do {
334
+ if (timers->first > now) {
335
+ timer_fast_forward(timers, now);
336
+ return NULL;
337
+ }
338
+
339
+ timer_fast_forward(timers, timers->first);
340
+ off = timers->base % PER_LEVEL;
341
+
342
+ /* This *may* be NULL, if we deleted the first timer */
343
+ t = list_pop(&timers->level[0]->list[off], struct timer, list);
344
+ if (t)
345
+ list_node_init(&t->list);
346
+ } while (!t && update_first(timers));
347
+
348
+ return t;
349
+ }
350
+
351
+ static bool timer_list_check(const struct list_head *l,
352
+ uint64_t min, uint64_t max, uint64_t first,
353
+ const char *abortstr)
354
+ {
355
+ const struct timer *t;
356
+
357
+ if (!list_check(l, abortstr))
358
+ return false;
359
+
360
+ list_for_each(l, t, list) {
361
+ if (t->time < min || t->time > max) {
362
+ if (abortstr) {
363
+ fprintf(stderr,
364
+ "%s: timer %p %llu not %llu-%llu\n",
365
+ abortstr, t, (long long)t->time,
366
+ (long long)min, (long long)max);
367
+ abort();
368
+ }
369
+ return false;
370
+ }
371
+ if (t->time < first) {
372
+ if (abortstr) {
373
+ fprintf(stderr,
374
+ "%s: timer %p %llu < minimum %llu\n",
375
+ abortstr, t, (long long)t->time,
376
+ (long long)first);
377
+ abort();
378
+ }
379
+ return false;
380
+ }
381
+ }
382
+ return true;
383
+ }
384
+
385
+ struct timers *timers_check(const struct timers *timers, const char *abortstr)
386
+ {
387
+ unsigned int l, i, off;
388
+ uint64_t base;
389
+
390
+ l = 0;
391
+ if (!timers->level[0])
392
+ goto past_levels;
393
+
394
+ /* First level is simple. */
395
+ off = timers->base % PER_LEVEL;
396
+ for (i = 0; i < PER_LEVEL; i++) {
397
+ struct list_head *h;
398
+
399
+ h = &timers->level[l]->list[(i+off) % PER_LEVEL];
400
+ if (!timer_list_check(h, timers->base + i, timers->base + i,
401
+ timers->firsts[l], abortstr))
402
+ return NULL;
403
+ }
404
+
405
+ /* For other levels, "current" bucket has been emptied, and may contain
406
+ * entries for the current + level_size bucket. */
407
+ for (l = 1; l < ARRAY_SIZE(timers->level) && timers->level[l]; l++) {
408
+ uint64_t per_bucket = 1ULL << (TIMER_LEVEL_BITS * l);
409
+
410
+ off = ((timers->base >> (l*TIMER_LEVEL_BITS)) % PER_LEVEL);
411
+ /* We start at *next* bucket. */
412
+ base = (timers->base & ~(per_bucket - 1)) + per_bucket;
413
+
414
+ for (i = 1; i <= PER_LEVEL; i++) {
415
+ struct list_head *h;
416
+
417
+ h = &timers->level[l]->list[(i+off) % PER_LEVEL];
418
+ if (!timer_list_check(h, base, base + per_bucket - 1,
419
+ timers->firsts[l], abortstr))
420
+ return NULL;
421
+ base += per_bucket;
422
+ }
423
+ }
424
+
425
+ past_levels:
426
+ base = (timers->base & ~((1ULL << (TIMER_LEVEL_BITS * l)) - 1))
427
+ + (1ULL << (TIMER_LEVEL_BITS * l)) - 1;
428
+ if (!timer_list_check(&timers->far, base, -1ULL,
429
+ timers->firsts[ARRAY_SIZE(timers->level)],
430
+ abortstr))
431
+ return NULL;
432
+
433
+ return (struct timers *)timers;
434
+ }
435
+
436
+ #ifdef CCAN_TIMER_DEBUG
437
+ static void dump_bucket_stats(FILE *fp, const struct list_head *h)
438
+ {
439
+ unsigned long long min, max, num;
440
+ struct timer *t;
441
+
442
+ if (list_empty(h)) {
443
+ printf("\n");
444
+ return;
445
+ }
446
+
447
+ min = -1ULL;
448
+ max = 0;
449
+ num = 0;
450
+ list_for_each(h, t, list) {
451
+ if (t->time < min)
452
+ min = t->time;
453
+ if (t->time > max)
454
+ max = t->time;
455
+ num++;
456
+ }
457
+ fprintf(fp, " %llu (%llu-%llu)\n",
458
+ num, min, max);
459
+ }
460
+
461
+ void timers_dump(const struct timers *timers, FILE *fp)
462
+ {
463
+ unsigned int l, i, off;
464
+ unsigned long long base;
465
+
466
+ if (!fp)
467
+ fp = stderr;
468
+
469
+ fprintf(fp, "Base: %llu\n", (unsigned long long)timers->base);
470
+
471
+ if (!timers->level[0])
472
+ goto past_levels;
473
+
474
+ fprintf(fp, "Level 0:\n");
475
+
476
+ /* First level is simple. */
477
+ off = timers->base % PER_LEVEL;
478
+ for (i = 0; i < PER_LEVEL; i++) {
479
+ const struct list_head *h;
480
+
481
+ fprintf(fp, " Bucket %llu (%lu):",
482
+ (i+off) % PER_LEVEL, timers->base + i);
483
+ h = &timers->level[0]->list[(i+off) % PER_LEVEL];
484
+ dump_bucket_stats(fp, h);
485
+ }
486
+
487
+ /* For other levels, "current" bucket has been emptied, and may contain
488
+ * entries for the current + level_size bucket. */
489
+ for (l = 1; l < ARRAY_SIZE(timers->level) && timers->level[l]; l++) {
490
+ uint64_t per_bucket = 1ULL << (TIMER_LEVEL_BITS * l);
491
+
492
+ off = ((timers->base >> (l*TIMER_LEVEL_BITS)) % PER_LEVEL);
493
+ /* We start at *next* bucket. */
494
+ base = (timers->base & ~(per_bucket - 1)) + per_bucket;
495
+
496
+ fprintf(fp, "Level %u:\n", l);
497
+ for (i = 1; i <= PER_LEVEL; i++) {
498
+ const struct list_head *h;
499
+
500
+ fprintf(fp, " Bucket %llu (%llu - %llu):",
501
+ (i+off) % PER_LEVEL,
502
+ base, base + per_bucket - 1);
503
+
504
+ h = &timers->level[l]->list[(i+off) % PER_LEVEL];
505
+ dump_bucket_stats(fp, h);
506
+ base += per_bucket;
507
+ }
508
+ }
509
+
510
+ past_levels:
511
+ if (!list_empty(&timers->far)) {
512
+ fprintf(fp, "Far timers:");
513
+ dump_bucket_stats(fp, &timers->far);
514
+ }
515
+ }
516
+ #endif
517
+
518
+ void timers_cleanup(struct timers *timers)
519
+ {
520
+ unsigned int l;
521
+
522
+ for (l = 0; l < ARRAY_SIZE(timers->level); l++)
523
+ free(timers->level[l]);
524
+ }