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