1 /* 2 * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "common.h" 18 #include <sys/time.h> 19 20 #define MILLION 1000000 21 #define THOUSAND 1000 22 #define SEC_TO_MS(t) ((t) * THOUSAND) /* Convert seconds to milliseconds. */ 23 #define SEC_TO_US(t) ((t) * MILLION) /* Convert seconds to microseconds. */ 24 #define MS_TO_US(t) ((t) * THOUSAND) /* Convert milliseconds to microseconds. */ 25 #define US_TO_NS(t) ((t) * THOUSAND) /* Convert microseconds to nanoseconds. */ 26 27 28 /* Get the current time with microsecond precision. Used for 29 * sub-second timing to make some timer tests run faster. 30 */ 31 static uint64_t 32 now(void) 33 { 34 struct timeval tv; 35 36 gettimeofday(&tv, NULL); 37 /* Promote potentially 32-bit time_t to uint64_t before conversion. */ 38 return SEC_TO_US((uint64_t)tv.tv_sec) + tv.tv_usec; 39 } 40 41 /* Sleep for a given number of milliseconds. The timeout is assumed to 42 * be less than 1 second. 43 */ 44 static void 45 mssleep(int t) 46 { 47 struct timespec stime = { 48 .tv_sec = 0, 49 .tv_nsec = US_TO_NS(MS_TO_US(t)), 50 }; 51 52 nanosleep(&stime, NULL); 53 } 54 55 /* Sleep for a given number of microseconds. The timeout is assumed to 56 * be less than 1 second. 57 */ 58 static void 59 ussleep(int t) 60 { 61 struct timespec stime = { 62 .tv_sec = 0, 63 .tv_nsec = US_TO_NS(t), 64 }; 65 66 nanosleep(&stime, NULL); 67 } 68 69 static void 70 test_kevent_timer_add(void) 71 { 72 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)"; 73 struct kevent kev; 74 75 test_begin(test_id); 76 77 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 78 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 79 err(1, "%s", test_id); 80 81 success(); 82 } 83 84 static void 85 test_kevent_timer_del(void) 86 { 87 const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)"; 88 struct kevent kev; 89 90 test_begin(test_id); 91 92 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 93 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 94 err(1, "%s", test_id); 95 96 test_no_kevents(); 97 98 success(); 99 } 100 101 static void 102 test_kevent_timer_get(void) 103 { 104 const char *test_id = "kevent(EVFILT_TIMER, wait)"; 105 struct kevent kev; 106 107 test_begin(test_id); 108 109 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 110 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 111 err(1, "%s", test_id); 112 113 kev.flags |= EV_CLEAR; 114 kev.data = 1; 115 kevent_cmp(&kev, kevent_get(kqfd)); 116 117 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 118 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 119 err(1, "%s", test_id); 120 121 success(); 122 } 123 124 static void 125 test_oneshot(void) 126 { 127 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)"; 128 struct kevent kev; 129 130 test_begin(test_id); 131 132 test_no_kevents(); 133 134 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL); 135 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 136 err(1, "%s", test_id); 137 138 /* Retrieve the event */ 139 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 140 kev.data = 1; 141 kevent_cmp(&kev, kevent_get(kqfd)); 142 143 /* Check if the event occurs again */ 144 sleep(3); 145 test_no_kevents(); 146 147 148 success(); 149 } 150 151 static void 152 test_periodic(void) 153 { 154 const char *test_id = "kevent(EVFILT_TIMER, periodic)"; 155 struct kevent kev; 156 157 test_begin(test_id); 158 159 test_no_kevents(); 160 161 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL); 162 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 163 err(1, "%s", test_id); 164 165 /* Retrieve the event */ 166 kev.flags = EV_ADD | EV_CLEAR; 167 kev.data = 1; 168 kevent_cmp(&kev, kevent_get(kqfd)); 169 170 /* Check if the event occurs again */ 171 sleep(1); 172 kevent_cmp(&kev, kevent_get(kqfd)); 173 174 /* Delete the event */ 175 kev.flags = EV_DELETE; 176 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 177 err(1, "%s", test_id); 178 179 success(); 180 } 181 182 static void 183 test_periodic_modify(void) 184 { 185 const char *test_id = "kevent(EVFILT_TIMER, periodic_modify)"; 186 struct kevent kev; 187 188 test_begin(test_id); 189 190 test_no_kevents(); 191 192 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 193 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 194 err(1, "%s", test_id); 195 196 /* Retrieve the event */ 197 kev.flags = EV_ADD | EV_CLEAR; 198 kev.data = 1; 199 kevent_cmp(&kev, kevent_get(kqfd)); 200 201 /* Check if the event occurs again */ 202 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 495, NULL); 203 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 204 err(1, "%s", test_id); 205 206 kev.flags = EV_ADD | EV_CLEAR; 207 sleep(1); 208 kev.data = 2; /* Should have fired twice */ 209 210 kevent_cmp(&kev, kevent_get(kqfd)); 211 212 /* Delete the event */ 213 kev.flags = EV_DELETE; 214 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 215 err(1, "%s", test_id); 216 217 success(); 218 } 219 220 #if WITH_NATIVE_KQUEUE_BUGS 221 static void 222 test_periodic_to_oneshot(void) 223 { 224 const char *test_id = "kevent(EVFILT_TIMER, period_to_oneshot)"; 225 struct kevent kev; 226 227 test_begin(test_id); 228 229 test_no_kevents(); 230 231 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 232 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 233 err(1, "%s", test_id); 234 235 /* Retrieve the event */ 236 kev.flags = EV_ADD | EV_CLEAR; 237 kev.data = 1; 238 kevent_cmp(&kev, kevent_get(kqfd)); 239 240 /* Check if the event occurs again */ 241 sleep(1); 242 kevent_cmp(&kev, kevent_get(kqfd)); 243 244 /* Switch to oneshot */ 245 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500, NULL); 246 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 247 err(1, "%s", test_id); 248 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 249 250 sleep(1); 251 kev.data = 1; /* Should have fired once */ 252 253 kevent_cmp(&kev, kevent_get(kqfd)); 254 255 success(); 256 } 257 #endif 258 259 static void 260 test_disable_and_enable(void) 261 { 262 const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)"; 263 struct kevent kev; 264 265 test_begin(test_id); 266 267 test_no_kevents(); 268 269 /* Add the watch and immediately disable it */ 270 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL); 271 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 272 err(1, "%s", test_id); 273 kev.flags = EV_DISABLE; 274 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 275 err(1, "%s", test_id); 276 test_no_kevents(); 277 278 /* Re-enable and check again */ 279 kev.flags = EV_ENABLE; 280 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 281 err(1, "%s", test_id); 282 283 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 284 kev.data = 1; 285 kevent_cmp(&kev, kevent_get(kqfd)); 286 287 success(); 288 } 289 290 static void 291 test_abstime(void) 292 { 293 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)"; 294 struct kevent kev; 295 uint64_t end, start, stop; 296 const int timeout_sec = 3; 297 298 test_begin(test_id); 299 300 test_no_kevents(); 301 302 start = now(); 303 end = start + SEC_TO_US(timeout_sec); 304 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 305 NOTE_ABSTIME | NOTE_USECONDS, end, NULL); 306 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 307 err(1, "%s", test_id); 308 309 /* Retrieve the event */ 310 kev.flags = EV_ADD | EV_ONESHOT; 311 kev.data = 1; 312 kev.fflags = 0; 313 kevent_cmp(&kev, kevent_get(kqfd)); 314 315 stop = now(); 316 if (stop < end) 317 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end); 318 /* Check if the event occurs again */ 319 sleep(3); 320 test_no_kevents(); 321 322 success(); 323 } 324 325 static void 326 test_abstime_epoch(void) 327 { 328 const char *test_id = "kevent(EVFILT_TIMER (EPOCH), NOTE_ABSTIME)"; 329 struct kevent kev; 330 331 test_begin(test_id); 332 333 test_no_kevents(); 334 335 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, NOTE_ABSTIME, 0, 336 NULL); 337 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 338 err(1, "%s", test_id); 339 340 /* Retrieve the event */ 341 kev.flags = EV_ADD; 342 kev.data = 1; 343 kev.fflags = 0; 344 kevent_cmp(&kev, kevent_get(kqfd)); 345 346 /* Delete the event */ 347 kev.flags = EV_DELETE; 348 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 349 err(1, "%s", test_id); 350 351 success(); 352 } 353 354 static void 355 test_abstime_preboot(void) 356 { 357 const char *test_id = "kevent(EVFILT_TIMER (PREBOOT), EV_ONESHOT, NOTE_ABSTIME)"; 358 struct kevent kev; 359 struct timespec btp; 360 uint64_t end, start, stop; 361 362 test_begin(test_id); 363 364 test_no_kevents(); 365 366 /* 367 * We'll expire it at just before system boot (roughly) with the hope that 368 * we'll get an ~immediate expiration, just as we do for any value specified 369 * between system boot and now. 370 */ 371 start = now(); 372 if (clock_gettime(CLOCK_BOOTTIME, &btp) != 0) 373 err(1, "%s", test_id); 374 375 end = start - SEC_TO_US(btp.tv_sec + 1); 376 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 377 NOTE_ABSTIME | NOTE_USECONDS, end, NULL); 378 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 379 err(1, "%s", test_id); 380 381 /* Retrieve the event */ 382 kev.flags = EV_ADD | EV_ONESHOT; 383 kev.data = 1; 384 kev.fflags = 0; 385 kevent_cmp(&kev, kevent_get(kqfd)); 386 387 stop = now(); 388 if (stop < end) 389 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end); 390 /* Check if the event occurs again */ 391 sleep(3); 392 test_no_kevents(); 393 394 success(); 395 } 396 397 static void 398 test_abstime_postboot(void) 399 { 400 const char *test_id = "kevent(EVFILT_TIMER (POSTBOOT), EV_ONESHOT, NOTE_ABSTIME)"; 401 struct kevent kev; 402 uint64_t end, start, stop; 403 const int timeout_sec = 1; 404 405 test_begin(test_id); 406 407 test_no_kevents(); 408 409 /* 410 * Set a timer for 1 second ago, it should fire immediately rather than 411 * being rejected. 412 */ 413 start = now(); 414 end = start - SEC_TO_US(timeout_sec); 415 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 416 NOTE_ABSTIME | NOTE_USECONDS, end, NULL); 417 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 418 err(1, "%s", test_id); 419 420 /* Retrieve the event */ 421 kev.flags = EV_ADD | EV_ONESHOT; 422 kev.data = 1; 423 kev.fflags = 0; 424 kevent_cmp(&kev, kevent_get(kqfd)); 425 426 stop = now(); 427 if (stop < end) 428 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end); 429 /* Check if the event occurs again */ 430 sleep(3); 431 test_no_kevents(); 432 433 success(); 434 } 435 436 static void 437 test_update(void) 438 { 439 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)"; 440 struct kevent kev; 441 long elapsed; 442 uint64_t start; 443 444 test_begin(test_id); 445 446 test_no_kevents(); 447 448 /* First set the timer to 1 second */ 449 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 450 NOTE_USECONDS, SEC_TO_US(1), (void *)1); 451 start = now(); 452 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 453 err(1, "%s", test_id); 454 455 /* Now reduce the timer to 1 ms */ 456 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 457 NOTE_USECONDS, MS_TO_US(1), (void *)2); 458 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 459 err(1, "%s", test_id); 460 461 /* Wait for the event */ 462 kev.flags |= EV_CLEAR; 463 kev.fflags &= ~NOTE_USECONDS; 464 kev.data = 1; 465 kevent_cmp(&kev, kevent_get(kqfd)); 466 elapsed = now() - start; 467 468 /* Check that the timer expired after at least 1 ms, but less than 469 * 1 second. This check is to make sure that the original 1 second 470 * timeout was not used. 471 */ 472 printf("timer expired after %ld us\n", elapsed); 473 if (elapsed < MS_TO_US(1)) 474 errx(1, "early timer expiration: %ld us", elapsed); 475 if (elapsed > SEC_TO_US(1)) 476 errx(1, "late timer expiration: %ld us", elapsed); 477 478 success(); 479 } 480 481 static void 482 test_update_equal(void) 483 { 484 const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)"; 485 struct kevent kev; 486 long elapsed; 487 uint64_t start; 488 489 test_begin(test_id); 490 491 test_no_kevents(); 492 493 /* First set the timer to 1 ms */ 494 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 495 NOTE_USECONDS, MS_TO_US(1), NULL); 496 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 497 err(1, "%s", test_id); 498 499 /* Sleep for a significant fraction of the timeout. */ 500 ussleep(600); 501 502 /* Now re-add the timer with the same parameters */ 503 start = now(); 504 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 505 err(1, "%s", test_id); 506 507 /* Wait for the event */ 508 kev.flags |= EV_CLEAR; 509 kev.fflags &= ~NOTE_USECONDS; 510 kev.data = 1; 511 kevent_cmp(&kev, kevent_get(kqfd)); 512 elapsed = now() - start; 513 514 /* Check that the timer expired after at least 1 ms. This check is 515 * to make sure that the timer re-started and that the event is 516 * not from the original add of the timer. 517 */ 518 printf("timer expired after %ld us\n", elapsed); 519 if (elapsed < MS_TO_US(1)) 520 errx(1, "early timer expiration: %ld us", elapsed); 521 522 success(); 523 } 524 525 static void 526 test_update_expired(void) 527 { 528 const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)"; 529 struct kevent kev; 530 long elapsed; 531 uint64_t start; 532 533 test_begin(test_id); 534 535 test_no_kevents(); 536 537 /* Set the timer to 1ms */ 538 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 539 NOTE_USECONDS, MS_TO_US(1), NULL); 540 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 541 err(1, "%s", test_id); 542 543 /* Wait for 2 ms to give the timer plenty of time to expire. */ 544 mssleep(2); 545 546 /* Now re-add the timer */ 547 start = now(); 548 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 549 err(1, "%s", test_id); 550 551 /* Wait for the event */ 552 kev.flags |= EV_CLEAR; 553 kev.fflags &= ~NOTE_USECONDS; 554 kev.data = 1; 555 kevent_cmp(&kev, kevent_get(kqfd)); 556 elapsed = now() - start; 557 558 /* Check that the timer expired after at least 1 ms. This check 559 * is to make sure that the timer re-started and that the event is 560 * not from the original add (and expiration) of the timer. 561 */ 562 printf("timer expired after %ld us\n", elapsed); 563 if (elapsed < MS_TO_US(1)) 564 errx(1, "early timer expiration: %ld us", elapsed); 565 566 /* Make sure the re-added timer does not fire. In other words, 567 * test that the event received above was the only event from the 568 * add and re-add of the timer. 569 */ 570 mssleep(2); 571 test_no_kevents(); 572 573 success(); 574 } 575 576 static void 577 test_update_periodic(void) 578 { 579 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)"; 580 struct kevent kev; 581 long elapsed; 582 uint64_t start, stop; 583 584 test_begin(test_id); 585 586 test_no_kevents(); 587 588 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL); 589 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 590 err(1, "%s", test_id); 591 592 /* Retrieve the event */ 593 kev.flags = EV_ADD | EV_CLEAR; 594 kev.data = 1; 595 kevent_cmp(&kev, kevent_get(kqfd)); 596 597 /* Check if the event occurs again */ 598 sleep(1); 599 kevent_cmp(&kev, kevent_get(kqfd)); 600 601 /* Re-add with new timeout. */ 602 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL); 603 start = now(); 604 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 605 err(1, "%s", test_id); 606 607 /* Retrieve the event */ 608 kev.flags = EV_ADD | EV_CLEAR; 609 kev.data = 1; 610 kevent_cmp(&kev, kevent_get(kqfd)); 611 612 stop = now(); 613 elapsed = stop - start; 614 615 /* Check that the timer expired after at least 2 ms. 616 */ 617 printf("timer expired after %ld us\n", elapsed); 618 if (elapsed < MS_TO_US(2)) 619 errx(1, "early timer expiration: %ld us", elapsed); 620 621 /* Delete the event */ 622 kev.flags = EV_DELETE; 623 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 624 err(1, "%s", test_id); 625 626 success(); 627 } 628 629 static void 630 test_update_timing(void) 631 { 632 #define MIN_SLEEP 500 633 #define MAX_SLEEP 1500 634 const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)"; 635 struct kevent kev; 636 int sleeptime; 637 long elapsed; 638 uint64_t start, stop; 639 640 test_begin(test_id); 641 642 test_no_kevents(); 643 644 /* Re-try the update tests with a variety of delays between the 645 * original timer activation and the update of the timer. The goal 646 * is to show that in all cases the only timer event that is 647 * received is from the update and not the original timer add. 648 */ 649 for (sleeptime = MIN_SLEEP; sleeptime < MAX_SLEEP; ++sleeptime) { 650 /* First set the timer to 1 ms */ 651 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 652 NOTE_USECONDS, MS_TO_US(1), NULL); 653 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 654 err(1, "%s", test_id); 655 656 /* Delay; the delay ranges from less than to greater than the 657 * timer period. 658 */ 659 ussleep(sleeptime); 660 661 /* Now re-add the timer with the same parameters */ 662 start = now(); 663 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 664 err(1, "%s", test_id); 665 666 /* Wait for the event */ 667 kev.flags |= EV_CLEAR; 668 kev.fflags &= ~NOTE_USECONDS; 669 kev.data = 1; 670 kevent_cmp(&kev, kevent_get(kqfd)); 671 stop = now(); 672 elapsed = stop - start; 673 674 /* Check that the timer expired after at least 1 ms. This 675 * check is to make sure that the timer re-started and that 676 * the event is not from the original add of the timer. 677 */ 678 if (elapsed < MS_TO_US(1)) 679 errx(1, "early timer expiration: %ld us", elapsed); 680 681 /* Make sure the re-added timer does not fire. In other words, 682 * test that the event received above was the only event from 683 * the add and re-add of the timer. 684 */ 685 mssleep(2); 686 test_no_kevents_quietly(); 687 } 688 689 success(); 690 } 691 692 static void 693 test_dispatch(void) 694 { 695 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD | EV_DISPATCH)"; 696 struct kevent kev; 697 698 test_no_kevents(); 699 700 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 200, NULL); 701 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 702 err(1, "%s", test_id); 703 704 /* Get one event */ 705 kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH; 706 kev.data = 1; 707 kevent_cmp(&kev, kevent_get(kqfd)); 708 709 /* Confirm that the knote is disabled due to EV_DISPATCH */ 710 usleep(500000); 711 test_no_kevents(); 712 713 /* Enable the knote and make sure no events are pending */ 714 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_DISPATCH, 0, 200, NULL); 715 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 716 err(1, "%s", test_id); 717 test_no_kevents(); 718 719 /* Get the next event */ 720 usleep(1100000); /* 1100 ms */ 721 kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH; 722 kev.data = 5; 723 kevent_cmp(&kev, kevent_get(kqfd)); 724 725 /* Remove the knote and ensure the event no longer fires */ 726 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 727 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 728 err(1, "%s", test_id); 729 usleep(500000); /* 500ms */ 730 test_no_kevents(); 731 732 success(); 733 } 734 735 void 736 test_evfilt_timer(void) 737 { 738 kqfd = kqueue(); 739 test_kevent_timer_add(); 740 test_kevent_timer_del(); 741 test_kevent_timer_get(); 742 test_oneshot(); 743 test_periodic(); 744 test_periodic_modify(); 745 #if WITH_NATIVE_KQUEUE_BUGS 746 test_periodic_to_oneshot(); 747 #endif 748 test_abstime(); 749 test_abstime_epoch(); 750 test_abstime_preboot(); 751 test_abstime_postboot(); 752 test_update(); 753 test_update_equal(); 754 test_update_expired(); 755 test_update_timing(); 756 test_update_periodic(); 757 test_disable_and_enable(); 758 test_dispatch(); 759 close(kqfd); 760 } 761