timer.c (bca9d05fdb058aa709621661c2feccae8940d94b) | timer.c (95c05062ec15cf323488d4c5e1986f5866bf7464) |
---|---|
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 --- 5 unchanged lines hidden (view full) --- 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 | 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 --- 5 unchanged lines hidden (view full) --- 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 |
|
22int kqfd; 23 | 29int kqfd; 30 |
31/* Get the current time with microsecond precision. Used for 32 * sub-second timing to make some timer tests run faster. 33 */ 34static long 35now(void) 36{ 37 38 struct timeval tv; 39 40 gettimeofday(&tv, NULL); 41 return SEC_TO_US(tv.tv_sec) + tv.tv_usec; 42} 43 44/* Sleep for a given number of milliseconds. The timeout is assumed to 45 * be less than 1 second. 46 */ |
|
24void | 47void |
48mssleep(int t) 49{ 50 51 struct timespec stime = { 52 .tv_sec = 0, 53 .tv_nsec = US_TO_NS(MS_TO_US(t)), 54 }; 55 56 nanosleep(&stime, NULL); 57} 58 59/* Sleep for a given number of microseconds. The timeout is assumed to 60 * be less than 1 second. 61 */ 62void 63ussleep(int t) 64{ 65 66 struct timespec stime = { 67 .tv_sec = 0, 68 .tv_nsec = US_TO_NS(t), 69 }; 70 71 nanosleep(&stime, NULL); 72} 73 74void |
|
25test_kevent_timer_add(void) 26{ 27 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)"; 28 struct kevent kev; 29 30 test_begin(test_id); 31 32 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); --- 151 unchanged lines hidden (view full) --- 184 err(1, "%s", test_id); 185 186 /* Retrieve the event */ 187 kev.flags = EV_ADD | EV_ONESHOT; 188 kev.data = 1; 189 kev.fflags = 0; 190 kevent_cmp(&kev, kevent_get(kqfd)); 191 if (time(NULL) < when + timeout) | 75test_kevent_timer_add(void) 76{ 77 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)"; 78 struct kevent kev; 79 80 test_begin(test_id); 81 82 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); --- 151 unchanged lines hidden (view full) --- 234 err(1, "%s", test_id); 235 236 /* Retrieve the event */ 237 kev.flags = EV_ADD | EV_ONESHOT; 238 kev.data = 1; 239 kev.fflags = 0; 240 kevent_cmp(&kev, kevent_get(kqfd)); 241 if (time(NULL) < when + timeout) |
192 err(1, "too early %jd %jd", time(), when + timeout); | 242 err(1, "too early %jd %jd", time(NULL), when + timeout); |
193 194 /* Check if the event occurs again */ 195 sleep(3); 196 test_no_kevents(); 197 198 success(); 199} 200 | 243 244 /* Check if the event occurs again */ 245 sleep(3); 246 test_no_kevents(); 247 248 success(); 249} 250 |
251static void 252test_update(void) 253{ 254 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)"; 255 struct kevent kev; 256 long elapsed; 257 long start; 258 259 test_begin(test_id); 260 261 test_no_kevents(); 262 263 /* First set the timer to 1 second */ 264 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 265 NOTE_USECONDS, SEC_TO_US(1), (void *)1); 266 start = now(); 267 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 268 err(1, "%s", test_id); 269 270 /* Now reduce the timer to 1 ms */ 271 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 272 NOTE_USECONDS, MS_TO_US(1), (void *)2); 273 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 274 err(1, "%s", test_id); 275 276 /* Wait for the event */ 277 kev.flags |= EV_CLEAR; 278 kev.fflags &= ~NOTE_USECONDS; 279 kev.data = 1; 280 kevent_cmp(&kev, kevent_get(kqfd)); 281 elapsed = now() - start; 282 283 /* Check that the timer expired after at least 1 ms, but less than 284 * 1 second. This check is to make sure that the original 1 second 285 * timeout was not used. 286 */ 287 printf("timer expired after %ld us\n", elapsed); 288 if (elapsed < MS_TO_US(1)) 289 errx(1, "early timer expiration: %ld us", elapsed); 290 if (elapsed > SEC_TO_US(1)) 291 errx(1, "late timer expiration: %ld us", elapsed); 292 293 success(); 294} 295 296static void 297test_update_equal(void) 298{ 299 const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)"; 300 struct kevent kev; 301 long elapsed; 302 long start; 303 304 test_begin(test_id); 305 306 test_no_kevents(); 307 308 /* First set the timer to 1 ms */ 309 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 310 NOTE_USECONDS, MS_TO_US(1), NULL); 311 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 312 err(1, "%s", test_id); 313 314 /* Sleep for a significant fraction of the timeout. */ 315 ussleep(600); 316 317 /* Now re-add the timer with the same parameters */ 318 start = now(); 319 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 320 err(1, "%s", test_id); 321 322 /* Wait for the event */ 323 kev.flags |= EV_CLEAR; 324 kev.fflags &= ~NOTE_USECONDS; 325 kev.data = 1; 326 kevent_cmp(&kev, kevent_get(kqfd)); 327 elapsed = now() - start; 328 329 /* Check that the timer expired after at least 1 ms. This check is 330 * to make sure that the timer re-started and that the event is 331 * not from the original add of the timer. 332 */ 333 printf("timer expired after %ld us\n", elapsed); 334 if (elapsed < MS_TO_US(1)) 335 errx(1, "early timer expiration: %ld us", elapsed); 336 337 success(); 338} 339 340static void 341test_update_expired(void) 342{ 343 const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)"; 344 struct kevent kev; 345 long elapsed; 346 long start; 347 348 test_begin(test_id); 349 350 test_no_kevents(); 351 352 /* Set the timer to 1ms */ 353 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 354 NOTE_USECONDS, MS_TO_US(1), NULL); 355 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 356 err(1, "%s", test_id); 357 358 /* Wait for 2 ms to give the timer plenty of time to expire. */ 359 mssleep(2); 360 361 /* Now re-add the timer */ 362 start = now(); 363 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 364 err(1, "%s", test_id); 365 366 /* Wait for the event */ 367 kev.flags |= EV_CLEAR; 368 kev.fflags &= ~NOTE_USECONDS; 369 kev.data = 1; 370 kevent_cmp(&kev, kevent_get(kqfd)); 371 elapsed = now() - start; 372 373 /* Check that the timer expired after at least 1 ms. This check 374 * is to make sure that the timer re-started and that the event is 375 * not from the original add (and expiration) of the timer. 376 */ 377 printf("timer expired after %ld us\n", elapsed); 378 if (elapsed < MS_TO_US(1)) 379 errx(1, "early timer expiration: %ld us", elapsed); 380 381 /* Make sure the re-added timer does not fire. In other words, 382 * test that the event received above was the only event from the 383 * add and re-add of the timer. 384 */ 385 mssleep(2); 386 test_no_kevents(); 387 388 success(); 389} 390 391static void 392test_update_periodic(void) 393{ 394 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)"; 395 struct kevent kev; 396 long elapsed; 397 long start; 398 long stop; 399 400 test_begin(test_id); 401 402 test_no_kevents(); 403 404 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL); 405 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 406 err(1, "%s", test_id); 407 408 /* Retrieve the event */ 409 kev.flags = EV_ADD | EV_CLEAR; 410 kev.data = 1; 411 kevent_cmp(&kev, kevent_get(kqfd)); 412 413 /* Check if the event occurs again */ 414 sleep(1); 415 kevent_cmp(&kev, kevent_get(kqfd)); 416 417 /* Re-add with new timeout. */ 418 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL); 419 start = now(); 420 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 421 err(1, "%s", test_id); 422 423 /* Retrieve the event */ 424 kev.flags = EV_ADD | EV_CLEAR; 425 kev.data = 1; 426 kevent_cmp(&kev, kevent_get(kqfd)); 427 428 stop = now(); 429 elapsed = stop - start; 430 431 /* Check that the timer expired after at least 2 ms. 432 */ 433 printf("timer expired after %ld us\n", elapsed); 434 if (elapsed < MS_TO_US(2)) 435 errx(1, "early timer expiration: %ld us", elapsed); 436 437 /* Delete the event */ 438 kev.flags = EV_DELETE; 439 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 440 err(1, "%s", test_id); 441 442 success(); 443} 444 445static void 446test_update_timing(void) 447{ 448#define MIN_SLEEP 500 449#define MAX_SLEEP 1500 450 const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)"; 451 struct kevent kev; 452 int iteration; 453 int sleeptime; 454 long elapsed; 455 long start; 456 long stop; 457 458 test_begin(test_id); 459 460 test_no_kevents(); 461 462 /* Re-try the update tests with a variety of delays between the 463 * original timer activation and the update of the timer. The goal 464 * is to show that in all cases the only timer event that is 465 * received is from the update and not the original timer add. 466 */ 467 for (sleeptime = MIN_SLEEP, iteration = 1; 468 sleeptime < MAX_SLEEP; 469 ++sleeptime, ++iteration) { 470 471 /* First set the timer to 1 ms */ 472 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 473 NOTE_USECONDS, MS_TO_US(1), NULL); 474 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 475 err(1, "%s", test_id); 476 477 /* Delay; the delay ranges from less than to greater than the 478 * timer period. 479 */ 480 ussleep(sleeptime); 481 482 /* Now re-add the timer with the same parameters */ 483 start = now(); 484 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 485 err(1, "%s", test_id); 486 487 /* Wait for the event */ 488 kev.flags |= EV_CLEAR; 489 kev.fflags &= ~NOTE_USECONDS; 490 kev.data = 1; 491 kevent_cmp(&kev, kevent_get(kqfd)); 492 stop = now(); 493 elapsed = stop - start; 494 495 /* Check that the timer expired after at least 1 ms. This 496 * check is to make sure that the timer re-started and that 497 * the event is not from the original add of the timer. 498 */ 499 if (elapsed < MS_TO_US(1)) 500 errx(1, "early timer expiration: %ld us", elapsed); 501 502 /* Make sure the re-added timer does not fire. In other words, 503 * test that the event received above was the only event from 504 * the add and re-add of the timer. 505 */ 506 mssleep(2); 507 test_no_kevents_quietly(); 508 } 509 510 success(); 511} 512 |
|
201void 202test_evfilt_timer() 203{ 204 kqfd = kqueue(); | 513void 514test_evfilt_timer() 515{ 516 kqfd = kqueue(); |
205 test_kevent_timer_add(); 206 test_kevent_timer_del(); 207 test_kevent_timer_get(); 208 test_oneshot(); 209 test_periodic(); 210 test_abstime(); 211 disable_and_enable(); | 517 test_kevent_timer_add(); 518 test_kevent_timer_del(); 519 test_kevent_timer_get(); 520 test_oneshot(); 521 test_periodic(); 522 test_abstime(); 523 test_update(); 524 test_update_equal(); 525 test_update_expired(); 526 test_update_timing(); 527 test_update_periodic(); 528 disable_and_enable(); |
212 close(kqfd); 213} | 529 close(kqfd); 530} |