timeout_ext 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }