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 */ 3395c05062SDavid Bright static long 3495c05062SDavid Bright now(void) 3595c05062SDavid Bright { 3695c05062SDavid Bright struct timeval tv; 3795c05062SDavid Bright 3895c05062SDavid Bright gettimeofday(&tv, NULL); 3995c05062SDavid Bright return SEC_TO_US(tv.tv_sec) + tv.tv_usec; 4095c05062SDavid Bright } 4195c05062SDavid Bright 4295c05062SDavid Bright /* Sleep for a given number of milliseconds. The timeout is assumed to 4395c05062SDavid Bright * be less than 1 second. 4495c05062SDavid Bright */ 45*c9c283bdSAlex Richardson static void 4695c05062SDavid Bright mssleep(int t) 4795c05062SDavid Bright { 4895c05062SDavid Bright struct timespec stime = { 4995c05062SDavid Bright .tv_sec = 0, 5095c05062SDavid Bright .tv_nsec = US_TO_NS(MS_TO_US(t)), 5195c05062SDavid Bright }; 5295c05062SDavid Bright 5395c05062SDavid Bright nanosleep(&stime, NULL); 5495c05062SDavid Bright } 5595c05062SDavid Bright 5695c05062SDavid Bright /* Sleep for a given number of microseconds. The timeout is assumed to 5795c05062SDavid Bright * be less than 1 second. 5895c05062SDavid Bright */ 59*c9c283bdSAlex Richardson static void 6095c05062SDavid Bright ussleep(int t) 6195c05062SDavid Bright { 6295c05062SDavid Bright struct timespec stime = { 6395c05062SDavid Bright .tv_sec = 0, 6495c05062SDavid Bright .tv_nsec = US_TO_NS(t), 6595c05062SDavid Bright }; 6695c05062SDavid Bright 6795c05062SDavid Bright nanosleep(&stime, NULL); 6895c05062SDavid Bright } 6995c05062SDavid Bright 70*c9c283bdSAlex Richardson static void 71cb5fe245SEnji Cooper test_kevent_timer_add(void) 72cb5fe245SEnji Cooper { 73cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)"; 74cb5fe245SEnji Cooper struct kevent kev; 75cb5fe245SEnji Cooper 76cb5fe245SEnji Cooper test_begin(test_id); 77cb5fe245SEnji Cooper 78cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 79cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 80cb5fe245SEnji Cooper err(1, "%s", test_id); 81cb5fe245SEnji Cooper 82cb5fe245SEnji Cooper success(); 83cb5fe245SEnji Cooper } 84cb5fe245SEnji Cooper 85*c9c283bdSAlex Richardson static void 86cb5fe245SEnji Cooper test_kevent_timer_del(void) 87cb5fe245SEnji Cooper { 88cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)"; 89cb5fe245SEnji Cooper struct kevent kev; 90cb5fe245SEnji Cooper 91cb5fe245SEnji Cooper test_begin(test_id); 92cb5fe245SEnji Cooper 93cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 94cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 95cb5fe245SEnji Cooper err(1, "%s", test_id); 96cb5fe245SEnji Cooper 97cb5fe245SEnji Cooper test_no_kevents(); 98cb5fe245SEnji Cooper 99cb5fe245SEnji Cooper success(); 100cb5fe245SEnji Cooper } 101cb5fe245SEnji Cooper 102*c9c283bdSAlex Richardson static void 103cb5fe245SEnji Cooper test_kevent_timer_get(void) 104cb5fe245SEnji Cooper { 105cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, wait)"; 106cb5fe245SEnji Cooper struct kevent kev; 107cb5fe245SEnji Cooper 108cb5fe245SEnji Cooper test_begin(test_id); 109cb5fe245SEnji Cooper 110cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); 111cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 112cb5fe245SEnji Cooper err(1, "%s", test_id); 113cb5fe245SEnji Cooper 114cb5fe245SEnji Cooper kev.flags |= EV_CLEAR; 115cb5fe245SEnji Cooper kev.data = 1; 116cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 117cb5fe245SEnji Cooper 118cb5fe245SEnji Cooper EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 119cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 120cb5fe245SEnji Cooper err(1, "%s", test_id); 121cb5fe245SEnji Cooper 122cb5fe245SEnji Cooper success(); 123cb5fe245SEnji Cooper } 124cb5fe245SEnji Cooper 125cb5fe245SEnji Cooper static void 126cb5fe245SEnji Cooper test_oneshot(void) 127cb5fe245SEnji Cooper { 128cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)"; 129cb5fe245SEnji Cooper struct kevent kev; 130cb5fe245SEnji Cooper 131cb5fe245SEnji Cooper test_begin(test_id); 132cb5fe245SEnji Cooper 133cb5fe245SEnji Cooper test_no_kevents(); 134cb5fe245SEnji Cooper 135cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL); 136cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 137cb5fe245SEnji Cooper err(1, "%s", test_id); 138cb5fe245SEnji Cooper 139cb5fe245SEnji Cooper /* Retrieve the event */ 140cb5fe245SEnji Cooper kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 141cb5fe245SEnji Cooper kev.data = 1; 142cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 143cb5fe245SEnji Cooper 144cb5fe245SEnji Cooper /* Check if the event occurs again */ 145cb5fe245SEnji Cooper sleep(3); 146cb5fe245SEnji Cooper test_no_kevents(); 147cb5fe245SEnji Cooper 148cb5fe245SEnji Cooper 149cb5fe245SEnji Cooper success(); 150cb5fe245SEnji Cooper } 151cb5fe245SEnji Cooper 152cb5fe245SEnji Cooper static void 153cb5fe245SEnji Cooper test_periodic(void) 154cb5fe245SEnji Cooper { 155cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, periodic)"; 156cb5fe245SEnji Cooper struct kevent kev; 157cb5fe245SEnji Cooper 158cb5fe245SEnji Cooper test_begin(test_id); 159cb5fe245SEnji Cooper 160cb5fe245SEnji Cooper test_no_kevents(); 161cb5fe245SEnji Cooper 162cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL); 163cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 164cb5fe245SEnji Cooper err(1, "%s", test_id); 165cb5fe245SEnji Cooper 166cb5fe245SEnji Cooper /* Retrieve the event */ 167cb5fe245SEnji Cooper kev.flags = EV_ADD | EV_CLEAR; 168cb5fe245SEnji Cooper kev.data = 1; 169cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 170cb5fe245SEnji Cooper 171cb5fe245SEnji Cooper /* Check if the event occurs again */ 172cb5fe245SEnji Cooper sleep(1); 173cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 174cb5fe245SEnji Cooper 175cb5fe245SEnji Cooper /* Delete the event */ 176cb5fe245SEnji Cooper kev.flags = EV_DELETE; 177cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 178cb5fe245SEnji Cooper err(1, "%s", test_id); 179cb5fe245SEnji Cooper 180cb5fe245SEnji Cooper success(); 181cb5fe245SEnji Cooper } 182cb5fe245SEnji Cooper 183cb5fe245SEnji Cooper static void 184cb5fe245SEnji Cooper disable_and_enable(void) 185cb5fe245SEnji Cooper { 186cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)"; 187cb5fe245SEnji Cooper struct kevent kev; 188cb5fe245SEnji Cooper 189cb5fe245SEnji Cooper test_begin(test_id); 190cb5fe245SEnji Cooper 191cb5fe245SEnji Cooper test_no_kevents(); 192cb5fe245SEnji Cooper 193cb5fe245SEnji Cooper /* Add the watch and immediately disable it */ 194cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL); 195cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 196cb5fe245SEnji Cooper err(1, "%s", test_id); 197cb5fe245SEnji Cooper kev.flags = EV_DISABLE; 198cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 199cb5fe245SEnji Cooper err(1, "%s", test_id); 200cb5fe245SEnji Cooper test_no_kevents(); 201cb5fe245SEnji Cooper 202cb5fe245SEnji Cooper /* Re-enable and check again */ 203cb5fe245SEnji Cooper kev.flags = EV_ENABLE; 204cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 205cb5fe245SEnji Cooper err(1, "%s", test_id); 206cb5fe245SEnji Cooper 207cb5fe245SEnji Cooper kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; 208cb5fe245SEnji Cooper kev.data = 1; 209cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd)); 210cb5fe245SEnji Cooper 211cb5fe245SEnji Cooper success(); 212cb5fe245SEnji Cooper } 213cb5fe245SEnji Cooper 2142b34e843SKonstantin Belousov static void 2152b34e843SKonstantin Belousov test_abstime(void) 2162b34e843SKonstantin Belousov { 2172b34e843SKonstantin Belousov const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)"; 2182b34e843SKonstantin Belousov struct kevent kev; 219c17dd0e8SKyle Evans long end, start, stop; 220c17dd0e8SKyle Evans const int timeout_sec = 3; 2212b34e843SKonstantin Belousov 2222b34e843SKonstantin Belousov test_begin(test_id); 2232b34e843SKonstantin Belousov 2242b34e843SKonstantin Belousov test_no_kevents(); 2252b34e843SKonstantin Belousov 226c17dd0e8SKyle Evans start = now(); 227c17dd0e8SKyle Evans end = start + SEC_TO_US(timeout_sec); 2282b34e843SKonstantin Belousov EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 229c17dd0e8SKyle Evans NOTE_ABSTIME | NOTE_USECONDS, end, NULL); 2302b34e843SKonstantin Belousov if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 2312b34e843SKonstantin Belousov err(1, "%s", test_id); 2322b34e843SKonstantin Belousov 2332b34e843SKonstantin Belousov /* Retrieve the event */ 2342b34e843SKonstantin Belousov kev.flags = EV_ADD | EV_ONESHOT; 2352b34e843SKonstantin Belousov kev.data = 1; 2362b34e843SKonstantin Belousov kev.fflags = 0; 2372b34e843SKonstantin Belousov kevent_cmp(&kev, kevent_get(kqfd)); 2382b34e843SKonstantin Belousov 239c17dd0e8SKyle Evans stop = now(); 240c17dd0e8SKyle Evans if (stop < end) 241c17dd0e8SKyle Evans err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end); 2422b34e843SKonstantin Belousov /* Check if the event occurs again */ 2432b34e843SKonstantin Belousov sleep(3); 2442b34e843SKonstantin Belousov test_no_kevents(); 2452b34e843SKonstantin Belousov 2462b34e843SKonstantin Belousov success(); 2472b34e843SKonstantin Belousov } 2482b34e843SKonstantin Belousov 24995c05062SDavid Bright static void 25095c05062SDavid Bright test_update(void) 25195c05062SDavid Bright { 25295c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)"; 25395c05062SDavid Bright struct kevent kev; 25495c05062SDavid Bright long elapsed; 25595c05062SDavid Bright long start; 25695c05062SDavid Bright 25795c05062SDavid Bright test_begin(test_id); 25895c05062SDavid Bright 25995c05062SDavid Bright test_no_kevents(); 26095c05062SDavid Bright 26195c05062SDavid Bright /* First set the timer to 1 second */ 26295c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 26395c05062SDavid Bright NOTE_USECONDS, SEC_TO_US(1), (void *)1); 26495c05062SDavid Bright start = now(); 26595c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 26695c05062SDavid Bright err(1, "%s", test_id); 26795c05062SDavid Bright 26895c05062SDavid Bright /* Now reduce the timer to 1 ms */ 26995c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 27095c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), (void *)2); 27195c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 27295c05062SDavid Bright err(1, "%s", test_id); 27395c05062SDavid Bright 27495c05062SDavid Bright /* Wait for the event */ 27595c05062SDavid Bright kev.flags |= EV_CLEAR; 27695c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 27795c05062SDavid Bright kev.data = 1; 27895c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 27995c05062SDavid Bright elapsed = now() - start; 28095c05062SDavid Bright 28195c05062SDavid Bright /* Check that the timer expired after at least 1 ms, but less than 28295c05062SDavid Bright * 1 second. This check is to make sure that the original 1 second 28395c05062SDavid Bright * timeout was not used. 28495c05062SDavid Bright */ 28595c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 28695c05062SDavid Bright if (elapsed < MS_TO_US(1)) 28795c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 28895c05062SDavid Bright if (elapsed > SEC_TO_US(1)) 28995c05062SDavid Bright errx(1, "late timer expiration: %ld us", elapsed); 29095c05062SDavid Bright 29195c05062SDavid Bright success(); 29295c05062SDavid Bright } 29395c05062SDavid Bright 29495c05062SDavid Bright static void 29595c05062SDavid Bright test_update_equal(void) 29695c05062SDavid Bright { 29795c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)"; 29895c05062SDavid Bright struct kevent kev; 29995c05062SDavid Bright long elapsed; 30095c05062SDavid Bright long start; 30195c05062SDavid Bright 30295c05062SDavid Bright test_begin(test_id); 30395c05062SDavid Bright 30495c05062SDavid Bright test_no_kevents(); 30595c05062SDavid Bright 30695c05062SDavid Bright /* First set the timer to 1 ms */ 30795c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 30895c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL); 30995c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 31095c05062SDavid Bright err(1, "%s", test_id); 31195c05062SDavid Bright 31295c05062SDavid Bright /* Sleep for a significant fraction of the timeout. */ 31395c05062SDavid Bright ussleep(600); 31495c05062SDavid Bright 31595c05062SDavid Bright /* Now re-add the timer with the same parameters */ 31695c05062SDavid Bright start = now(); 31795c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 31895c05062SDavid Bright err(1, "%s", test_id); 31995c05062SDavid Bright 32095c05062SDavid Bright /* Wait for the event */ 32195c05062SDavid Bright kev.flags |= EV_CLEAR; 32295c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 32395c05062SDavid Bright kev.data = 1; 32495c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 32595c05062SDavid Bright elapsed = now() - start; 32695c05062SDavid Bright 32795c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This check is 32895c05062SDavid Bright * to make sure that the timer re-started and that the event is 32995c05062SDavid Bright * not from the original add of the timer. 33095c05062SDavid Bright */ 33195c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 33295c05062SDavid Bright if (elapsed < MS_TO_US(1)) 33395c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 33495c05062SDavid Bright 33595c05062SDavid Bright success(); 33695c05062SDavid Bright } 33795c05062SDavid Bright 33895c05062SDavid Bright static void 33995c05062SDavid Bright test_update_expired(void) 34095c05062SDavid Bright { 34195c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)"; 34295c05062SDavid Bright struct kevent kev; 34395c05062SDavid Bright long elapsed; 34495c05062SDavid Bright long start; 34595c05062SDavid Bright 34695c05062SDavid Bright test_begin(test_id); 34795c05062SDavid Bright 34895c05062SDavid Bright test_no_kevents(); 34995c05062SDavid Bright 35095c05062SDavid Bright /* Set the timer to 1ms */ 35195c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 35295c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL); 35395c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 35495c05062SDavid Bright err(1, "%s", test_id); 35595c05062SDavid Bright 35695c05062SDavid Bright /* Wait for 2 ms to give the timer plenty of time to expire. */ 35795c05062SDavid Bright mssleep(2); 35895c05062SDavid Bright 35995c05062SDavid Bright /* Now re-add the timer */ 36095c05062SDavid Bright start = now(); 36195c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 36295c05062SDavid Bright err(1, "%s", test_id); 36395c05062SDavid Bright 36495c05062SDavid Bright /* Wait for the event */ 36595c05062SDavid Bright kev.flags |= EV_CLEAR; 36695c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 36795c05062SDavid Bright kev.data = 1; 36895c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 36995c05062SDavid Bright elapsed = now() - start; 37095c05062SDavid Bright 37195c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This check 37295c05062SDavid Bright * is to make sure that the timer re-started and that the event is 37395c05062SDavid Bright * not from the original add (and expiration) of the timer. 37495c05062SDavid Bright */ 37595c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 37695c05062SDavid Bright if (elapsed < MS_TO_US(1)) 37795c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 37895c05062SDavid Bright 37995c05062SDavid Bright /* Make sure the re-added timer does not fire. In other words, 38095c05062SDavid Bright * test that the event received above was the only event from the 38195c05062SDavid Bright * add and re-add of the timer. 38295c05062SDavid Bright */ 38395c05062SDavid Bright mssleep(2); 38495c05062SDavid Bright test_no_kevents(); 38595c05062SDavid Bright 38695c05062SDavid Bright success(); 38795c05062SDavid Bright } 38895c05062SDavid Bright 38995c05062SDavid Bright static void 39095c05062SDavid Bright test_update_periodic(void) 39195c05062SDavid Bright { 39295c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)"; 39395c05062SDavid Bright struct kevent kev; 39495c05062SDavid Bright long elapsed; 39595c05062SDavid Bright long start; 39695c05062SDavid Bright long stop; 39795c05062SDavid Bright 39895c05062SDavid Bright test_begin(test_id); 39995c05062SDavid Bright 40095c05062SDavid Bright test_no_kevents(); 40195c05062SDavid Bright 40295c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL); 40395c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 40495c05062SDavid Bright err(1, "%s", test_id); 40595c05062SDavid Bright 40695c05062SDavid Bright /* Retrieve the event */ 40795c05062SDavid Bright kev.flags = EV_ADD | EV_CLEAR; 40895c05062SDavid Bright kev.data = 1; 40995c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 41095c05062SDavid Bright 41195c05062SDavid Bright /* Check if the event occurs again */ 41295c05062SDavid Bright sleep(1); 41395c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 41495c05062SDavid Bright 41595c05062SDavid Bright /* Re-add with new timeout. */ 41695c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL); 41795c05062SDavid Bright start = now(); 41895c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 41995c05062SDavid Bright err(1, "%s", test_id); 42095c05062SDavid Bright 42195c05062SDavid Bright /* Retrieve the event */ 42295c05062SDavid Bright kev.flags = EV_ADD | EV_CLEAR; 42395c05062SDavid Bright kev.data = 1; 42495c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 42595c05062SDavid Bright 42695c05062SDavid Bright stop = now(); 42795c05062SDavid Bright elapsed = stop - start; 42895c05062SDavid Bright 42995c05062SDavid Bright /* Check that the timer expired after at least 2 ms. 43095c05062SDavid Bright */ 43195c05062SDavid Bright printf("timer expired after %ld us\n", elapsed); 43295c05062SDavid Bright if (elapsed < MS_TO_US(2)) 43395c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 43495c05062SDavid Bright 43595c05062SDavid Bright /* Delete the event */ 43695c05062SDavid Bright kev.flags = EV_DELETE; 43795c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 43895c05062SDavid Bright err(1, "%s", test_id); 43995c05062SDavid Bright 44095c05062SDavid Bright success(); 44195c05062SDavid Bright } 44295c05062SDavid Bright 44395c05062SDavid Bright static void 44495c05062SDavid Bright test_update_timing(void) 44595c05062SDavid Bright { 44695c05062SDavid Bright #define MIN_SLEEP 500 44795c05062SDavid Bright #define MAX_SLEEP 1500 44895c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)"; 44995c05062SDavid Bright struct kevent kev; 45095c05062SDavid Bright int iteration; 45195c05062SDavid Bright int sleeptime; 45295c05062SDavid Bright long elapsed; 45395c05062SDavid Bright long start; 45495c05062SDavid Bright long stop; 45595c05062SDavid Bright 45695c05062SDavid Bright test_begin(test_id); 45795c05062SDavid Bright 45895c05062SDavid Bright test_no_kevents(); 45995c05062SDavid Bright 46095c05062SDavid Bright /* Re-try the update tests with a variety of delays between the 46195c05062SDavid Bright * original timer activation and the update of the timer. The goal 46295c05062SDavid Bright * is to show that in all cases the only timer event that is 46395c05062SDavid Bright * received is from the update and not the original timer add. 46495c05062SDavid Bright */ 46595c05062SDavid Bright for (sleeptime = MIN_SLEEP, iteration = 1; 46695c05062SDavid Bright sleeptime < MAX_SLEEP; 46795c05062SDavid Bright ++sleeptime, ++iteration) { 46895c05062SDavid Bright 46995c05062SDavid Bright /* First set the timer to 1 ms */ 47095c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 47195c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL); 47295c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 47395c05062SDavid Bright err(1, "%s", test_id); 47495c05062SDavid Bright 47595c05062SDavid Bright /* Delay; the delay ranges from less than to greater than the 47695c05062SDavid Bright * timer period. 47795c05062SDavid Bright */ 47895c05062SDavid Bright ussleep(sleeptime); 47995c05062SDavid Bright 48095c05062SDavid Bright /* Now re-add the timer with the same parameters */ 48195c05062SDavid Bright start = now(); 48295c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 48395c05062SDavid Bright err(1, "%s", test_id); 48495c05062SDavid Bright 48595c05062SDavid Bright /* Wait for the event */ 48695c05062SDavid Bright kev.flags |= EV_CLEAR; 48795c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS; 48895c05062SDavid Bright kev.data = 1; 48995c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd)); 49095c05062SDavid Bright stop = now(); 49195c05062SDavid Bright elapsed = stop - start; 49295c05062SDavid Bright 49395c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This 49495c05062SDavid Bright * check is to make sure that the timer re-started and that 49595c05062SDavid Bright * the event is not from the original add of the timer. 49695c05062SDavid Bright */ 49795c05062SDavid Bright if (elapsed < MS_TO_US(1)) 49895c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed); 49995c05062SDavid Bright 50095c05062SDavid Bright /* Make sure the re-added timer does not fire. In other words, 50195c05062SDavid Bright * test that the event received above was the only event from 50295c05062SDavid Bright * the add and re-add of the timer. 50395c05062SDavid Bright */ 50495c05062SDavid Bright mssleep(2); 50595c05062SDavid Bright test_no_kevents_quietly(); 50695c05062SDavid Bright } 50795c05062SDavid Bright 50895c05062SDavid Bright success(); 50995c05062SDavid Bright } 51095c05062SDavid Bright 511cb5fe245SEnji Cooper void 512*c9c283bdSAlex Richardson test_evfilt_timer(void) 513cb5fe245SEnji Cooper { 514cb5fe245SEnji Cooper kqfd = kqueue(); 515cb5fe245SEnji Cooper test_kevent_timer_add(); 516cb5fe245SEnji Cooper test_kevent_timer_del(); 517cb5fe245SEnji Cooper test_kevent_timer_get(); 518cb5fe245SEnji Cooper test_oneshot(); 519cb5fe245SEnji Cooper test_periodic(); 5202b34e843SKonstantin Belousov test_abstime(); 52195c05062SDavid Bright test_update(); 52295c05062SDavid Bright test_update_equal(); 52395c05062SDavid Bright test_update_expired(); 52495c05062SDavid Bright test_update_timing(); 52595c05062SDavid Bright test_update_periodic(); 526cb5fe245SEnji Cooper disable_and_enable(); 527cb5fe245SEnji Cooper close(kqfd); 528cb5fe245SEnji Cooper } 529