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 2295c05062SDavid Bright #define MILLION 1000000 2395c05062SDavid Bright #define THOUSAND 1000 2495c05062SDavid Bright #define SEC_TO_MS(t) ((t) * THOUSAND) /* Convert seconds to milliseconds. */ 2595c05062SDavid Bright #define SEC_TO_US(t) ((t) * MILLION) /* Convert seconds to microseconds. */ 2695c05062SDavid Bright #define MS_TO_US(t) ((t) * THOUSAND) /* Convert milliseconds to microseconds. */ 2795c05062SDavid Bright #define US_TO_NS(t) ((t) * THOUSAND) /* Convert microseconds to nanoseconds. */ 2895c05062SDavid Bright 29cb5fe245SEnji Cooper 3095c05062SDavid Bright /* Get the current time with microsecond precision. Used for 3195c05062SDavid Bright * sub-second timing to make some timer tests run faster. 3295c05062SDavid Bright */ 330fbdc372SKyle Evans static uint64_t 3495c05062SDavid Bright now(void) 3595c05062SDavid Bright { 3695c05062SDavid Bright struct timeval tv; 3795c05062SDavid Bright 3895c05062SDavid Bright gettimeofday(&tv, NULL); 390fbdc372SKyle Evans /* Promote potentially 32-bit time_t to uint64_t before conversion. */ 400fbdc372SKyle Evans return SEC_TO_US((uint64_t)tv.tv_sec) + tv.tv_usec; 4195c05062SDavid Bright } 4295c05062SDavid Bright 4395c05062SDavid Bright /* Sleep for a given number of milliseconds. The timeout is assumed to 4495c05062SDavid Bright * be less than 1 second. 4595c05062SDavid Bright */ 46c9c283bdSAlex Richardson static void 4795c05062SDavid Bright mssleep(int t) 4895c05062SDavid Bright { 4995c05062SDavid Bright struct timespec stime = { 5095c05062SDavid Bright .tv_sec = 0, 5195c05062SDavid Bright .tv_nsec = US_TO_NS(MS_TO_US(t)), 5295c05062SDavid Bright }; 5395c05062SDavid Bright 5495c05062SDavid Bright nanosleep(&stime, NULL); 5595c05062SDavid Bright } 5695c05062SDavid Bright 5795c05062SDavid Bright /* Sleep for a given number of microseconds. The timeout is assumed to 5895c05062SDavid Bright * be less than 1 second. 5995c05062SDavid Bright */ 60c9c283bdSAlex Richardson static void 6195c05062SDavid Bright ussleep(int t) 6295c05062SDavid Bright { 6395c05062SDavid Bright struct timespec stime = { 6495c05062SDavid Bright .tv_sec = 0, 6595c05062SDavid Bright .tv_nsec = US_TO_NS(t), 6695c05062SDavid Bright }; 6795c05062SDavid Bright 6895c05062SDavid Bright nanosleep(&stime, NULL); 6995c05062SDavid Bright } 7095c05062SDavid Bright 71c9c283bdSAlex Richardson static void 72cb5fe245SEnji Cooper test_kevent_timer_add(void) 73cb5fe245SEnji Cooper { 74cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)"; 75cb5fe245SEnji Cooper struct kevent kev; 76cb5fe245SEnji Cooper 77cb5fe245SEnji Cooper test_begin(test_id); 78cb5fe245SEnji Cooper 79cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 80cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 81cb5fe245SEnji Cooper err(1, "%s", test_id); 82cb5fe245SEnji Cooper 83cb5fe245SEnji Cooper success(); 84cb5fe245SEnji Cooper } 85cb5fe245SEnji Cooper 86c9c283bdSAlex Richardson static void 87cb5fe245SEnji Cooper test_kevent_timer_del(void) 88cb5fe245SEnji Cooper { 89cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)"; 90cb5fe245SEnji Cooper struct kevent kev; 91cb5fe245SEnji Cooper 92cb5fe245SEnji Cooper test_begin(test_id); 93cb5fe245SEnji Cooper 94cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 95cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 96cb5fe245SEnji Cooper err(1, "%s", test_id); 97cb5fe245SEnji Cooper 98cb5fe245SEnji Cooper test_no_kevents(); 99cb5fe245SEnji Cooper 100cb5fe245SEnji Cooper success(); 101cb5fe245SEnji Cooper } 102cb5fe245SEnji Cooper 103c9c283bdSAlex Richardson static void 104cb5fe245SEnji Cooper test_kevent_timer_get(void) 105cb5fe245SEnji Cooper { 106cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, wait)"; 107cb5fe245SEnji Cooper struct kevent kev; 108cb5fe245SEnji Cooper 109cb5fe245SEnji Cooper test_begin(test_id); 110cb5fe245SEnji Cooper 111cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 112cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 113cb5fe245SEnji Cooper err(1, "%s", test_id); 114cb5fe245SEnji Cooper 115cb5fe245SEnji Cooper kev.flags |= EV_CLEAR; 116cb5fe245SEnji Cooper kev.data = 1; 117cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 118cb5fe245SEnji Cooper 119cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 120cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 121cb5fe245SEnji Cooper err(1, "%s", test_id); 122cb5fe245SEnji Cooper 123cb5fe245SEnji Cooper success(); 124cb5fe245SEnji Cooper } 125cb5fe245SEnji Cooper 126cb5fe245SEnji Cooper static void 127cb5fe245SEnji Cooper test_oneshot(void) 128cb5fe245SEnji Cooper { 129cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)"; 130cb5fe245SEnji Cooper struct kevent kev; 131cb5fe245SEnji Cooper 132cb5fe245SEnji Cooper test_begin(test_id); 133cb5fe245SEnji Cooper 134cb5fe245SEnji Cooper test_no_kevents(); 135cb5fe245SEnji Cooper 136cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL); 137cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 138cb5fe245SEnji Cooper err(1, "%s", test_id); 139cb5fe245SEnji Cooper 140cb5fe245SEnji Cooper /* Retrieve the event */ 141cb5fe245SEnji Cooper kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 142cb5fe245SEnji Cooper kev.data = 1; 143cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 144cb5fe245SEnji Cooper 145cb5fe245SEnji Cooper /* Check if the event occurs again */ 146cb5fe245SEnji Cooper sleep(3); 147cb5fe245SEnji Cooper test_no_kevents(); 148cb5fe245SEnji Cooper 149cb5fe245SEnji Cooper 150cb5fe245SEnji Cooper success(); 151cb5fe245SEnji Cooper } 152cb5fe245SEnji Cooper 153cb5fe245SEnji Cooper static void 154cb5fe245SEnji Cooper test_periodic(void) 155cb5fe245SEnji Cooper { 156cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, periodic)"; 157cb5fe245SEnji Cooper struct kevent kev; 158cb5fe245SEnji Cooper 159cb5fe245SEnji Cooper test_begin(test_id); 160cb5fe245SEnji Cooper 161cb5fe245SEnji Cooper test_no_kevents(); 162cb5fe245SEnji Cooper 163cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL); 164cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 165cb5fe245SEnji Cooper err(1, "%s", test_id); 166cb5fe245SEnji Cooper 167cb5fe245SEnji Cooper /* Retrieve the event */ 168cb5fe245SEnji Cooper kev.flags = EV_ADD | EV_CLEAR; 169cb5fe245SEnji Cooper kev.data = 1; 170cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 171cb5fe245SEnji Cooper 172cb5fe245SEnji Cooper /* Check if the event occurs again */ 173cb5fe245SEnji Cooper sleep(1); 174cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 175cb5fe245SEnji Cooper 176cb5fe245SEnji Cooper /* Delete the event */ 177cb5fe245SEnji Cooper kev.flags = EV_DELETE; 178cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 179cb5fe245SEnji Cooper err(1, "%s", test_id); 180cb5fe245SEnji Cooper 181cb5fe245SEnji Cooper success(); 182cb5fe245SEnji Cooper } 183cb5fe245SEnji Cooper 184cb5fe245SEnji Cooper static void 185cb5fe245SEnji Cooper disable_and_enable(void) 186cb5fe245SEnji Cooper { 187cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)"; 188cb5fe245SEnji Cooper struct kevent kev; 189cb5fe245SEnji Cooper 190cb5fe245SEnji Cooper test_begin(test_id); 191cb5fe245SEnji Cooper 192cb5fe245SEnji Cooper test_no_kevents(); 193cb5fe245SEnji Cooper 194cb5fe245SEnji Cooper /* Add the watch and immediately disable it */ 195cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL); 196cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 197cb5fe245SEnji Cooper err(1, "%s", test_id); 198cb5fe245SEnji Cooper kev.flags = EV_DISABLE; 199cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 200cb5fe245SEnji Cooper err(1, "%s", test_id); 201cb5fe245SEnji Cooper test_no_kevents(); 202cb5fe245SEnji Cooper 203cb5fe245SEnji Cooper /* Re-enable and check again */ 204cb5fe245SEnji Cooper kev.flags = EV_ENABLE; 205cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 206cb5fe245SEnji Cooper err(1, "%s", test_id); 207cb5fe245SEnji Cooper 208cb5fe245SEnji Cooper kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 209cb5fe245SEnji Cooper kev.data = 1; 210cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 211cb5fe245SEnji Cooper 212cb5fe245SEnji Cooper success(); 213cb5fe245SEnji Cooper } 214cb5fe245SEnji Cooper 2152b34e843SKonstantin Belousov static void 2162b34e843SKonstantin Belousov test_abstime(void) 2172b34e843SKonstantin Belousov { 2182b34e843SKonstantin Belousov const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)"; 2192b34e843SKonstantin Belousov struct kevent kev; 2200fbdc372SKyle Evans uint64_t end, start, stop; 221c17dd0e8SKyle Evans const int timeout_sec = 3; 2222b34e843SKonstantin Belousov 2232b34e843SKonstantin Belousov test_begin(test_id); 2242b34e843SKonstantin Belousov 2252b34e843SKonstantin Belousov test_no_kevents(); 2262b34e843SKonstantin Belousov 227c17dd0e8SKyle Evans start = now(); 228c17dd0e8SKyle Evans end = start + SEC_TO_US(timeout_sec); 2292b34e843SKonstantin Belousov EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 230c17dd0e8SKyle Evans NOTE_ABSTIME | NOTE_USECONDS, end, NULL); 2312b34e843SKonstantin Belousov if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 2322b34e843SKonstantin Belousov err(1, "%s", test_id); 2332b34e843SKonstantin Belousov 2342b34e843SKonstantin Belousov /* Retrieve the event */ 2352b34e843SKonstantin Belousov kev.flags = EV_ADD | EV_ONESHOT; 2362b34e843SKonstantin Belousov kev.data = 1; 2372b34e843SKonstantin Belousov kev.fflags = 0; 2382b34e843SKonstantin Belousov kevent_cmp(&kev, kevent_get(kqfd)); 2392b34e843SKonstantin Belousov 240c17dd0e8SKyle Evans stop = now(); 241c17dd0e8SKyle Evans if (stop < end) 242c17dd0e8SKyle Evans err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end); 2432b34e843SKonstantin Belousov /* Check if the event occurs again */ 2442b34e843SKonstantin Belousov sleep(3); 2452b34e843SKonstantin Belousov test_no_kevents(); 2462b34e843SKonstantin Belousov 2472b34e843SKonstantin Belousov success(); 2482b34e843SKonstantin Belousov } 2492b34e843SKonstantin Belousov 25095c05062SDavid Bright static void 251*9c999a25SKyle Evans test_abstime_preboot(void) 252*9c999a25SKyle Evans { 253*9c999a25SKyle Evans const char *test_id = "kevent(EVFILT_TIMER (PREBOOT), EV_ONESHOT, NOTE_ABSTIME)"; 254*9c999a25SKyle Evans struct kevent kev; 255*9c999a25SKyle Evans struct timespec btp; 256*9c999a25SKyle Evans uint64_t end, start, stop; 257*9c999a25SKyle Evans 258*9c999a25SKyle Evans test_begin(test_id); 259*9c999a25SKyle Evans 260*9c999a25SKyle Evans test_no_kevents(); 261*9c999a25SKyle Evans 262*9c999a25SKyle Evans /* 263*9c999a25SKyle Evans * We'll expire it at just before system boot (roughly) with the hope that 264*9c999a25SKyle Evans * we'll get an ~immediate expiration, just as we do for any value specified 265*9c999a25SKyle Evans * between system boot and now. 266*9c999a25SKyle Evans */ 267*9c999a25SKyle Evans start = now(); 268*9c999a25SKyle Evans if (clock_gettime(CLOCK_BOOTTIME, &btp) != 0) 269*9c999a25SKyle Evans err(1, "%s", test_id); 270*9c999a25SKyle Evans 271*9c999a25SKyle Evans end = start - SEC_TO_US(btp.tv_sec + 1); 272*9c999a25SKyle Evans EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 273*9c999a25SKyle Evans NOTE_ABSTIME | NOTE_USECONDS, end, NULL); 274*9c999a25SKyle Evans if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 275*9c999a25SKyle Evans err(1, "%s", test_id); 276*9c999a25SKyle Evans 277*9c999a25SKyle Evans /* Retrieve the event */ 278*9c999a25SKyle Evans kev.flags = EV_ADD | EV_ONESHOT; 279*9c999a25SKyle Evans kev.data = 1; 280*9c999a25SKyle Evans kev.fflags = 0; 281*9c999a25SKyle Evans kevent_cmp(&kev, kevent_get(kqfd)); 282*9c999a25SKyle Evans 283*9c999a25SKyle Evans stop = now(); 284*9c999a25SKyle Evans if (stop < end) 285*9c999a25SKyle Evans err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end); 286*9c999a25SKyle Evans /* Check if the event occurs again */ 287*9c999a25SKyle Evans sleep(3); 288*9c999a25SKyle Evans test_no_kevents(); 289*9c999a25SKyle Evans 290*9c999a25SKyle Evans success(); 291*9c999a25SKyle Evans } 292*9c999a25SKyle Evans 293*9c999a25SKyle Evans static void 294*9c999a25SKyle Evans test_abstime_postboot(void) 295*9c999a25SKyle Evans { 296*9c999a25SKyle Evans const char *test_id = "kevent(EVFILT_TIMER (POSTBOOT), EV_ONESHOT, NOTE_ABSTIME)"; 297*9c999a25SKyle Evans struct kevent kev; 298*9c999a25SKyle Evans uint64_t end, start, stop; 299*9c999a25SKyle Evans const int timeout_sec = 1; 300*9c999a25SKyle Evans 301*9c999a25SKyle Evans test_begin(test_id); 302*9c999a25SKyle Evans 303*9c999a25SKyle Evans test_no_kevents(); 304*9c999a25SKyle Evans 305*9c999a25SKyle Evans /* 306*9c999a25SKyle Evans * Set a timer for 1 second ago, it should fire immediately rather than 307*9c999a25SKyle Evans * being rejected. 308*9c999a25SKyle Evans */ 309*9c999a25SKyle Evans start = now(); 310*9c999a25SKyle Evans end = start - SEC_TO_US(timeout_sec); 311*9c999a25SKyle Evans EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 312*9c999a25SKyle Evans NOTE_ABSTIME | NOTE_USECONDS, end, NULL); 313*9c999a25SKyle Evans if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 314*9c999a25SKyle Evans err(1, "%s", test_id); 315*9c999a25SKyle Evans 316*9c999a25SKyle Evans /* Retrieve the event */ 317*9c999a25SKyle Evans kev.flags = EV_ADD | EV_ONESHOT; 318*9c999a25SKyle Evans kev.data = 1; 319*9c999a25SKyle Evans kev.fflags = 0; 320*9c999a25SKyle Evans kevent_cmp(&kev, kevent_get(kqfd)); 321*9c999a25SKyle Evans 322*9c999a25SKyle Evans stop = now(); 323*9c999a25SKyle Evans if (stop < end) 324*9c999a25SKyle Evans err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end); 325*9c999a25SKyle Evans /* Check if the event occurs again */ 326*9c999a25SKyle Evans sleep(3); 327*9c999a25SKyle Evans test_no_kevents(); 328*9c999a25SKyle Evans 329*9c999a25SKyle Evans success(); 330*9c999a25SKyle Evans } 331*9c999a25SKyle Evans 332*9c999a25SKyle Evans static void 33395c05062SDavid Bright test_update(void) 33495c05062SDavid Bright { 33595c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)"; 33695c05062SDavid Bright struct kevent kev; 33795c05062SDavid Bright long elapsed; 3380fbdc372SKyle Evans uint64_t start; 33995c05062SDavid Bright 34095c05062SDavid Bright test_begin(test_id); 34195c05062SDavid Bright 34295c05062SDavid Bright test_no_kevents(); 34395c05062SDavid Bright 34495c05062SDavid Bright /* First set the timer to 1 second */ 34595c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 34695c05062SDavid Bright NOTE_USECONDS, SEC_TO_US(1), (void *)1); 34795c05062SDavid Bright start = now(); 34895c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 34995c05062SDavid Bright err(1, "%s", test_id); 35095c05062SDavid Bright 35195c05062SDavid Bright /* Now reduce the timer to 1 ms */ 35295c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 35395c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), (void *)2); 35495c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 35595c05062SDavid Bright err(1, "%s", test_id); 35695c05062SDavid Bright 35795c05062SDavid Bright /* Wait for the event */ 35895c05062SDavid Bright kev.flags |= EV_CLEAR; 35995c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 36095c05062SDavid Bright kev.data = 1; 36195c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 36295c05062SDavid Bright elapsed = now() - start; 36395c05062SDavid Bright 36495c05062SDavid Bright /* Check that the timer expired after at least 1 ms, but less than 36595c05062SDavid Bright * 1 second. This check is to make sure that the original 1 second 36695c05062SDavid Bright * timeout was not used. 36795c05062SDavid Bright */ 36895c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 36995c05062SDavid Bright if (elapsed < MS_TO_US(1)) 37095c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 37195c05062SDavid Bright if (elapsed > SEC_TO_US(1)) 37295c05062SDavid Bright errx(1, "late timer expiration: %ld us", elapsed); 37395c05062SDavid Bright 37495c05062SDavid Bright success(); 37595c05062SDavid Bright } 37695c05062SDavid Bright 37795c05062SDavid Bright static void 37895c05062SDavid Bright test_update_equal(void) 37995c05062SDavid Bright { 38095c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)"; 38195c05062SDavid Bright struct kevent kev; 38295c05062SDavid Bright long elapsed; 3830fbdc372SKyle Evans uint64_t start; 38495c05062SDavid Bright 38595c05062SDavid Bright test_begin(test_id); 38695c05062SDavid Bright 38795c05062SDavid Bright test_no_kevents(); 38895c05062SDavid Bright 38995c05062SDavid Bright /* First set the timer to 1 ms */ 39095c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 39195c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL); 39295c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 39395c05062SDavid Bright err(1, "%s", test_id); 39495c05062SDavid Bright 39595c05062SDavid Bright /* Sleep for a significant fraction of the timeout. */ 39695c05062SDavid Bright ussleep(600); 39795c05062SDavid Bright 39895c05062SDavid Bright /* Now re-add the timer with the same parameters */ 39995c05062SDavid Bright start = now(); 40095c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 40195c05062SDavid Bright err(1, "%s", test_id); 40295c05062SDavid Bright 40395c05062SDavid Bright /* Wait for the event */ 40495c05062SDavid Bright kev.flags |= EV_CLEAR; 40595c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 40695c05062SDavid Bright kev.data = 1; 40795c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 40895c05062SDavid Bright elapsed = now() - start; 40995c05062SDavid Bright 41095c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This check is 41195c05062SDavid Bright * to make sure that the timer re-started and that the event is 41295c05062SDavid Bright * not from the original add of the timer. 41395c05062SDavid Bright */ 41495c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 41595c05062SDavid Bright if (elapsed < MS_TO_US(1)) 41695c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 41795c05062SDavid Bright 41895c05062SDavid Bright success(); 41995c05062SDavid Bright } 42095c05062SDavid Bright 42195c05062SDavid Bright static void 42295c05062SDavid Bright test_update_expired(void) 42395c05062SDavid Bright { 42495c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)"; 42595c05062SDavid Bright struct kevent kev; 42695c05062SDavid Bright long elapsed; 4270fbdc372SKyle Evans uint64_t start; 42895c05062SDavid Bright 42995c05062SDavid Bright test_begin(test_id); 43095c05062SDavid Bright 43195c05062SDavid Bright test_no_kevents(); 43295c05062SDavid Bright 43395c05062SDavid Bright /* Set the timer to 1ms */ 43495c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 43595c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL); 43695c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 43795c05062SDavid Bright err(1, "%s", test_id); 43895c05062SDavid Bright 43995c05062SDavid Bright /* Wait for 2 ms to give the timer plenty of time to expire. */ 44095c05062SDavid Bright mssleep(2); 44195c05062SDavid Bright 44295c05062SDavid Bright /* Now re-add the timer */ 44395c05062SDavid Bright start = now(); 44495c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 44595c05062SDavid Bright err(1, "%s", test_id); 44695c05062SDavid Bright 44795c05062SDavid Bright /* Wait for the event */ 44895c05062SDavid Bright kev.flags |= EV_CLEAR; 44995c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 45095c05062SDavid Bright kev.data = 1; 45195c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 45295c05062SDavid Bright elapsed = now() - start; 45395c05062SDavid Bright 45495c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This check 45595c05062SDavid Bright * is to make sure that the timer re-started and that the event is 45695c05062SDavid Bright * not from the original add (and expiration) of the timer. 45795c05062SDavid Bright */ 45895c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 45995c05062SDavid Bright if (elapsed < MS_TO_US(1)) 46095c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 46195c05062SDavid Bright 46295c05062SDavid Bright /* Make sure the re-added timer does not fire. In other words, 46395c05062SDavid Bright * test that the event received above was the only event from the 46495c05062SDavid Bright * add and re-add of the timer. 46595c05062SDavid Bright */ 46695c05062SDavid Bright mssleep(2); 46795c05062SDavid Bright test_no_kevents(); 46895c05062SDavid Bright 46995c05062SDavid Bright success(); 47095c05062SDavid Bright } 47195c05062SDavid Bright 47295c05062SDavid Bright static void 47395c05062SDavid Bright test_update_periodic(void) 47495c05062SDavid Bright { 47595c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)"; 47695c05062SDavid Bright struct kevent kev; 47795c05062SDavid Bright long elapsed; 4780fbdc372SKyle Evans uint64_t start, stop; 47995c05062SDavid Bright 48095c05062SDavid Bright test_begin(test_id); 48195c05062SDavid Bright 48295c05062SDavid Bright test_no_kevents(); 48395c05062SDavid Bright 48495c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL); 48595c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 48695c05062SDavid Bright err(1, "%s", test_id); 48795c05062SDavid Bright 48895c05062SDavid Bright /* Retrieve the event */ 48995c05062SDavid Bright kev.flags = EV_ADD | EV_CLEAR; 49095c05062SDavid Bright kev.data = 1; 49195c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 49295c05062SDavid Bright 49395c05062SDavid Bright /* Check if the event occurs again */ 49495c05062SDavid Bright sleep(1); 49595c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 49695c05062SDavid Bright 49795c05062SDavid Bright /* Re-add with new timeout. */ 49895c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL); 49995c05062SDavid Bright start = now(); 50095c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 50195c05062SDavid Bright err(1, "%s", test_id); 50295c05062SDavid Bright 50395c05062SDavid Bright /* Retrieve the event */ 50495c05062SDavid Bright kev.flags = EV_ADD | EV_CLEAR; 50595c05062SDavid Bright kev.data = 1; 50695c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 50795c05062SDavid Bright 50895c05062SDavid Bright stop = now(); 50995c05062SDavid Bright elapsed = stop - start; 51095c05062SDavid Bright 51195c05062SDavid Bright /* Check that the timer expired after at least 2 ms. 51295c05062SDavid Bright */ 51395c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 51495c05062SDavid Bright if (elapsed < MS_TO_US(2)) 51595c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 51695c05062SDavid Bright 51795c05062SDavid Bright /* Delete the event */ 51895c05062SDavid Bright kev.flags = EV_DELETE; 51995c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 52095c05062SDavid Bright err(1, "%s", test_id); 52195c05062SDavid Bright 52295c05062SDavid Bright success(); 52395c05062SDavid Bright } 52495c05062SDavid Bright 52595c05062SDavid Bright static void 52695c05062SDavid Bright test_update_timing(void) 52795c05062SDavid Bright { 52895c05062SDavid Bright #define MIN_SLEEP 500 52995c05062SDavid Bright #define MAX_SLEEP 1500 53095c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)"; 53195c05062SDavid Bright struct kevent kev; 53295c05062SDavid Bright int iteration; 53395c05062SDavid Bright int sleeptime; 53495c05062SDavid Bright long elapsed; 5350fbdc372SKyle Evans uint64_t start, stop; 53695c05062SDavid Bright 53795c05062SDavid Bright test_begin(test_id); 53895c05062SDavid Bright 53995c05062SDavid Bright test_no_kevents(); 54095c05062SDavid Bright 54195c05062SDavid Bright /* Re-try the update tests with a variety of delays between the 54295c05062SDavid Bright * original timer activation and the update of the timer. The goal 54395c05062SDavid Bright * is to show that in all cases the only timer event that is 54495c05062SDavid Bright * received is from the update and not the original timer add. 54595c05062SDavid Bright */ 54695c05062SDavid Bright for (sleeptime = MIN_SLEEP, iteration = 1; 54795c05062SDavid Bright sleeptime < MAX_SLEEP; 54895c05062SDavid Bright ++sleeptime, ++iteration) { 54995c05062SDavid Bright 55095c05062SDavid Bright /* First set the timer to 1 ms */ 55195c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 55295c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL); 55395c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 55495c05062SDavid Bright err(1, "%s", test_id); 55595c05062SDavid Bright 55695c05062SDavid Bright /* Delay; the delay ranges from less than to greater than the 55795c05062SDavid Bright * timer period. 55895c05062SDavid Bright */ 55995c05062SDavid Bright ussleep(sleeptime); 56095c05062SDavid Bright 56195c05062SDavid Bright /* Now re-add the timer with the same parameters */ 56295c05062SDavid Bright start = now(); 56395c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 56495c05062SDavid Bright err(1, "%s", test_id); 56595c05062SDavid Bright 56695c05062SDavid Bright /* Wait for the event */ 56795c05062SDavid Bright kev.flags |= EV_CLEAR; 56895c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 56995c05062SDavid Bright kev.data = 1; 57095c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 57195c05062SDavid Bright stop = now(); 57295c05062SDavid Bright elapsed = stop - start; 57395c05062SDavid Bright 57495c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This 57595c05062SDavid Bright * check is to make sure that the timer re-started and that 57695c05062SDavid Bright * the event is not from the original add of the timer. 57795c05062SDavid Bright */ 57895c05062SDavid Bright if (elapsed < MS_TO_US(1)) 57995c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 58095c05062SDavid Bright 58195c05062SDavid Bright /* Make sure the re-added timer does not fire. In other words, 58295c05062SDavid Bright * test that the event received above was the only event from 58395c05062SDavid Bright * the add and re-add of the timer. 58495c05062SDavid Bright */ 58595c05062SDavid Bright mssleep(2); 58695c05062SDavid Bright test_no_kevents_quietly(); 58795c05062SDavid Bright } 58895c05062SDavid Bright 58995c05062SDavid Bright success(); 59095c05062SDavid Bright } 59195c05062SDavid Bright 592cb5fe245SEnji Cooper void 593c9c283bdSAlex Richardson test_evfilt_timer(void) 594cb5fe245SEnji Cooper { 595cb5fe245SEnji Cooper kqfd = kqueue(); 596cb5fe245SEnji Cooper test_kevent_timer_add(); 597cb5fe245SEnji Cooper test_kevent_timer_del(); 598cb5fe245SEnji Cooper test_kevent_timer_get(); 599cb5fe245SEnji Cooper test_oneshot(); 600cb5fe245SEnji Cooper test_periodic(); 6012b34e843SKonstantin Belousov test_abstime(); 602*9c999a25SKyle Evans test_abstime_preboot(); 603*9c999a25SKyle Evans test_abstime_postboot(); 60495c05062SDavid Bright test_update(); 60595c05062SDavid Bright test_update_equal(); 60695c05062SDavid Bright test_update_expired(); 60795c05062SDavid Bright test_update_timing(); 60895c05062SDavid Bright test_update_periodic(); 609cb5fe245SEnji Cooper disable_and_enable(); 610cb5fe245SEnji Cooper close(kqfd); 611cb5fe245SEnji Cooper } 612