1cb5fe245SEnji Cooper /* 2cb5fe245SEnji Cooper * Copyright (c) 2009 Mark Heily <mark@heily.com> 3cb5fe245SEnji Cooper * 4cb5fe245SEnji Cooper * Permission to use, copy, modify, and distribute this software for any 5cb5fe245SEnji Cooper * purpose with or without fee is hereby granted, provided that the above 6cb5fe245SEnji Cooper * copyright notice and this permission notice appear in all copies. 7cb5fe245SEnji Cooper * 8cb5fe245SEnji Cooper * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9cb5fe245SEnji Cooper * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10cb5fe245SEnji Cooper * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11cb5fe245SEnji Cooper * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12cb5fe245SEnji Cooper * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13cb5fe245SEnji Cooper * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14cb5fe245SEnji Cooper * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15cb5fe245SEnji Cooper * 16cb5fe245SEnji Cooper * $FreeBSD$ 17cb5fe245SEnji Cooper */ 18cb5fe245SEnji Cooper 19cb5fe245SEnji Cooper #include "common.h" 202b34e843SKonstantin Belousov #include <sys/time.h> 21cb5fe245SEnji Cooper 22*95c05062SDavid Bright #define MILLION 1000000 23*95c05062SDavid Bright #define THOUSAND 1000 24*95c05062SDavid Bright #define SEC_TO_MS(t) ((t) * THOUSAND) /* Convert seconds to milliseconds. */ 25*95c05062SDavid Bright #define SEC_TO_US(t) ((t) * MILLION) /* Convert seconds to microseconds. */ 26*95c05062SDavid Bright #define MS_TO_US(t) ((t) * THOUSAND) /* Convert milliseconds to microseconds. */ 27*95c05062SDavid Bright #define US_TO_NS(t) ((t) * THOUSAND) /* Convert microseconds to nanoseconds. */ 28*95c05062SDavid Bright 29cb5fe245SEnji Cooper int kqfd; 30cb5fe245SEnji Cooper 31*95c05062SDavid Bright /* Get the current time with microsecond precision. Used for 32*95c05062SDavid Bright * sub-second timing to make some timer tests run faster. 33*95c05062SDavid Bright */ 34*95c05062SDavid Bright static long 35*95c05062SDavid Bright now(void) 36*95c05062SDavid Bright { 37*95c05062SDavid Bright 38*95c05062SDavid Bright struct timeval tv; 39*95c05062SDavid Bright 40*95c05062SDavid Bright gettimeofday(&tv, NULL); 41*95c05062SDavid Bright return SEC_TO_US(tv.tv_sec) + tv.tv_usec; 42*95c05062SDavid Bright } 43*95c05062SDavid Bright 44*95c05062SDavid Bright /* Sleep for a given number of milliseconds. The timeout is assumed to 45*95c05062SDavid Bright * be less than 1 second. 46*95c05062SDavid Bright */ 47*95c05062SDavid Bright void 48*95c05062SDavid Bright mssleep(int t) 49*95c05062SDavid Bright { 50*95c05062SDavid Bright 51*95c05062SDavid Bright struct timespec stime = { 52*95c05062SDavid Bright .tv_sec = 0, 53*95c05062SDavid Bright .tv_nsec = US_TO_NS(MS_TO_US(t)), 54*95c05062SDavid Bright }; 55*95c05062SDavid Bright 56*95c05062SDavid Bright nanosleep(&stime, NULL); 57*95c05062SDavid Bright } 58*95c05062SDavid Bright 59*95c05062SDavid Bright /* Sleep for a given number of microseconds. The timeout is assumed to 60*95c05062SDavid Bright * be less than 1 second. 61*95c05062SDavid Bright */ 62*95c05062SDavid Bright void 63*95c05062SDavid Bright ussleep(int t) 64*95c05062SDavid Bright { 65*95c05062SDavid Bright 66*95c05062SDavid Bright struct timespec stime = { 67*95c05062SDavid Bright .tv_sec = 0, 68*95c05062SDavid Bright .tv_nsec = US_TO_NS(t), 69*95c05062SDavid Bright }; 70*95c05062SDavid Bright 71*95c05062SDavid Bright nanosleep(&stime, NULL); 72*95c05062SDavid Bright } 73*95c05062SDavid Bright 74cb5fe245SEnji Cooper void 75cb5fe245SEnji Cooper test_kevent_timer_add(void) 76cb5fe245SEnji Cooper { 77cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)"; 78cb5fe245SEnji Cooper struct kevent kev; 79cb5fe245SEnji Cooper 80cb5fe245SEnji Cooper test_begin(test_id); 81cb5fe245SEnji Cooper 82cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 83cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 84cb5fe245SEnji Cooper err(1, "%s", test_id); 85cb5fe245SEnji Cooper 86cb5fe245SEnji Cooper success(); 87cb5fe245SEnji Cooper } 88cb5fe245SEnji Cooper 89cb5fe245SEnji Cooper void 90cb5fe245SEnji Cooper test_kevent_timer_del(void) 91cb5fe245SEnji Cooper { 92cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)"; 93cb5fe245SEnji Cooper struct kevent kev; 94cb5fe245SEnji Cooper 95cb5fe245SEnji Cooper test_begin(test_id); 96cb5fe245SEnji Cooper 97cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 98cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 99cb5fe245SEnji Cooper err(1, "%s", test_id); 100cb5fe245SEnji Cooper 101cb5fe245SEnji Cooper test_no_kevents(); 102cb5fe245SEnji Cooper 103cb5fe245SEnji Cooper success(); 104cb5fe245SEnji Cooper } 105cb5fe245SEnji Cooper 106cb5fe245SEnji Cooper void 107cb5fe245SEnji Cooper test_kevent_timer_get(void) 108cb5fe245SEnji Cooper { 109cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, wait)"; 110cb5fe245SEnji Cooper struct kevent kev; 111cb5fe245SEnji Cooper 112cb5fe245SEnji Cooper test_begin(test_id); 113cb5fe245SEnji Cooper 114cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 115cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 116cb5fe245SEnji Cooper err(1, "%s", test_id); 117cb5fe245SEnji Cooper 118cb5fe245SEnji Cooper kev.flags |= EV_CLEAR; 119cb5fe245SEnji Cooper kev.data = 1; 120cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 121cb5fe245SEnji Cooper 122cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 123cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 124cb5fe245SEnji Cooper err(1, "%s", test_id); 125cb5fe245SEnji Cooper 126cb5fe245SEnji Cooper success(); 127cb5fe245SEnji Cooper } 128cb5fe245SEnji Cooper 129cb5fe245SEnji Cooper static void 130cb5fe245SEnji Cooper test_oneshot(void) 131cb5fe245SEnji Cooper { 132cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)"; 133cb5fe245SEnji Cooper struct kevent kev; 134cb5fe245SEnji Cooper 135cb5fe245SEnji Cooper test_begin(test_id); 136cb5fe245SEnji Cooper 137cb5fe245SEnji Cooper test_no_kevents(); 138cb5fe245SEnji Cooper 139cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL); 140cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 141cb5fe245SEnji Cooper err(1, "%s", test_id); 142cb5fe245SEnji Cooper 143cb5fe245SEnji Cooper /* Retrieve the event */ 144cb5fe245SEnji Cooper kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 145cb5fe245SEnji Cooper kev.data = 1; 146cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 147cb5fe245SEnji Cooper 148cb5fe245SEnji Cooper /* Check if the event occurs again */ 149cb5fe245SEnji Cooper sleep(3); 150cb5fe245SEnji Cooper test_no_kevents(); 151cb5fe245SEnji Cooper 152cb5fe245SEnji Cooper 153cb5fe245SEnji Cooper success(); 154cb5fe245SEnji Cooper } 155cb5fe245SEnji Cooper 156cb5fe245SEnji Cooper static void 157cb5fe245SEnji Cooper test_periodic(void) 158cb5fe245SEnji Cooper { 159cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, periodic)"; 160cb5fe245SEnji Cooper struct kevent kev; 161cb5fe245SEnji Cooper 162cb5fe245SEnji Cooper test_begin(test_id); 163cb5fe245SEnji Cooper 164cb5fe245SEnji Cooper test_no_kevents(); 165cb5fe245SEnji Cooper 166cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL); 167cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 168cb5fe245SEnji Cooper err(1, "%s", test_id); 169cb5fe245SEnji Cooper 170cb5fe245SEnji Cooper /* Retrieve the event */ 171cb5fe245SEnji Cooper kev.flags = EV_ADD | EV_CLEAR; 172cb5fe245SEnji Cooper kev.data = 1; 173cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 174cb5fe245SEnji Cooper 175cb5fe245SEnji Cooper /* Check if the event occurs again */ 176cb5fe245SEnji Cooper sleep(1); 177cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 178cb5fe245SEnji Cooper 179cb5fe245SEnji Cooper /* Delete the event */ 180cb5fe245SEnji Cooper kev.flags = EV_DELETE; 181cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 182cb5fe245SEnji Cooper err(1, "%s", test_id); 183cb5fe245SEnji Cooper 184cb5fe245SEnji Cooper success(); 185cb5fe245SEnji Cooper } 186cb5fe245SEnji Cooper 187cb5fe245SEnji Cooper static void 188cb5fe245SEnji Cooper disable_and_enable(void) 189cb5fe245SEnji Cooper { 190cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)"; 191cb5fe245SEnji Cooper struct kevent kev; 192cb5fe245SEnji Cooper 193cb5fe245SEnji Cooper test_begin(test_id); 194cb5fe245SEnji Cooper 195cb5fe245SEnji Cooper test_no_kevents(); 196cb5fe245SEnji Cooper 197cb5fe245SEnji Cooper /* Add the watch and immediately disable it */ 198cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL); 199cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 200cb5fe245SEnji Cooper err(1, "%s", test_id); 201cb5fe245SEnji Cooper kev.flags = EV_DISABLE; 202cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 203cb5fe245SEnji Cooper err(1, "%s", test_id); 204cb5fe245SEnji Cooper test_no_kevents(); 205cb5fe245SEnji Cooper 206cb5fe245SEnji Cooper /* Re-enable and check again */ 207cb5fe245SEnji Cooper kev.flags = EV_ENABLE; 208cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 209cb5fe245SEnji Cooper err(1, "%s", test_id); 210cb5fe245SEnji Cooper 211cb5fe245SEnji Cooper kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 212cb5fe245SEnji Cooper kev.data = 1; 213cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 214cb5fe245SEnji Cooper 215cb5fe245SEnji Cooper success(); 216cb5fe245SEnji Cooper } 217cb5fe245SEnji Cooper 2182b34e843SKonstantin Belousov static void 2192b34e843SKonstantin Belousov test_abstime(void) 2202b34e843SKonstantin Belousov { 2212b34e843SKonstantin Belousov const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)"; 2222b34e843SKonstantin Belousov struct kevent kev; 2232b34e843SKonstantin Belousov time_t when; 2242b34e843SKonstantin Belousov const int timeout = 3; 2252b34e843SKonstantin Belousov 2262b34e843SKonstantin Belousov test_begin(test_id); 2272b34e843SKonstantin Belousov 2282b34e843SKonstantin Belousov test_no_kevents(); 2292b34e843SKonstantin Belousov 2302b34e843SKonstantin Belousov when = time(NULL); 2312b34e843SKonstantin Belousov EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 2322b34e843SKonstantin Belousov NOTE_ABSTIME | NOTE_SECONDS, when + timeout, NULL); 2332b34e843SKonstantin Belousov if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 2342b34e843SKonstantin Belousov err(1, "%s", test_id); 2352b34e843SKonstantin Belousov 2362b34e843SKonstantin Belousov /* Retrieve the event */ 2372b34e843SKonstantin Belousov kev.flags = EV_ADD | EV_ONESHOT; 2382b34e843SKonstantin Belousov kev.data = 1; 2392b34e843SKonstantin Belousov kev.fflags = 0; 2402b34e843SKonstantin Belousov kevent_cmp(&kev, kevent_get(kqfd)); 2412b34e843SKonstantin Belousov if (time(NULL) < when + timeout) 242*95c05062SDavid Bright err(1, "too early %jd %jd", time(NULL), when + timeout); 2432b34e843SKonstantin Belousov 2442b34e843SKonstantin Belousov /* Check if the event occurs again */ 2452b34e843SKonstantin Belousov sleep(3); 2462b34e843SKonstantin Belousov test_no_kevents(); 2472b34e843SKonstantin Belousov 2482b34e843SKonstantin Belousov success(); 2492b34e843SKonstantin Belousov } 2502b34e843SKonstantin Belousov 251*95c05062SDavid Bright static void 252*95c05062SDavid Bright test_update(void) 253*95c05062SDavid Bright { 254*95c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)"; 255*95c05062SDavid Bright struct kevent kev; 256*95c05062SDavid Bright long elapsed; 257*95c05062SDavid Bright long start; 258*95c05062SDavid Bright 259*95c05062SDavid Bright test_begin(test_id); 260*95c05062SDavid Bright 261*95c05062SDavid Bright test_no_kevents(); 262*95c05062SDavid Bright 263*95c05062SDavid Bright /* First set the timer to 1 second */ 264*95c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 265*95c05062SDavid Bright NOTE_USECONDS, SEC_TO_US(1), (void *)1); 266*95c05062SDavid Bright start = now(); 267*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 268*95c05062SDavid Bright err(1, "%s", test_id); 269*95c05062SDavid Bright 270*95c05062SDavid Bright /* Now reduce the timer to 1 ms */ 271*95c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 272*95c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), (void *)2); 273*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 274*95c05062SDavid Bright err(1, "%s", test_id); 275*95c05062SDavid Bright 276*95c05062SDavid Bright /* Wait for the event */ 277*95c05062SDavid Bright kev.flags |= EV_CLEAR; 278*95c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 279*95c05062SDavid Bright kev.data = 1; 280*95c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 281*95c05062SDavid Bright elapsed = now() - start; 282*95c05062SDavid Bright 283*95c05062SDavid Bright /* Check that the timer expired after at least 1 ms, but less than 284*95c05062SDavid Bright * 1 second. This check is to make sure that the original 1 second 285*95c05062SDavid Bright * timeout was not used. 286*95c05062SDavid Bright */ 287*95c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 288*95c05062SDavid Bright if (elapsed < MS_TO_US(1)) 289*95c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 290*95c05062SDavid Bright if (elapsed > SEC_TO_US(1)) 291*95c05062SDavid Bright errx(1, "late timer expiration: %ld us", elapsed); 292*95c05062SDavid Bright 293*95c05062SDavid Bright success(); 294*95c05062SDavid Bright } 295*95c05062SDavid Bright 296*95c05062SDavid Bright static void 297*95c05062SDavid Bright test_update_equal(void) 298*95c05062SDavid Bright { 299*95c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)"; 300*95c05062SDavid Bright struct kevent kev; 301*95c05062SDavid Bright long elapsed; 302*95c05062SDavid Bright long start; 303*95c05062SDavid Bright 304*95c05062SDavid Bright test_begin(test_id); 305*95c05062SDavid Bright 306*95c05062SDavid Bright test_no_kevents(); 307*95c05062SDavid Bright 308*95c05062SDavid Bright /* First set the timer to 1 ms */ 309*95c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 310*95c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL); 311*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 312*95c05062SDavid Bright err(1, "%s", test_id); 313*95c05062SDavid Bright 314*95c05062SDavid Bright /* Sleep for a significant fraction of the timeout. */ 315*95c05062SDavid Bright ussleep(600); 316*95c05062SDavid Bright 317*95c05062SDavid Bright /* Now re-add the timer with the same parameters */ 318*95c05062SDavid Bright start = now(); 319*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 320*95c05062SDavid Bright err(1, "%s", test_id); 321*95c05062SDavid Bright 322*95c05062SDavid Bright /* Wait for the event */ 323*95c05062SDavid Bright kev.flags |= EV_CLEAR; 324*95c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 325*95c05062SDavid Bright kev.data = 1; 326*95c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 327*95c05062SDavid Bright elapsed = now() - start; 328*95c05062SDavid Bright 329*95c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This check is 330*95c05062SDavid Bright * to make sure that the timer re-started and that the event is 331*95c05062SDavid Bright * not from the original add of the timer. 332*95c05062SDavid Bright */ 333*95c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 334*95c05062SDavid Bright if (elapsed < MS_TO_US(1)) 335*95c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 336*95c05062SDavid Bright 337*95c05062SDavid Bright success(); 338*95c05062SDavid Bright } 339*95c05062SDavid Bright 340*95c05062SDavid Bright static void 341*95c05062SDavid Bright test_update_expired(void) 342*95c05062SDavid Bright { 343*95c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)"; 344*95c05062SDavid Bright struct kevent kev; 345*95c05062SDavid Bright long elapsed; 346*95c05062SDavid Bright long start; 347*95c05062SDavid Bright 348*95c05062SDavid Bright test_begin(test_id); 349*95c05062SDavid Bright 350*95c05062SDavid Bright test_no_kevents(); 351*95c05062SDavid Bright 352*95c05062SDavid Bright /* Set the timer to 1ms */ 353*95c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 354*95c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL); 355*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 356*95c05062SDavid Bright err(1, "%s", test_id); 357*95c05062SDavid Bright 358*95c05062SDavid Bright /* Wait for 2 ms to give the timer plenty of time to expire. */ 359*95c05062SDavid Bright mssleep(2); 360*95c05062SDavid Bright 361*95c05062SDavid Bright /* Now re-add the timer */ 362*95c05062SDavid Bright start = now(); 363*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 364*95c05062SDavid Bright err(1, "%s", test_id); 365*95c05062SDavid Bright 366*95c05062SDavid Bright /* Wait for the event */ 367*95c05062SDavid Bright kev.flags |= EV_CLEAR; 368*95c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 369*95c05062SDavid Bright kev.data = 1; 370*95c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 371*95c05062SDavid Bright elapsed = now() - start; 372*95c05062SDavid Bright 373*95c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This check 374*95c05062SDavid Bright * is to make sure that the timer re-started and that the event is 375*95c05062SDavid Bright * not from the original add (and expiration) of the timer. 376*95c05062SDavid Bright */ 377*95c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 378*95c05062SDavid Bright if (elapsed < MS_TO_US(1)) 379*95c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 380*95c05062SDavid Bright 381*95c05062SDavid Bright /* Make sure the re-added timer does not fire. In other words, 382*95c05062SDavid Bright * test that the event received above was the only event from the 383*95c05062SDavid Bright * add and re-add of the timer. 384*95c05062SDavid Bright */ 385*95c05062SDavid Bright mssleep(2); 386*95c05062SDavid Bright test_no_kevents(); 387*95c05062SDavid Bright 388*95c05062SDavid Bright success(); 389*95c05062SDavid Bright } 390*95c05062SDavid Bright 391*95c05062SDavid Bright static void 392*95c05062SDavid Bright test_update_periodic(void) 393*95c05062SDavid Bright { 394*95c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)"; 395*95c05062SDavid Bright struct kevent kev; 396*95c05062SDavid Bright long elapsed; 397*95c05062SDavid Bright long start; 398*95c05062SDavid Bright long stop; 399*95c05062SDavid Bright 400*95c05062SDavid Bright test_begin(test_id); 401*95c05062SDavid Bright 402*95c05062SDavid Bright test_no_kevents(); 403*95c05062SDavid Bright 404*95c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL); 405*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 406*95c05062SDavid Bright err(1, "%s", test_id); 407*95c05062SDavid Bright 408*95c05062SDavid Bright /* Retrieve the event */ 409*95c05062SDavid Bright kev.flags = EV_ADD | EV_CLEAR; 410*95c05062SDavid Bright kev.data = 1; 411*95c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 412*95c05062SDavid Bright 413*95c05062SDavid Bright /* Check if the event occurs again */ 414*95c05062SDavid Bright sleep(1); 415*95c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 416*95c05062SDavid Bright 417*95c05062SDavid Bright /* Re-add with new timeout. */ 418*95c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL); 419*95c05062SDavid Bright start = now(); 420*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 421*95c05062SDavid Bright err(1, "%s", test_id); 422*95c05062SDavid Bright 423*95c05062SDavid Bright /* Retrieve the event */ 424*95c05062SDavid Bright kev.flags = EV_ADD | EV_CLEAR; 425*95c05062SDavid Bright kev.data = 1; 426*95c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 427*95c05062SDavid Bright 428*95c05062SDavid Bright stop = now(); 429*95c05062SDavid Bright elapsed = stop - start; 430*95c05062SDavid Bright 431*95c05062SDavid Bright /* Check that the timer expired after at least 2 ms. 432*95c05062SDavid Bright */ 433*95c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 434*95c05062SDavid Bright if (elapsed < MS_TO_US(2)) 435*95c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 436*95c05062SDavid Bright 437*95c05062SDavid Bright /* Delete the event */ 438*95c05062SDavid Bright kev.flags = EV_DELETE; 439*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 440*95c05062SDavid Bright err(1, "%s", test_id); 441*95c05062SDavid Bright 442*95c05062SDavid Bright success(); 443*95c05062SDavid Bright } 444*95c05062SDavid Bright 445*95c05062SDavid Bright static void 446*95c05062SDavid Bright test_update_timing(void) 447*95c05062SDavid Bright { 448*95c05062SDavid Bright #define MIN_SLEEP 500 449*95c05062SDavid Bright #define MAX_SLEEP 1500 450*95c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)"; 451*95c05062SDavid Bright struct kevent kev; 452*95c05062SDavid Bright int iteration; 453*95c05062SDavid Bright int sleeptime; 454*95c05062SDavid Bright long elapsed; 455*95c05062SDavid Bright long start; 456*95c05062SDavid Bright long stop; 457*95c05062SDavid Bright 458*95c05062SDavid Bright test_begin(test_id); 459*95c05062SDavid Bright 460*95c05062SDavid Bright test_no_kevents(); 461*95c05062SDavid Bright 462*95c05062SDavid Bright /* Re-try the update tests with a variety of delays between the 463*95c05062SDavid Bright * original timer activation and the update of the timer. The goal 464*95c05062SDavid Bright * is to show that in all cases the only timer event that is 465*95c05062SDavid Bright * received is from the update and not the original timer add. 466*95c05062SDavid Bright */ 467*95c05062SDavid Bright for (sleeptime = MIN_SLEEP, iteration = 1; 468*95c05062SDavid Bright sleeptime < MAX_SLEEP; 469*95c05062SDavid Bright ++sleeptime, ++iteration) { 470*95c05062SDavid Bright 471*95c05062SDavid Bright /* First set the timer to 1 ms */ 472*95c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 473*95c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL); 474*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 475*95c05062SDavid Bright err(1, "%s", test_id); 476*95c05062SDavid Bright 477*95c05062SDavid Bright /* Delay; the delay ranges from less than to greater than the 478*95c05062SDavid Bright * timer period. 479*95c05062SDavid Bright */ 480*95c05062SDavid Bright ussleep(sleeptime); 481*95c05062SDavid Bright 482*95c05062SDavid Bright /* Now re-add the timer with the same parameters */ 483*95c05062SDavid Bright start = now(); 484*95c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 485*95c05062SDavid Bright err(1, "%s", test_id); 486*95c05062SDavid Bright 487*95c05062SDavid Bright /* Wait for the event */ 488*95c05062SDavid Bright kev.flags |= EV_CLEAR; 489*95c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 490*95c05062SDavid Bright kev.data = 1; 491*95c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 492*95c05062SDavid Bright stop = now(); 493*95c05062SDavid Bright elapsed = stop - start; 494*95c05062SDavid Bright 495*95c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This 496*95c05062SDavid Bright * check is to make sure that the timer re-started and that 497*95c05062SDavid Bright * the event is not from the original add of the timer. 498*95c05062SDavid Bright */ 499*95c05062SDavid Bright if (elapsed < MS_TO_US(1)) 500*95c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 501*95c05062SDavid Bright 502*95c05062SDavid Bright /* Make sure the re-added timer does not fire. In other words, 503*95c05062SDavid Bright * test that the event received above was the only event from 504*95c05062SDavid Bright * the add and re-add of the timer. 505*95c05062SDavid Bright */ 506*95c05062SDavid Bright mssleep(2); 507*95c05062SDavid Bright test_no_kevents_quietly(); 508*95c05062SDavid Bright } 509*95c05062SDavid Bright 510*95c05062SDavid Bright success(); 511*95c05062SDavid Bright } 512*95c05062SDavid Bright 513cb5fe245SEnji Cooper void 514cb5fe245SEnji Cooper test_evfilt_timer() 515cb5fe245SEnji Cooper { 516cb5fe245SEnji Cooper kqfd = kqueue(); 517cb5fe245SEnji Cooper test_kevent_timer_add(); 518cb5fe245SEnji Cooper test_kevent_timer_del(); 519cb5fe245SEnji Cooper test_kevent_timer_get(); 520cb5fe245SEnji Cooper test_oneshot(); 521cb5fe245SEnji Cooper test_periodic(); 5222b34e843SKonstantin Belousov test_abstime(); 523*95c05062SDavid Bright test_update(); 524*95c05062SDavid Bright test_update_equal(); 525*95c05062SDavid Bright test_update_expired(); 526*95c05062SDavid Bright test_update_timing(); 527*95c05062SDavid Bright test_update_periodic(); 528cb5fe245SEnji Cooper disable_and_enable(); 529cb5fe245SEnji Cooper close(kqfd); 530cb5fe245SEnji Cooper } 531