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