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 58 require_threads(void) { 59 t_info("This test requires threads\n"); 60 t_result(T_THREADONLY); 61 return; 62 } 63 64 static void 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1131 main(int argc, char **argv) { 1132 t_settests(T_testlist); 1133 return (t_main(argc, argv)); 1134 } 1135 #endif 1136