1#include <sys/types.h> 2#include <sys/event.h> 3#include <sys/time.h> 4#include <assert.h> 5#include <errno.h> 6#include <stdio.h> 7#include <stdlib.h> 8#include <unistd.h> 9 10int kq, passed, failed; 11 12/* 13 * Wait for given kevent, which should return in 'expected' usecs. 14 */ 15int 16do_simple_kevent(struct kevent64_s *kev, uint64_t expected) 17{ 18 int ret; 19 uint64_t elapsed_usecs, delta_usecs; 20 struct timespec timeout; 21 struct timeval before, after; 22 23 /* time out after 1 sec extra delay */ 24 timeout.tv_sec = (expected / (1000 * 1000)) + 1; 25 timeout.tv_nsec = (expected % (1000 * 1000)) * 1000; 26 27 /* measure time for the kevent */ 28 gettimeofday(&before, NULL); 29 ret = kevent64(kq, kev, 1, kev, 1, 0, &timeout); 30 gettimeofday(&after, NULL); 31 32 if (ret < 1 || (kev->flags & EV_ERROR)) { 33 printf("\tfailure: kevent returned %d, error %d\n", ret, 34 (ret == -1 ? errno : (int) kev->data)); 35 return 0; 36 } 37 38 /* did it work? */ 39 elapsed_usecs = (after.tv_sec - before.tv_sec) * (1000 * 1000) + 40 (after.tv_usec - before.tv_usec); 41 delta_usecs = abs(elapsed_usecs - (expected)); 42 43 /* failure if we're 30% off, or 50 mics late */ 44 if (delta_usecs > (30 * expected / 100.0) && delta_usecs > 50) { 45 printf("\tfailure: expected %lld usec, measured %lld usec.\n", 46 expected, elapsed_usecs); 47 return 0; 48 } else { 49 printf("\tsuccess.\n"); 50 return 1; 51 } 52} 53 54void 55test_absolute_kevent(int time, int scale) 56{ 57 struct timeval tv; 58 struct kevent64_s kev; 59 uint64_t nowus, expected, deadline; 60 int ret; 61 int timescale = 0; 62 63 gettimeofday(&tv, NULL); 64 nowus = tv.tv_sec * (1000 * 1000LL) + tv.tv_usec; 65 66 switch (scale) { 67 case NOTE_SECONDS: 68 printf("Testing %d sec absolute timer...\n", time); 69 timescale = 1000 * 1000; 70 break; 71 case NOTE_USECONDS: 72 printf("Testing %d usec absolute timer...\n", time); 73 timescale = 1; 74 break; 75 case 0: 76 printf("Testing %d msec absolute timer...\n", time); 77 timescale = 1000; 78 break; 79 default: 80 printf("Failure: scale 0x%x not recognized.\n", scale); 81 return; 82 } 83 84 expected = time * timescale; 85 deadline = nowus / timescale + time; 86 87 /* deadlines in the past should fire immediately */ 88 if (time < 0) 89 expected = 0; 90 91 EV_SET64(&kev, 1, EVFILT_TIMER, EV_ADD, 92 NOTE_ABSOLUTE | scale, deadline, 0,0,0); 93 ret = do_simple_kevent(&kev, expected); 94 95 if (ret) 96 passed++; 97 else 98 failed++; 99} 100 101void 102test_oneshot_kevent(int time, int scale) 103{ 104 int ret; 105 uint64_t expected = 0; 106 struct kevent64_s kev; 107 108 switch (scale) { 109 case NOTE_SECONDS: 110 printf("Testing %d sec interval timer...\n", time); 111 expected = time * (1000 * 1000); 112 break; 113 case NOTE_USECONDS: 114 printf("Testing %d usec interval timer...\n", time); 115 expected = time; 116 break; 117 case NOTE_NSECONDS: 118 printf("Testing %d nsec interval timer...\n", time); 119 expected = time / 1000; 120 break; 121 case 0: 122 printf("Testing %d msec interval timer...\n", time); 123 expected = time * 1000; 124 break; 125 default: 126 printf("Failure: scale 0x%x not recognized.\n", scale); 127 return; 128 } 129 130 /* deadlines in the past should fire immediately */ 131 if (time < 0) 132 expected = 0; 133 134 EV_SET64(&kev, 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, scale, time, 135 0, 0, 0); 136 ret = do_simple_kevent(&kev, expected); 137 138 if (ret) 139 passed++; 140 else 141 failed++; 142 143} 144 145void 146test_repeating_kevent(int usec) 147{ 148 struct kevent64_s kev; 149 int expected_pops, ret; 150 151 expected_pops = 1000 * 1000 / usec; 152 printf("Testing repeating kevent for %d pops in a second...\n", 153 expected_pops); 154 155 EV_SET64(&kev, 3, EVFILT_TIMER, EV_ADD, NOTE_USECONDS, usec, 0, 0, 0); 156 ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL); 157 if (ret != 0) { 158 printf("\tfailure: kevent64 returned %d\n", ret); 159 failed++; 160 return; 161 } 162 163 /* sleep 1 second */ 164 usleep(1000 * 1000); 165 ret = kevent64(kq, NULL, 0, &kev, 1, 0, NULL); 166 if (ret != 1 || (kev.flags & EV_ERROR)) { 167 printf("\tfailure: kevent64 returned %d\n", ret); 168 failed++; 169 return; 170 } 171 172 /* check how many times the timer fired: within 5%? */ 173 if (kev.data > expected_pops + (expected_pops / 20) || 174 kev.data < expected_pops - (expected_pops / 20)) { 175 printf("\tfailure: saw %lld pops.\n", kev.data); 176 failed++; 177 } else { 178 printf("\tsuccess: saw %lld pops.\n", kev.data); 179 passed++; 180 } 181 182 EV_SET64(&kev, 3, EVFILT_TIMER, EV_DELETE, 0, 0, 0, 0, 0); 183 ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL); 184 if (ret != 0) { 185 printf("\tfailed to stop repeating timer: %d\n", ret); 186 } 187} 188 189void 190test_updated_kevent(int first, int second) 191{ 192 struct kevent64_s kev; 193 int ret; 194 195 printf("Testing update from %d to %d msecs...\n", first, second); 196 197 EV_SET64(&kev, 4, EVFILT_TIMER, EV_ADD|EV_ONESHOT, 0, first, 0, 0, 0); 198 ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL); 199 if (ret != 0) { 200 printf("\tfailure: initial kevent returned %d\n", ret); 201 failed++; 202 return; 203 } 204 205 EV_SET64(&kev, 4, EVFILT_TIMER, EV_ONESHOT, 0, second, 0, 0, 0); 206 if (second < 0) 207 second = 0; 208 ret = do_simple_kevent(&kev, second * 1000); 209 if (ret) 210 passed++; 211 else 212 failed++; 213} 214 215int 216main(void) 217{ 218 struct timeval tv; 219 struct kevent64_s kev; 220 uint64_t nowms, deadline; 221 222 kq = kqueue(); 223 assert(kq > 0); 224 passed = 0; 225 failed = 0; 226 227 test_absolute_kevent(100, 0); 228 test_absolute_kevent(200, 0); 229 test_absolute_kevent(300, 0); 230 test_absolute_kevent(1000, 0); 231 test_absolute_kevent(500, NOTE_USECONDS); 232 test_absolute_kevent(100, NOTE_USECONDS); 233 test_absolute_kevent(5, NOTE_SECONDS); 234 test_absolute_kevent(-1000, 0); 235 236 test_oneshot_kevent(1, NOTE_SECONDS); 237 test_oneshot_kevent(10, 0); 238 test_oneshot_kevent(200, NOTE_USECONDS); 239 test_oneshot_kevent(300000, NOTE_NSECONDS); 240 test_oneshot_kevent(-1, NOTE_SECONDS); 241 242 test_repeating_kevent(100 * 1000); 243 test_repeating_kevent(5 * 1000); 244 test_repeating_kevent(200); 245 test_repeating_kevent(50); 246 test_repeating_kevent(10); 247 248 test_updated_kevent(1000, 2000); 249 test_updated_kevent(2000, 1000); 250 test_updated_kevent(1000, -1); 251 252 printf("\nFinished: %d tests passed, %d failed.\n", passed, failed); 253 254 exit(EXIT_SUCCESS); 255} 256