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, 500, 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 iteration; 637 int sleeptime; 638 long elapsed; 639 uint64_t start, stop; 640 641 test_begin(test_id); 642 643 test_no_kevents(); 644 645 /* Re-try the update tests with a variety of delays between the 646 * original timer activation and the update of the timer. The goal 647 * is to show that in all cases the only timer event that is 648 * received is from the update and not the original timer add. 649 */ 650 for (sleeptime = MIN_SLEEP, iteration = 1; 651 sleeptime < MAX_SLEEP; 652 ++sleeptime, ++iteration) { 653 654 /* First set the timer to 1 ms */ 655 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 656 NOTE_USECONDS, MS_TO_US(1), NULL); 657 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 658 err(1, "%s", test_id); 659 660 /* Delay; the delay ranges from less than to greater than the 661 * timer period. 662 */ 663 ussleep(sleeptime); 664 665 /* Now re-add the timer with the same parameters */ 666 start = now(); 667 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 668 err(1, "%s", test_id); 669 670 /* Wait for the event */ 671 kev.flags |= EV_CLEAR; 672 kev.fflags &= ~NOTE_USECONDS; 673 kev.data = 1; 674 kevent_cmp(&kev, kevent_get(kqfd)); 675 stop = now(); 676 elapsed = stop - start; 677 678 /* Check that the timer expired after at least 1 ms. This 679 * check is to make sure that the timer re-started and that 680 * the event is not from the original add of the timer. 681 */ 682 if (elapsed < MS_TO_US(1)) 683 errx(1, "early timer expiration: %ld us", elapsed); 684 685 /* Make sure the re-added timer does not fire. In other words, 686 * test that the event received above was the only event from 687 * the add and re-add of the timer. 688 */ 689 mssleep(2); 690 test_no_kevents_quietly(); 691 } 692 693 success(); 694 } 695 696 static void 697 test_dispatch(void) 698 { 699 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD | EV_DISPATCH)"; 700 struct kevent kev; 701 702 test_no_kevents(); 703 704 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 200, NULL); 705 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 706 err(1, "%s", test_id); 707 708 /* Get one event */ 709 kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH; 710 kev.data = 1; 711 kevent_cmp(&kev, kevent_get(kqfd)); 712 713 /* Confirm that the knote is disabled due to EV_DISPATCH */ 714 usleep(500000); 715 test_no_kevents(); 716 717 /* Enable the knote and make sure no events are pending */ 718 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_DISPATCH, 0, 200, NULL); 719 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 720 err(1, "%s", test_id); 721 test_no_kevents(); 722 723 /* Get the next event */ 724 usleep(1100000); /* 1100 ms */ 725 kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH; 726 kev.data = 5; 727 kevent_cmp(&kev, kevent_get(kqfd)); 728 729 /* Remove the knote and ensure the event no longer fires */ 730 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 731 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 732 err(1, "%s", test_id); 733 usleep(500000); /* 500ms */ 734 test_no_kevents(); 735 736 success(); 737 } 738 739 void 740 test_evfilt_timer(void) 741 { 742 kqfd = kqueue(); 743 test_kevent_timer_add(); 744 test_kevent_timer_del(); 745 test_kevent_timer_get(); 746 test_oneshot(); 747 test_periodic(); 748 test_periodic_modify(); 749 #if WITH_NATIVE_KQUEUE_BUGS 750 test_periodic_to_oneshot(); 751 #endif 752 test_abstime(); 753 test_abstime_epoch(); 754 test_abstime_preboot(); 755 test_abstime_postboot(); 756 test_update(); 757 test_update_equal(); 758 test_update_expired(); 759 test_update_timing(); 760 test_update_periodic(); 761 test_disable_and_enable(); 762 test_dispatch(); 763 close(kqfd); 764 } 765