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