7 #include "ext/timeouts/timeout.h"
9 #define THE_END_OF_TIME ((timeout_t)-1)
11 static int check_misc(void) {
12 if (TIMEOUT_VERSION
!= timeout_version())
14 if (TIMEOUT_V_REL
!= timeout_v_rel())
16 if (TIMEOUT_V_API
!= timeout_v_api())
18 if (TIMEOUT_V_ABI
!= timeout_v_abi())
20 if (strcmp(timeout_vendor(), TIMEOUT_VENDOR
))
25 static int check_open_close(timeout_t hz_set
, timeout_t hz_expect
) {
27 struct timeouts
*tos
= timeouts_open(hz_set
, &err
);
32 if (hz_expect
!= timeouts_hz(tos
))
39 static timeout_t
random_to(timeout_t min
, timeout_t max
)
43 /* Not actually all that random, but should exercise the code. */
44 timeout_t rand64
= random() * (timeout_t
)INT_MAX
+ random();
45 return min
+ (rand64
% (max
-min
));
48 /* configuration for check_randomized */
50 /* When creating timeouts, smallest possible delay */
51 timeout_t min_timeout
;
52 /* When creating timeouts, largest possible delay */
53 timeout_t max_timeout
;
54 /* First time to start the clock at. */
56 /* Do not advance the clock past this time. */
58 /* Number of timeouts to create and monitor. */
60 /* Advance the clock by no more than this each step. */
62 /* Use relative timers and stepping */
64 /* Every time the clock ticks, try removing this many timeouts at
67 /* When we're done, advance the clock to the end of time. */
71 static int check_randomized(const struct rand_cfg
*cfg
)
74 printf("Failure on line %d\n", __LINE__); \
80 struct timeout
*t
= calloc(cfg
->n_timeouts
, sizeof(struct timeout
));
81 timeout_t
*timeouts
= calloc(cfg
->n_timeouts
, sizeof(timeout_t
));
82 uint8_t *fired
= calloc(cfg
->n_timeouts
, sizeof(uint8_t));
83 uint8_t *found
= calloc(cfg
->n_timeouts
, sizeof(uint8_t));
84 uint8_t *deleted
= calloc(cfg
->n_timeouts
, sizeof(uint8_t));
85 struct timeouts
*tos
= timeouts_open(0, &err
);
86 timeout_t now
= cfg
->start_at
;
87 int n_added_pending
= 0, cnt_added_pending
= 0;
88 int n_added_expired
= 0, cnt_added_expired
= 0;
89 struct timeouts_it it_p
, it_e
, it_all
;
90 int p_done
= 0, e_done
= 0, all_done
= 0;
91 struct timeout
*to
= NULL
;
92 const int rel
= cfg
->relative
;
94 if (!t
|| !timeouts
|| !tos
|| !fired
|| !found
|| !deleted
)
96 timeouts_update(tos
, cfg
->start_at
);
98 for (i
= 0; i
< cfg
->n_timeouts
; ++i
) {
99 if (&t
[i
] != timeout_init(&t
[i
], rel
? 0 : TIMEOUT_ABS
))
101 if (timeout_pending(&t
[i
]))
103 if (timeout_expired(&t
[i
]))
106 timeouts
[i
] = random_to(cfg
->min_timeout
, cfg
->max_timeout
);
108 timeouts_add(tos
, &t
[i
], timeouts
[i
] - (rel
? now
: 0));
109 if (timeouts
[i
] <= cfg
->start_at
) {
110 if (timeout_pending(&t
[i
]))
112 if (! timeout_expired(&t
[i
]))
116 if (! timeout_pending(&t
[i
]))
118 if (timeout_expired(&t
[i
]))
124 if (!!n_added_pending
!= timeouts_pending(tos
))
126 if (!!n_added_expired
!= timeouts_expired(tos
))
129 /* Test foreach, interleaving a few iterators. */
130 TIMEOUTS_IT_INIT(&it_p
, TIMEOUTS_PENDING
);
131 TIMEOUTS_IT_INIT(&it_e
, TIMEOUTS_EXPIRED
);
132 TIMEOUTS_IT_INIT(&it_all
, TIMEOUTS_ALL
);
133 while (! (p_done
&& e_done
&& all_done
)) {
135 to
= timeouts_next(tos
, &it_p
);
145 to
= timeouts_next(tos
, &it_e
);
155 to
= timeouts_next(tos
, &it_all
);
165 for (i
= 0; i
< cfg
->n_timeouts
; ++i
) {
169 if (cnt_added_expired
!= n_added_expired
)
171 if (cnt_added_pending
!= n_added_pending
)
174 while (NULL
!= (to
= timeouts_get(tos
))) {
177 if (timeouts
[i
] > cfg
->start_at
)
178 FAIL(); /* shouldn't have happened yet */
180 --n_added_expired
; /* drop expired timeouts. */
184 if (n_added_expired
!= 0)
187 while (now
< cfg
->end_at
) {
188 int n_fired_this_time
= 0;
189 timeout_t first_at
= timeouts_timeout(tos
) + now
;
191 timeout_t oldtime
= now
;
192 timeout_t step
= random_to(1, cfg
->max_step
);
196 timeouts_step(tos
, step
);
198 timeouts_update(tos
, now
);
200 for (i
= 0; i
< cfg
->try_removing
; ++i
) {
201 int idx
= random() % cfg
->n_timeouts
;
203 timeout_del(&t
[idx
]);
208 another
= (timeouts_timeout(tos
) == 0);
210 while (NULL
!= (to
= timeouts_get(tos
))) {
212 FAIL(); /* Thought we saw the last one! */
215 if (timeouts
[i
] > now
)
216 FAIL(); /* shouldn't have happened yet */
217 if (timeouts
[i
] <= oldtime
)
218 FAIL(); /* should have happened already */
219 if (timeouts
[i
] < first_at
)
220 FAIL(); /* first_at should've been earlier */
223 another
= (timeouts_timeout(tos
) == 0);
225 if (n_fired_this_time
&& first_at
> now
)
226 FAIL(); /* first_at should've been earlier */
228 FAIL(); /* Huh? We think there are more? */
229 if (!timeouts_check(tos
, stderr
))
233 for (i
= 0; i
< cfg
->n_timeouts
; ++i
) {
235 FAIL(); /* Nothing fired twice. */
236 if (timeouts
[i
] <= now
) {
237 if (!(fired
[i
] || deleted
[i
]))
243 if (fired
[i
] && deleted
[i
])
245 if (cfg
->finalize
> 1) {
251 /* Now nothing more should fire between now and the end of time. */
253 timeouts_update(tos
, THE_END_OF_TIME
);
254 if (cfg
->finalize
> 1) {
255 if (timeouts_get(tos
))
257 TIMEOUTS_FOREACH(to
, tos
, TIMEOUTS_ALL
)
264 if (tos
) timeouts_close(tos
);
266 if (timeouts
) free(timeouts
);
267 if (fired
) free(fired
);
268 if (found
) free(found
);
269 if (deleted
) free(deleted
);
273 struct intervals_cfg
{
274 const timeout_t
*timeouts
;
282 check_intervals(struct intervals_cfg
*cfg
)
287 struct timeout
*t
= calloc(cfg
->n_timeouts
, sizeof(struct timeout
));
288 unsigned *fired
= calloc(cfg
->n_timeouts
, sizeof(unsigned));
289 struct timeouts
*tos
= timeouts_open(0, &err
);
291 timeout_t now
= cfg
->start_at
;
292 if (!t
|| !tos
|| !fired
)
295 timeouts_update(tos
, now
);
297 for (i
= 0; i
< cfg
->n_timeouts
; ++i
) {
298 if (&t
[i
] != timeout_init(&t
[i
], TIMEOUT_INT
))
300 if (timeout_pending(&t
[i
]))
302 if (timeout_expired(&t
[i
]))
305 timeouts_add(tos
, &t
[i
], cfg
->timeouts
[i
]);
306 if (! timeout_pending(&t
[i
]))
308 if (timeout_expired(&t
[i
]))
312 while (now
< cfg
->end_at
) {
313 timeout_t delay
= timeouts_timeout(tos
);
314 if (cfg
->skip
&& delay
< cfg
->skip
)
316 timeouts_step(tos
, delay
);
319 while (NULL
!= (to
= timeouts_get(tos
))) {
323 if (0 != (to
->expires
- cfg
->start_at
) % cfg
->timeouts
[i
])
325 if (to
->expires
<= now
)
327 if (to
->expires
> now
+ cfg
->timeouts
[i
])
330 if (!timeouts_check(tos
, stderr
))
334 timeout_t duration
= now
- cfg
->start_at
;
335 for (i
= 0; i
< cfg
->n_timeouts
; ++i
) {
337 if (fired
[i
] > duration
/ cfg
->timeouts
[i
])
340 if (fired
[i
] != duration
/ cfg
->timeouts
[i
])
343 if (!timeout_pending(&t
[i
]))
350 if (fired
) free(fired
);
356 main(int argc
, char **argv
)
360 #define DO(fn) do { \
361 printf("."); fflush(stdout); \
364 printf("%s failed\n", #fn); \
368 #define DO_N(n, fn) do { \
369 for (j = 0; j < (n); ++j) { \
375 DO(check_open_close(1000, 1000));
376 DO(check_open_close(0, TIMEOUT_mHZ
));
378 struct rand_cfg cfg1
= {
389 DO_N(300,check_randomized(&cfg1
));
391 struct rand_cfg cfg2
= {
402 DO_N(300,check_randomized(&cfg2
));
404 struct rand_cfg cfg2b
= {
415 DO_N(300,check_randomized(&cfg2b
));
417 struct rand_cfg cfg2c
= {
428 DO_N(300,check_randomized(&cfg2c
));
430 struct rand_cfg cfg3
= {
432 .max_timeout
= ((uint64_t)1) << 50,
434 .end_at
= ((uint64_t)1) << 49,
441 DO_N(10,check_randomized(&cfg3
));
443 struct rand_cfg cfg3b
= {
444 .min_timeout
= ((uint64_t)1) << 50,
445 .max_timeout
= ((uint64_t)1) << 52,
447 .end_at
= ((uint64_t)1) << 53,
449 .max_step
= ((uint64_t)1)<<48,
454 DO_N(10,check_randomized(&cfg3b
));
456 struct rand_cfg cfg4
= {
458 .max_timeout
= ((uint64_t)1) << 30,
460 .end_at
= ((uint64_t)1) << 26,
467 DO_N(10,check_randomized(&cfg4
));
469 const timeout_t primes
[] = {
470 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,
471 59,61,67,71,73,79,83,89,97
473 const timeout_t factors_of_1337
[] = {
476 const timeout_t multiples_of_five
[] = {
477 5, 10, 15, 20, 25, 30, 35, 40, 45, 50
480 struct intervals_cfg icfg1
= {
482 .n_timeouts
= sizeof(primes
)/sizeof(timeout_t
),
487 DO(check_intervals(&icfg1
));
489 struct intervals_cfg icfg2
= {
490 .timeouts
= factors_of_1337
,
491 .n_timeouts
= sizeof(factors_of_1337
)/sizeof(timeout_t
),
496 DO(check_intervals(&icfg2
));
498 struct intervals_cfg icfg3
= {
499 .timeouts
= multiples_of_five
,
500 .n_timeouts
= sizeof(multiples_of_five
)/sizeof(timeout_t
),
505 DO(check_intervals(&icfg3
));
507 struct intervals_cfg icfg4
= {
509 .n_timeouts
= sizeof(primes
)/sizeof(timeout_t
),
514 DO(check_intervals(&icfg4
));
528 * Investigate whether any untaken branches are possible.