1 /* $NetBSD: t_timers.c,v 1.6 2014/12/10 04:37:54 christos Exp $ */
2
3 /*
4 * Copyright (C) 2004, 2007-2009, 2011, 2013 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001 Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* Id: t_timers.c,v 1.33 2011/03/14 14:13:10 fdupont Exp */
21
22 #include <config.h>
23
24 #include <stdlib.h>
25
26 #include <isc/condition.h>
27 #include <isc/mem.h>
28 #include <isc/platform.h>
29 #include <isc/task.h>
30 #include <isc/time.h>
31 #include <isc/timer.h>
32 #include <isc/util.h>
33
34 #include <tests/t_api.h>
35
36 #ifdef ISC_PLATFORM_USETHREADS
37 isc_boolean_t threaded = ISC_TRUE;
38 #else
39 isc_boolean_t threaded = ISC_FALSE;
40 #endif
41
42 #define Tx_FUDGE_SECONDS 0 /* in absence of clock_getres() */
43 #define Tx_FUDGE_NANOSECONDS 500000000 /* in absence of clock_getres() */
44
45 static isc_time_t Tx_endtime;
46 static isc_time_t Tx_lasttime;
47 static int Tx_eventcnt;
48 static int Tx_nevents;
49 static isc_mutex_t Tx_mx;
50 static isc_condition_t Tx_cv;
51 static int Tx_nfails;
52 static int Tx_nprobs;
53 static isc_timer_t *Tx_timer;
54 static int Tx_seconds;
55 static int Tx_nanoseconds;
56
57 static void
require_threads(void)58 require_threads(void) {
59 t_info("This test requires threads\n");
60 t_result(T_THREADONLY);
61 return;
62 }
63
64 static void
tx_sde(isc_task_t * task,isc_event_t * event)65 tx_sde(isc_task_t *task, isc_event_t *event) {
66 isc_result_t isc_result;
67
68 UNUSED(task);
69 UNUSED(event);
70
71 /*
72 * Signal shutdown processing complete.
73 */
74 isc_result = isc_mutex_lock(&Tx_mx);
75 if (isc_result != ISC_R_SUCCESS) {
76 t_info("isc_mutex_lock failed %s\n",
77 isc_result_totext(isc_result));
78 ++Tx_nprobs;
79 }
80
81 isc_result = isc_condition_signal(&Tx_cv);
82 if (isc_result != ISC_R_SUCCESS) {
83 t_info("isc_condition_signal failed %s\n",
84 isc_result_totext(isc_result));
85 ++Tx_nprobs;
86 }
87
88 isc_result = isc_mutex_unlock(&Tx_mx);
89 if (isc_result != ISC_R_SUCCESS) {
90 t_info("isc_mutex_unlock failed %s\n",
91 isc_result_totext(isc_result));
92 ++Tx_nprobs;
93 }
94
95 isc_event_free(&event);
96 }
97
98 static void
tx_te(isc_task_t * task,isc_event_t * event)99 tx_te(isc_task_t *task, isc_event_t *event) {
100 isc_result_t isc_result;
101 isc_time_t now;
102 isc_time_t base;
103 isc_time_t ulim;
104 isc_time_t llim;
105 isc_interval_t interval;
106 isc_eventtype_t expected_event_type;
107
108 ++Tx_eventcnt;
109
110 t_info("tick %d\n", Tx_eventcnt);
111
112 expected_event_type = ISC_TIMEREVENT_LIFE;
113 if ((isc_timertype_t) event->ev_arg == isc_timertype_ticker)
114 expected_event_type = ISC_TIMEREVENT_TICK;
115
116 if (event->ev_type != expected_event_type) {
117 t_info("expected event type %d, got %d\n",
118 expected_event_type, (int) event->ev_type);
119 ++Tx_nfails;
120 }
121
122 isc_result = isc_time_now(&now);
123 if (isc_result == ISC_R_SUCCESS) {
124 isc_interval_set(&interval, Tx_seconds, Tx_nanoseconds);
125 isc_result = isc_time_add(&Tx_lasttime, &interval, &base);
126 if (isc_result != ISC_R_SUCCESS) {
127 t_info("isc_time_add failed %s\n",
128 isc_result_totext(isc_result));
129 ++Tx_nprobs;
130 }
131 } else {
132 t_info("isc_time_now failed %s\n",
133 isc_result_totext(isc_result));
134 ++Tx_nprobs;
135 }
136
137 if (isc_result == ISC_R_SUCCESS) {
138 isc_interval_set(&interval,
139 Tx_FUDGE_SECONDS, Tx_FUDGE_NANOSECONDS);
140 isc_result = isc_time_add(&base, &interval, &ulim);
141 if (isc_result != ISC_R_SUCCESS) {
142 t_info("isc_time_add failed %s\n",
143 isc_result_totext(isc_result));
144 ++Tx_nprobs;
145 }
146 }
147
148 if (isc_result == ISC_R_SUCCESS) {
149 isc_result = isc_time_subtract(&base, &interval, &llim);
150 if (isc_result != ISC_R_SUCCESS) {
151 t_info("isc_time_subtract failed %s\n",
152 isc_result_totext(isc_result));
153 ++Tx_nprobs;
154 }
155 }
156
157 if (isc_result == ISC_R_SUCCESS) {
158 if (isc_time_compare(&llim, &now) > 0) {
159 t_info("timer range error: early by "
160 "%lu microseconds\n",
161 (unsigned long)isc_time_microdiff(&base, &now));
162 ++Tx_nfails;
163 } else if (isc_time_compare(&ulim, &now) < 0) {
164 t_info("timer range error: late by "
165 "%lu microseconds\n",
166 (unsigned long)isc_time_microdiff(&now, &base));
167 ++Tx_nfails;
168 }
169 Tx_lasttime = now;
170 }
171
172 if (Tx_eventcnt == Tx_nevents) {
173 isc_result = isc_time_now(&Tx_endtime);
174 if (isc_result != ISC_R_SUCCESS) {
175 t_info("isc_time_now failed %s\n",
176 isc_result_totext(isc_result));
177 ++Tx_nprobs;
178 }
179 isc_timer_detach(&Tx_timer);
180 isc_task_shutdown(task);
181 }
182
183 isc_event_free(&event);
184 }
185
186 static void
t_timers_x(isc_timertype_t timertype,isc_time_t * expires,isc_interval_t * interval,void (* action)(isc_task_t *,isc_event_t *))187 t_timers_x(isc_timertype_t timertype, isc_time_t *expires,
188 isc_interval_t *interval,
189 void (*action)(isc_task_t *, isc_event_t *))
190 {
191 char *p;
192 isc_mem_t *mctx;
193 isc_taskmgr_t *tmgr;
194 isc_task_t *task;
195 unsigned int workers;
196 isc_result_t isc_result;
197 isc_timermgr_t *timermgr;
198
199 Tx_eventcnt = 0;
200 isc_time_settoepoch(&Tx_endtime);
201
202 workers = 2;
203 p = t_getenv("ISC_TASK_WORKERS");
204 if (p != NULL)
205 workers = atoi(p);
206
207 mctx = NULL;
208 isc_result = isc_mem_create(0, 0, &mctx);
209 if (isc_result != ISC_R_SUCCESS) {
210 t_info("isc_mem_create failed %s\n",
211 isc_result_totext(isc_result));
212 ++Tx_nprobs;
213 return;
214 }
215
216 isc_result = isc_mutex_init(&Tx_mx);
217 if (isc_result != ISC_R_SUCCESS) {
218 t_info("isc_mutex_init failed %s\n",
219 isc_result_totext(isc_result));
220 isc_mem_destroy(&mctx);
221 ++Tx_nprobs;
222 return;
223 }
224
225 isc_result = isc_condition_init(&Tx_cv);
226 if (isc_result != ISC_R_SUCCESS) {
227 t_info("isc_condition_init failed %s\n",
228 isc_result_totext(isc_result));
229 DESTROYLOCK(&Tx_mx);
230 isc_mem_destroy(&mctx);
231 ++Tx_nprobs;
232 return;
233 }
234
235 tmgr = NULL;
236 isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
237 if (isc_result != ISC_R_SUCCESS) {
238 t_info("isc_taskmgr_create failed %s\n",
239 isc_result_totext(isc_result));
240 DESTROYLOCK(&Tx_mx);
241 (void) isc_condition_destroy(&Tx_cv);
242 isc_mem_destroy(&mctx);
243 ++Tx_nprobs;
244 return;
245 }
246
247 timermgr = NULL;
248 isc_result = isc_timermgr_create(mctx, &timermgr);
249 if (isc_result != ISC_R_SUCCESS) {
250 t_info("isc_timermgr_create failed %s\n",
251 isc_result_totext(isc_result));
252 isc_taskmgr_destroy(&tmgr);
253 DESTROYLOCK(&Tx_mx);
254 (void) isc_condition_destroy(&Tx_cv);
255 isc_mem_destroy(&mctx);
256 ++Tx_nprobs;
257 return;
258 }
259
260 isc_result = isc_mutex_lock(&Tx_mx);
261 if (isc_result != ISC_R_SUCCESS) {
262 t_info("isc_mutex_lock failed %s\n",
263 isc_result_totext(isc_result));
264 isc_timermgr_destroy(&timermgr);
265 isc_taskmgr_destroy(&tmgr);
266 DESTROYLOCK(&Tx_mx);
267 (void) isc_condition_destroy(&Tx_cv);
268 isc_mem_destroy(&mctx);
269 ++Tx_nprobs;
270 return;
271 }
272
273 task = NULL;
274 isc_result = isc_task_create(tmgr, 0, &task);
275 if (isc_result != ISC_R_SUCCESS) {
276 t_info("isc_task_create failed %s\n",
277 isc_result_totext(isc_result));
278 isc_timermgr_destroy(&timermgr);
279 isc_taskmgr_destroy(&tmgr);
280 DESTROYLOCK(&Tx_mx);
281 (void) isc_condition_destroy(&Tx_cv);
282 isc_mem_destroy(&mctx);
283 ++Tx_nprobs;
284 return;
285 }
286
287 isc_result = isc_task_onshutdown(task, tx_sde, NULL);
288 if (isc_result != ISC_R_SUCCESS) {
289 t_info("isc_task_onshutdown failed %s\n",
290 isc_result_totext(isc_result));
291 isc_timermgr_destroy(&timermgr);
292 isc_task_destroy(&task);
293 isc_taskmgr_destroy(&tmgr);
294 DESTROYLOCK(&Tx_mx);
295 (void) isc_condition_destroy(&Tx_cv);
296 isc_mem_destroy(&mctx);
297 ++Tx_nprobs;
298 return;
299 }
300
301 isc_result = isc_time_now(&Tx_lasttime);
302 if (isc_result != ISC_R_SUCCESS) {
303 isc_timermgr_destroy(&timermgr);
304 isc_task_destroy(&task);
305 isc_taskmgr_destroy(&tmgr);
306 DESTROYLOCK(&Tx_mx);
307 (void) isc_condition_destroy(&Tx_cv);
308 isc_mem_destroy(&mctx);
309 ++Tx_nprobs;
310 return;
311 }
312
313 Tx_timer = NULL;
314 isc_result = isc_timer_create(timermgr, timertype, expires, interval,
315 task, action, (void *)timertype,
316 &Tx_timer);
317
318 if (isc_result != ISC_R_SUCCESS) {
319 isc_timermgr_destroy(&timermgr);
320 isc_task_destroy(&task);
321 isc_taskmgr_destroy(&tmgr);
322 DESTROYLOCK(&Tx_mx);
323 (void) isc_condition_destroy(&Tx_cv);
324 isc_mem_destroy(&mctx);
325 ++Tx_nprobs;
326 return;
327 }
328
329 /*
330 * Wait for shutdown processing to complete.
331 */
332 while (Tx_eventcnt != Tx_nevents) {
333 isc_result = isc_condition_wait(&Tx_cv, &Tx_mx);
334 if (isc_result != ISC_R_SUCCESS) {
335 t_info("isc_condition_waituntil failed %s\n",
336 isc_result_totext(isc_result));
337 ++Tx_nprobs;
338 }
339 }
340
341 isc_result = isc_mutex_unlock(&Tx_mx);
342 if (isc_result != ISC_R_SUCCESS) {
343 t_info("isc_mutex_unlock failed %s\n",
344 isc_result_totext(isc_result));
345 ++Tx_nprobs;
346 }
347
348 isc_task_detach(&task);
349 isc_taskmgr_destroy(&tmgr);
350 isc_timermgr_destroy(&timermgr);
351 DESTROYLOCK(&Tx_mx);
352 (void) isc_condition_destroy(&Tx_cv);
353 isc_mem_destroy(&mctx);
354
355 }
356
357 #define T1_SECONDS 2
358 #define T1_NANOSECONDS 500000000
359
360 static const char *a1 =
361 "When type is isc_timertype_ticker, a call to isc_timer_create() "
362 "creates a timer that posts an ISC_TIMEREVENT_TICK event to the "
363 "specified task every 'interval' seconds and returns ISC_R_SUCCESS.";
364
365 static void
t1(void)366 t1(void) {
367 int result;
368 isc_time_t expires;
369 isc_interval_t interval;
370
371 t_assert("isc_timer_create", 1, T_REQUIRED, "%s", a1);
372
373 if (threaded) {
374 Tx_nfails = 0;
375 Tx_nprobs = 0;
376 Tx_nevents = 12;
377 Tx_seconds = T1_SECONDS;
378 Tx_nanoseconds = T1_NANOSECONDS;
379 isc_interval_set(&interval, Tx_seconds, Tx_nanoseconds);
380 isc_time_settoepoch(&expires);
381
382 t_timers_x(isc_timertype_ticker, &expires, &interval, tx_te);
383
384 result = T_UNRESOLVED;
385
386 if ((Tx_nfails == 0) && (Tx_nprobs == 0))
387 result = T_PASS;
388 else if (Tx_nfails)
389 result = T_FAIL;
390
391 t_result(result);
392 } else
393 require_threads();
394 }
395
396 #define T2_SECONDS 5
397 #define T2_NANOSECONDS 300000000;
398
399 static const char *a2 =
400 "When type is isc_timertype_once, a call to isc_timer_create() "
401 "creates a timer that posts an ISC_TIMEEVENT_LIFE event to the "
402 "specified task when the current time reaches or exceeds the time "
403 "specified by 'expires'.";
404
405 static void
t2(void)406 t2(void) {
407 int result;
408 int isc_result;
409 isc_time_t expires;
410 isc_interval_t interval;
411
412 t_assert("isc_timer_create", 2, T_REQUIRED, "%s", a2);
413
414 if (threaded) {
415 Tx_nfails = 0;
416 Tx_nprobs = 0;
417 Tx_nevents = 1;
418 Tx_seconds = T2_SECONDS;
419 Tx_nanoseconds = T2_NANOSECONDS;
420 isc_interval_set(&interval, Tx_seconds, Tx_nanoseconds);
421
422 isc_result = isc_time_nowplusinterval(&expires, &interval);
423 if (isc_result == ISC_R_SUCCESS) {
424
425 isc_interval_set(&interval, 0, 0);
426 t_timers_x(isc_timertype_once, &expires, &interval,
427 tx_te);
428
429 } else {
430 t_info("isc_time_nowplusinterval failed %s\n",
431 isc_result_totext(isc_result));
432 }
433
434 result = T_UNRESOLVED;
435
436 if ((Tx_nfails == 0) && (Tx_nprobs == 0))
437 result = T_PASS;
438 else if (Tx_nfails)
439 result = T_FAIL;
440
441 t_result(result);
442 } else
443 require_threads();
444 }
445
446 static void
t3_te(isc_task_t * task,isc_event_t * event)447 t3_te(isc_task_t *task, isc_event_t *event) {
448 isc_result_t isc_result;
449 isc_time_t now;
450 isc_time_t base;
451 isc_time_t ulim;
452 isc_time_t llim;
453 isc_interval_t interval;
454
455 ++Tx_eventcnt;
456
457 t_info("tick %d\n", Tx_eventcnt);
458
459 isc_result = isc_time_now(&now);
460 if (isc_result != ISC_R_SUCCESS) {
461 t_info("isc_time_now failed %s\n",
462 isc_result_totext(isc_result));
463 ++Tx_nprobs;
464 }
465
466 if (isc_result == ISC_R_SUCCESS) {
467 isc_interval_set(&interval, Tx_seconds, Tx_nanoseconds);
468 isc_result = isc_time_add(&Tx_lasttime, &interval, &base);
469 if (isc_result != ISC_R_SUCCESS) {
470 t_info("isc_time_add failed %s\n",
471 isc_result_totext(isc_result));
472 ++Tx_nprobs;
473 }
474 }
475
476 if (isc_result == ISC_R_SUCCESS) {
477 isc_interval_set(&interval,
478 Tx_FUDGE_SECONDS, Tx_FUDGE_NANOSECONDS);
479 isc_result = isc_time_add(&base, &interval, &ulim);
480 if (isc_result != ISC_R_SUCCESS) {
481 t_info("isc_time_add failed %s\n",
482 isc_result_totext(isc_result));
483 ++Tx_nprobs;
484 }
485 }
486
487 if (isc_result == ISC_R_SUCCESS) {
488 isc_result = isc_time_subtract(&base, &interval, &llim);
489 if (isc_result != ISC_R_SUCCESS) {
490 t_info("isc_time_subtract failed %s\n",
491 isc_result_totext(isc_result));
492 ++Tx_nprobs;
493 }
494 }
495
496 if (isc_result == ISC_R_SUCCESS) {
497 if (isc_time_compare(&llim, &now) > 0) {
498 t_info("timer range error: early by "
499 "%lu microseconds\n",
500 (unsigned long)isc_time_microdiff(&base, &now));
501 ++Tx_nfails;
502 } else if (isc_time_compare(&ulim, &now) < 0) {
503 t_info("timer range error: late by "
504 "%lu microseconds\n",
505 (unsigned long)isc_time_microdiff(&now, &base));
506 ++Tx_nfails;
507 }
508 Tx_lasttime = now;
509 }
510
511 if (event->ev_type != ISC_TIMEREVENT_IDLE) {
512 t_info("received event type %d, expected type %d\n",
513 event->ev_type, ISC_TIMEREVENT_IDLE);
514 ++Tx_nfails;
515 }
516
517 isc_timer_detach(&Tx_timer);
518 isc_task_shutdown(task);
519 isc_event_free(&event);
520 }
521
522 #define T3_SECONDS 4
523 #define T3_NANOSECONDS 400000000
524
525 static const char *a3 =
526 "When type is isc_timertype_once, a call to isc_timer_create() "
527 "creates a timer that posts an ISC_TIMEEVENT_IDLE event to the "
528 "specified task when the timer has been idle for 'interval' seconds.";
529
530 static void
t3(void)531 t3(void) {
532 int result;
533 int isc_result;
534 isc_time_t expires;
535 isc_interval_t interval;
536
537 t_assert("isc_timer_create", 3, T_REQUIRED, "%s", a3);
538
539 if (threaded) {
540 Tx_nfails = 0;
541 Tx_nprobs = 0;
542 Tx_nevents = 1;
543 Tx_seconds = T3_SECONDS;
544 Tx_nanoseconds = T3_NANOSECONDS;
545
546 isc_interval_set(&interval, Tx_seconds + 1, Tx_nanoseconds);
547
548 isc_result = isc_time_nowplusinterval(&expires, &interval);
549 if (isc_result == ISC_R_SUCCESS) {
550 isc_interval_set(&interval, Tx_seconds,
551 Tx_nanoseconds);
552 t_timers_x(isc_timertype_once, &expires, &interval,
553 t3_te);
554 } else {
555 t_info("isc_time_nowplusinterval failed %s\n",
556 isc_result_totext(isc_result));
557 ++Tx_nprobs;
558 }
559
560 result = T_UNRESOLVED;
561
562 if ((Tx_nfails == 0) && (Tx_nprobs == 0))
563 result = T_PASS;
564 else if (Tx_nfails)
565 result = T_FAIL;
566
567 t_result(result);
568 } else
569 require_threads();
570 }
571
572 #define T4_SECONDS 2
573 #define T4_NANOSECONDS 500000000
574
575 static void
t4_te(isc_task_t * task,isc_event_t * event)576 t4_te(isc_task_t *task, isc_event_t *event) {
577
578 isc_result_t isc_result;
579 isc_time_t now;
580 isc_time_t base;
581 isc_time_t ulim;
582 isc_time_t llim;
583 isc_time_t expires;
584 isc_interval_t interval;
585
586 ++Tx_eventcnt;
587
588 t_info("tick %d\n", Tx_eventcnt);
589
590 /*
591 * Check expired time.
592 */
593
594 isc_result = isc_time_now(&now);
595 if (isc_result != ISC_R_SUCCESS) {
596 t_info("isc_time_now failed %s\n",
597 isc_result_totext(isc_result));
598 ++Tx_nprobs;
599 }
600
601 if (isc_result == ISC_R_SUCCESS) {
602 isc_interval_set(&interval, Tx_seconds, Tx_nanoseconds);
603 isc_result = isc_time_add(&Tx_lasttime, &interval, &base);
604 if (isc_result != ISC_R_SUCCESS) {
605 t_info("isc_time_add failed %s\n",
606 isc_result_totext(isc_result));
607 ++Tx_nprobs;
608 }
609 }
610
611 if (isc_result == ISC_R_SUCCESS) {
612 isc_interval_set(&interval,
613 Tx_FUDGE_SECONDS, Tx_FUDGE_NANOSECONDS);
614 isc_result = isc_time_add(&base, &interval, &ulim);
615 if (isc_result != ISC_R_SUCCESS) {
616 t_info("isc_time_add failed %s\n",
617 isc_result_totext(isc_result));
618 ++Tx_nprobs;
619 }
620 }
621
622 if (isc_result == ISC_R_SUCCESS) {
623 isc_result = isc_time_subtract(&base, &interval, &llim);
624 if (isc_result != ISC_R_SUCCESS) {
625 t_info("isc_time_subtract failed %s\n",
626 isc_result_totext(isc_result));
627 ++Tx_nprobs;
628 }
629 }
630
631 if (isc_result == ISC_R_SUCCESS) {
632 if (isc_time_compare(&llim, &now) > 0) {
633 t_info("timer range error: early by "
634 "%lu microseconds\n",
635 (unsigned long)isc_time_microdiff(&base, &now));
636 ++Tx_nfails;
637 } else if (isc_time_compare(&ulim, &now) < 0) {
638 t_info("timer range error: late by "
639 "%lu microseconds\n",
640 (unsigned long)isc_time_microdiff(&now, &base));
641 ++Tx_nfails;
642 }
643 Tx_lasttime = now;
644 }
645
646 if (Tx_eventcnt < 3) {
647 if (event->ev_type != ISC_TIMEREVENT_TICK) {
648 t_info("received event type %d, expected type %d\n",
649 event->ev_type, ISC_TIMEREVENT_IDLE);
650 ++Tx_nfails;
651 }
652 if (Tx_eventcnt == 2) {
653 isc_interval_set(&interval, T4_SECONDS,
654 T4_NANOSECONDS);
655 isc_result = isc_time_nowplusinterval(&expires,
656 &interval);
657 if (isc_result == ISC_R_SUCCESS) {
658 isc_interval_set(&interval, 0, 0);
659 isc_result =
660 isc_timer_reset(Tx_timer,
661 isc_timertype_once,
662 &expires, &interval,
663 ISC_FALSE);
664 if (isc_result != ISC_R_SUCCESS) {
665 t_info("isc_timer_reset failed %s\n",
666 isc_result_totext(isc_result));
667 ++Tx_nfails;
668 }
669 } else {
670 t_info("isc_time_nowplusinterval failed %s\n",
671 isc_result_totext(isc_result));
672 ++Tx_nprobs;
673 }
674 }
675 } else {
676 if (event->ev_type != ISC_TIMEREVENT_LIFE) {
677 t_info("received event type %d, expected type %d\n",
678 event->ev_type, ISC_TIMEREVENT_IDLE);
679 ++Tx_nfails;
680 }
681
682 isc_timer_detach(&Tx_timer);
683 isc_task_shutdown(task);
684 }
685
686 isc_event_free(&event);
687 }
688
689 static const char *a4 =
690 "A call to isc_timer_reset() changes the timer's type, expires and "
691 "interval values to the given values.";
692
693 static void
t4(void)694 t4(void) {
695 int result;
696 isc_time_t expires;
697 isc_interval_t interval;
698
699 t_assert("isc_timer_reset", 4, T_REQUIRED, "%s", a4);
700
701 if (threaded) {
702 Tx_nfails = 0;
703 Tx_nprobs = 0;
704 Tx_nevents = 3;
705 Tx_seconds = T4_SECONDS;
706 Tx_nanoseconds = T4_NANOSECONDS;
707
708 isc_interval_set(&interval, T4_SECONDS, T4_NANOSECONDS);
709 isc_time_settoepoch(&expires);
710 t_timers_x(isc_timertype_ticker, &expires, &interval, t4_te);
711
712 result = T_UNRESOLVED;
713
714 if ((Tx_nfails == 0) && (Tx_nprobs == 0))
715 result = T_PASS;
716 else if (Tx_nfails)
717 result = T_FAIL;
718
719 t_result(result);
720 } else
721 require_threads();
722 }
723
724 #define T5_NTICKS 4
725 #define T5_SECONDS 3
726
727 static int T5_startflag;
728 static int T5_shutdownflag;
729 static int T5_eventcnt;
730 static isc_mutex_t T5_mx;
731 static isc_condition_t T5_cv;
732 static int T5_nfails;
733 static int T5_nprobs;
734 static isc_timer_t *T5_tickertimer;
735 static isc_timer_t *T5_oncetimer;
736 static isc_task_t *T5_task1;
737 static isc_task_t *T5_task2;
738
739 /*
740 * T5_task1 blocks on T5_mx while events accumulate
741 * in it's queue, until signaled by T5_task2.
742 */
743
744 static void
t5_start_event(isc_task_t * task,isc_event_t * event)745 t5_start_event(isc_task_t *task, isc_event_t *event) {
746 isc_result_t isc_result;
747
748 UNUSED(task);
749
750 t_info("t5_start_event\n");
751
752 isc_result = isc_mutex_lock(&T5_mx);
753 if (isc_result != ISC_R_SUCCESS) {
754 t_info("isc_mutex_lock failed %s\n",
755 isc_result_totext(isc_result));
756 ++T5_nprobs;
757 }
758
759 while (! T5_startflag) {
760 (void) isc_condition_wait(&T5_cv, &T5_mx);
761 }
762
763 isc_result = isc_mutex_unlock(&T5_mx);
764 if (isc_result != ISC_R_SUCCESS) {
765 t_info("isc_mutex_unlock failed %s\n",
766 isc_result_totext(isc_result));
767 ++T5_nprobs;
768 }
769 isc_event_free(&event);
770 }
771
772 static void
t5_tick_event(isc_task_t * task,isc_event_t * event)773 t5_tick_event(isc_task_t *task, isc_event_t *event) {
774 isc_result_t isc_result;
775 isc_time_t expires;
776 isc_interval_t interval;
777
778 UNUSED(task);
779
780 ++T5_eventcnt;
781 t_info("t5_tick_event %d\n", T5_eventcnt);
782
783 /*
784 * On the first tick, purge all remaining tick events
785 * and then shut down the task.
786 */
787 if (T5_eventcnt == 1) {
788 isc_time_settoepoch(&expires);
789 isc_interval_set(&interval, T5_SECONDS, 0);
790 isc_result = isc_timer_reset(T5_tickertimer,
791 isc_timertype_ticker, &expires,
792 &interval, ISC_TRUE);
793 if (isc_result != ISC_R_SUCCESS) {
794 t_info("isc_timer_reset failed %s\n",
795 isc_result_totext(isc_result));
796 ++T5_nfails;
797 }
798 isc_task_shutdown(task);
799 }
800 isc_event_free(&event);
801 }
802
803 static void
t5_once_event(isc_task_t * task,isc_event_t * event)804 t5_once_event(isc_task_t *task, isc_event_t *event) {
805
806 isc_result_t isc_result;
807
808 t_info("t5_once_event\n");
809
810 /*
811 * Allow task1 to start processing events.
812 */
813 isc_result = isc_mutex_lock(&T5_mx);
814 if (isc_result != ISC_R_SUCCESS) {
815 t_info("isc_mutex_lock failed %s\n",
816 isc_result_totext(isc_result));
817 ++T5_nprobs;
818 }
819
820 T5_startflag = 1;
821
822 isc_result = isc_condition_broadcast(&T5_cv);
823 if (isc_result != ISC_R_SUCCESS) {
824 t_info("isc_condition_broadcast failed %s\n",
825 isc_result_totext(isc_result));
826 ++T5_nprobs;
827 }
828
829 isc_result = isc_mutex_unlock(&T5_mx);
830 if (isc_result != ISC_R_SUCCESS) {
831 t_info("isc_mutex_unlock failed %s\n",
832 isc_result_totext(isc_result));
833 ++T5_nprobs;
834 }
835
836 isc_event_free(&event);
837 isc_task_shutdown(task);
838 }
839
840 static void
t5_shutdown_event(isc_task_t * task,isc_event_t * event)841 t5_shutdown_event(isc_task_t *task, isc_event_t *event) {
842
843 isc_result_t isc_result;
844
845 UNUSED(task);
846 UNUSED(event);
847
848 t_info("t5_shutdown_event\n");
849
850 /*
851 * Signal shutdown processing complete.
852 */
853 isc_result = isc_mutex_lock(&T5_mx);
854 if (isc_result != ISC_R_SUCCESS) {
855 t_info("isc_mutex_lock failed %s\n",
856 isc_result_totext(isc_result));
857 ++T5_nprobs;
858 }
859
860 T5_shutdownflag = 1;
861
862 isc_result = isc_condition_signal(&T5_cv);
863 if (isc_result != ISC_R_SUCCESS) {
864 t_info("isc_condition_signal failed %s\n",
865 isc_result_totext(isc_result));
866 ++T5_nprobs;
867 }
868
869 isc_result = isc_mutex_unlock(&T5_mx);
870 if (isc_result != ISC_R_SUCCESS) {
871 t_info("isc_mutex_unlock failed %s\n",
872 isc_result_totext(isc_result));
873 ++T5_nprobs;
874 }
875 isc_event_free(&event);
876 }
877
878 static int
t_timers5(void)879 t_timers5(void) {
880 char *p;
881 int result;
882 isc_mem_t *mctx;
883 isc_taskmgr_t *tmgr;
884 unsigned int workers;
885 isc_result_t isc_result;
886 isc_timermgr_t *timermgr;
887 isc_event_t *event;
888 isc_time_t expires;
889 isc_interval_t interval;
890
891 T5_startflag = 0;
892 T5_shutdownflag = 0;
893 T5_eventcnt = 0;
894
895 workers = 2;
896 p = t_getenv("ISC_TASK_WORKERS");
897 if (p != NULL)
898 workers = atoi(p);
899
900 mctx = NULL;
901 isc_result = isc_mem_create(0, 0, &mctx);
902 if (isc_result != ISC_R_SUCCESS) {
903 t_info("isc_mem_create failed %s\n",
904 isc_result_totext(isc_result));
905 return(T_UNRESOLVED);
906 }
907
908 isc_result = isc_mutex_init(&T5_mx);
909 if (isc_result != ISC_R_SUCCESS) {
910 t_info("isc_mutex_init failed %s\n",
911 isc_result_totext(isc_result));
912 isc_mem_destroy(&mctx);
913 return(T_UNRESOLVED);
914 }
915
916 isc_result = isc_condition_init(&T5_cv);
917 if (isc_result != ISC_R_SUCCESS) {
918 t_info("isc_condition_init failed %s\n",
919 isc_result_totext(isc_result));
920 DESTROYLOCK(&T5_mx);
921 isc_mem_destroy(&mctx);
922 return(T_UNRESOLVED);
923 }
924
925 tmgr = NULL;
926 isc_result = isc_taskmgr_create(mctx, workers, 0, &tmgr);
927 if (isc_result != ISC_R_SUCCESS) {
928 t_info("isc_taskmgr_create failed %s\n",
929 isc_result_totext(isc_result));
930 DESTROYLOCK(&T5_mx);
931 (void) isc_condition_destroy(&T5_cv);
932 isc_mem_destroy(&mctx);
933 return(T_UNRESOLVED);
934 }
935
936 timermgr = NULL;
937 isc_result = isc_timermgr_create(mctx, &timermgr);
938 if (isc_result != ISC_R_SUCCESS) {
939 t_info("isc_timermgr_create failed %s\n",
940 isc_result_totext(isc_result));
941 isc_taskmgr_destroy(&tmgr);
942 DESTROYLOCK(&T5_mx);
943 (void) isc_condition_destroy(&T5_cv);
944 isc_mem_destroy(&mctx);
945 return(T_UNRESOLVED);
946 }
947
948 T5_task1 = NULL;
949 isc_result = isc_task_create(tmgr, 0, &T5_task1);
950 if (isc_result != ISC_R_SUCCESS) {
951 t_info("isc_task_create failed %s\n",
952 isc_result_totext(isc_result));
953 isc_timermgr_destroy(&timermgr);
954 isc_taskmgr_destroy(&tmgr);
955 DESTROYLOCK(&T5_mx);
956 (void) isc_condition_destroy(&T5_cv);
957 isc_mem_destroy(&mctx);
958 return(T_UNRESOLVED);
959 }
960
961 isc_result = isc_task_onshutdown(T5_task1, t5_shutdown_event, NULL);
962 if (isc_result != ISC_R_SUCCESS) {
963 t_info("isc_task_onshutdown failed %s\n",
964 isc_result_totext(isc_result));
965 isc_timermgr_destroy(&timermgr);
966 isc_task_destroy(&T5_task1);
967 isc_taskmgr_destroy(&tmgr);
968 DESTROYLOCK(&T5_mx);
969 (void) isc_condition_destroy(&T5_cv);
970 isc_mem_destroy(&mctx);
971 return(T_UNRESOLVED);
972 }
973
974 T5_task2 = NULL;
975 isc_result = isc_task_create(tmgr, 0, &T5_task2);
976 if (isc_result != ISC_R_SUCCESS) {
977 t_info("isc_task_create failed %s\n",
978 isc_result_totext(isc_result));
979 isc_timermgr_destroy(&timermgr);
980 isc_task_destroy(&T5_task1);
981 isc_taskmgr_destroy(&tmgr);
982 DESTROYLOCK(&T5_mx);
983 (void) isc_condition_destroy(&T5_cv);
984 isc_mem_destroy(&mctx);
985 return(T_UNRESOLVED);
986 }
987
988 isc_result = isc_mutex_lock(&T5_mx);
989 if (isc_result != ISC_R_SUCCESS) {
990 t_info("isc_mutex_lock failed %s\n",
991 isc_result_totext(isc_result));
992 isc_timermgr_destroy(&timermgr);
993 isc_taskmgr_destroy(&tmgr);
994 DESTROYLOCK(&T5_mx);
995 (void) isc_condition_destroy(&T5_cv);
996 isc_mem_destroy(&mctx);
997 return(T_UNRESOLVED);
998 }
999
1000 event = isc_event_allocate(mctx, (void *)1 , (isc_eventtype_t)1,
1001 t5_start_event, NULL, sizeof(*event));
1002 isc_task_send(T5_task1, &event);
1003
1004 isc_time_settoepoch(&expires);
1005 isc_interval_set(&interval, T5_SECONDS, 0);
1006
1007 T5_tickertimer = NULL;
1008 isc_result = isc_timer_create(timermgr, isc_timertype_ticker,
1009 &expires, &interval, T5_task1,
1010 t5_tick_event, NULL, &T5_tickertimer);
1011
1012 if (isc_result != ISC_R_SUCCESS) {
1013 isc_timermgr_destroy(&timermgr);
1014 (void) isc_condition_signal(&T5_cv);
1015 (void) isc_mutex_unlock(&T5_mx);
1016 isc_task_destroy(&T5_task1);
1017 isc_task_destroy(&T5_task2);
1018 isc_taskmgr_destroy(&tmgr);
1019 DESTROYLOCK(&T5_mx);
1020 (void) isc_condition_destroy(&T5_cv);
1021 isc_mem_destroy(&mctx);
1022 return(T_UNRESOLVED);
1023 }
1024
1025 T5_oncetimer = NULL;
1026 isc_interval_set(&interval, (T5_SECONDS * T5_NTICKS) + 2, 0);
1027 isc_result = isc_time_nowplusinterval(&expires, &interval);
1028 if (isc_result != ISC_R_SUCCESS) {
1029 isc_timer_detach(&T5_tickertimer);
1030 isc_timermgr_destroy(&timermgr);
1031 (void)isc_condition_signal(&T5_cv);
1032 (void)isc_mutex_unlock(&T5_mx);
1033 isc_task_destroy(&T5_task1);
1034 isc_task_destroy(&T5_task2);
1035 isc_taskmgr_destroy(&tmgr);
1036 DESTROYLOCK(&T5_mx);
1037 (void) isc_condition_destroy(&T5_cv);
1038 isc_mem_destroy(&mctx);
1039 return(T_UNRESOLVED);
1040 }
1041
1042 isc_interval_set(&interval, 0, 0);
1043 isc_result = isc_timer_create(timermgr, isc_timertype_once,
1044 &expires, &interval, T5_task2,
1045 t5_once_event, NULL, &T5_oncetimer);
1046
1047 if (isc_result != ISC_R_SUCCESS) {
1048 isc_timer_detach(&T5_tickertimer);
1049 isc_timermgr_destroy(&timermgr);
1050 (void) isc_condition_signal(&T5_cv);
1051 (void) isc_mutex_unlock(&T5_mx);
1052 isc_task_destroy(&T5_task1);
1053 isc_task_destroy(&T5_task2);
1054 isc_taskmgr_destroy(&tmgr);
1055 DESTROYLOCK(&T5_mx);
1056 (void) isc_condition_destroy(&T5_cv);
1057 isc_mem_destroy(&mctx);
1058 ++T5_nprobs;
1059 return(T_UNRESOLVED);
1060 }
1061
1062 /*
1063 * Wait for shutdown processing to complete.
1064 */
1065 while (! T5_shutdownflag) {
1066 isc_result = isc_condition_wait(&T5_cv, &T5_mx);
1067 if (isc_result != ISC_R_SUCCESS) {
1068 t_info("isc_condition_waituntil failed %s\n",
1069 isc_result_totext(isc_result));
1070 ++T5_nprobs;
1071 }
1072 }
1073
1074 isc_result = isc_mutex_unlock(&T5_mx);
1075 if (isc_result != ISC_R_SUCCESS) {
1076 t_info("isc_mutex_unlock failed %s\n",
1077 isc_result_totext(isc_result));
1078 ++T5_nprobs;
1079 }
1080
1081 if (T5_eventcnt != 1) {
1082 t_info("processed %d events\n", T5_eventcnt);
1083 ++T5_nfails;
1084 }
1085
1086 isc_timer_detach(&T5_tickertimer);
1087 isc_timer_detach(&T5_oncetimer);
1088 isc_timermgr_destroy(&timermgr);
1089 isc_task_destroy(&T5_task1);
1090 isc_task_destroy(&T5_task2);
1091 isc_taskmgr_destroy(&tmgr);
1092 DESTROYLOCK(&T5_mx);
1093 (void) isc_condition_destroy(&T5_cv);
1094 isc_mem_destroy(&mctx);
1095
1096 result = T_UNRESOLVED;
1097
1098 if ((T5_nfails == 0) && (T5_nprobs == 0))
1099 result = T_PASS;
1100 else if (T5_nfails)
1101 result = T_FAIL;
1102
1103 return (result);
1104 }
1105
1106 static const char *a5 =
1107 "When 'purge' is TRUE, a call to isc_timer_reset() purges any pending "
1108 "events from 'timer' from the task's event queue.";
1109
1110 static void
t5(void)1111 t5(void) {
1112 t_assert("isc_timer_reset", 5, T_REQUIRED, "%s", a5);
1113
1114 if (threaded)
1115 t_result(t_timers5());
1116 else
1117 require_threads();
1118 }
1119
1120 testspec_t T_testlist[] = {
1121 { (PFV) t1, "timer_create" },
1122 { (PFV) t2, "timer_create" },
1123 { (PFV) t3, "timer_create" },
1124 { (PFV) t4, "timer_reset" },
1125 { (PFV) t5, "timer_reset" },
1126 { (PFV) NULL, NULL }
1127 };
1128
1129 #ifdef WIN32
1130 int
main(int argc,char ** argv)1131 main(int argc, char **argv) {
1132 t_settests(T_testlist);
1133 return (t_main(argc, argv));
1134 }
1135 #endif
1136