/* Tests for getitimer(2)/setitimer(2) - by D.C. van Moolenbroek */ /* Warning: this test deals with (real and virtual) time, and, lacking a proper * point of reference, its correctness depends on circumstances like CPU speed * and system load. A succeeding test run says a lot - failure not so much. */ #include #include #include #include #include #include #include #include #include #include #include #define ITERATIONS 3 #define MAX_ERROR 4 /* we have to keep in mind the millisecond values are rounded up */ #define UPPERUSEC(us) ((us)+(1000000/system_hz)) #define EQUSEC(l,r) \ ((l) <= ((r) + (1000000/system_hz)) && (l) >= ((r) - (1000000/system_hz))) #define FILLITIMER(it, vs, vu, is, iu) \ (it).it_value.tv_sec = (vs); \ (it).it_value.tv_usec = (vu); \ (it).it_interval.tv_sec = (is); \ (it).it_interval.tv_usec = (iu); /* these two macros are not fully working for all possible values; * the tests only use values that the macros can deal with, though. */ #define EQITIMER(it, vs, vu, is, iu) \ ((it).it_value.tv_sec == (vs) && EQUSEC((it).it_value.tv_usec,vu) && \ (it).it_interval.tv_sec == (is) && (it).it_interval.tv_usec == (iu)) #define LEITIMER(it, vs, vu, is, iu) \ ((it).it_value.tv_sec > 0 && ((it).it_value.tv_sec < (vs) || \ ((it).it_value.tv_sec == (vs) && (it).it_value.tv_usec <= \ UPPERUSEC(vu))) && \ (it).it_interval.tv_sec == (is) && EQUSEC((it).it_interval.tv_usec,iu)) _PROTOTYPE(int main, (int argc, char **argv)); _PROTOTYPE(void test, (int m, int t)); _PROTOTYPE(void test_which, (void)); _PROTOTYPE(void test_getset, (void)); _PROTOTYPE(void test_neglarge, (void)); _PROTOTYPE(void test_zero, (void)); _PROTOTYPE(void test_timer, (void)); _PROTOTYPE(void test_alarm, (void)); _PROTOTYPE(void test_fork, (void)); _PROTOTYPE(void test_exec, (void)); _PROTOTYPE(int do_check, (void)); _PROTOTYPE(void got_alarm, (int sig)); _PROTOTYPE(void busy_wait, (int secs)); _PROTOTYPE(void e, (int n)); _PROTOTYPE(void quit, (void)); static char *executable; static int signals; static int timer; static int errct = 0, subtest; static long system_hz; static int sigs[] = { SIGALRM, SIGVTALRM, SIGPROF }; static const char *names[] = { "REAL", "VIRTUAL", "PROF" }; int main(argc, argv) int argc; char **argv; { int i, m = 0xFFFF, n = 0xF; system_hz = sysconf(_SC_CLK_TCK); if (strcmp(argv[0], "DO CHECK") == 0) { timer = atoi(argv[1]); exit(do_check()); } printf("Test 41 "); fflush(stdout); executable = argv[0]; if (argc >= 2) m = atoi(argv[1]); if (argc >= 3) n = atoi(argv[2]); for (i = 0; i < ITERATIONS; i++) { if (n & 1) test(m, ITIMER_REAL); if (n & 2) test(m, ITIMER_VIRTUAL); if (n & 4) test(m, ITIMER_PROF); } quit(); return(-1); /* impossible */ } void test(m, t) int m; int t; { timer = t; if (m & 0001) test_which(); if (m & 0002) test_getset(); if (m & 0004) test_neglarge(); if (m & 0010) test_zero(); if (m & 0020) test_timer(); if (m & 0040) test_alarm(); if (m & 0100) test_fork(); if (m & 0200) test_exec(); } /* test invalid and unsupported 'which' values */ void test_which() { struct itimerval it; subtest = 0; errno = 0; if (!getitimer(-1, &it) || errno != EINVAL) e(1); errno = 0; if ( getitimer(timer, &it) ) e(2); errno = 0; if (!getitimer( 3, &it) || errno != EINVAL) e(3); } /* test if we get back what we set */ void test_getset() { struct itimerval it, oit; subtest = 1; /* no alarm should be set initially */ if (getitimer(timer, &it)) e(1); if (!EQITIMER(it, 0, 0, 0, 0)) e(2); if (setitimer(timer, &it, &oit)) e(3); if (setitimer(timer, &oit, NULL)) e(4); if (!EQITIMER(oit, 0, 0, 0, 0)) e(5); FILLITIMER(it, 123, 0, 456, 0); if (setitimer(timer, &it, NULL)) e(6); FILLITIMER(it, 987, 0, 654, 0); if (setitimer(timer, &it, &oit)) e(7); if (!LEITIMER(oit, 123, 0, 456, 0)) e(8); if (getitimer(timer, &oit)) e(9); if (!LEITIMER(oit, 987, 0, 654, 0)) e(10); FILLITIMER(it, 0, 0, 0, 0); if (setitimer(timer, &it, &oit)) e(11); if (!LEITIMER(oit, 987, 0, 654, 0)) e(12); if (getitimer(timer, &oit)) e(13); if (!EQITIMER(oit, 0, 0, 0, 0)) e(14); } /* test negative/large values */ void test_neglarge() { struct itimerval it; subtest = 2; FILLITIMER(it, 4, 0, 5, 0); if (setitimer(timer, &it, NULL)) e(1); FILLITIMER(it, 1000000000, 0, 0, 0); if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(2); FILLITIMER(it, 0, 1000000, 0, 0); if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(3); FILLITIMER(it, 0, 0, 0, 1000000); if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(4); FILLITIMER(it, -1, 0, 0, 0); if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(5); FILLITIMER(it, 0, -1, 0, 0); if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(6); FILLITIMER(it, 0, 0, -1, 0); if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(7); FILLITIMER(it, 0, 0, 0, -1); if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(8); if (getitimer(timer, &it)) e(9); if (!LEITIMER(it, 4, 0, 5, 0)) e(10); } /* setitimer with a zero timer has to set the interval to zero as well */ void test_zero() { struct itimerval it; subtest = 3; it.it_value.tv_sec = 0; it.it_value.tv_usec = 0; it.it_interval.tv_sec = 1; it.it_interval.tv_usec = 1; if (setitimer(timer, &it, NULL)) e(1); if (getitimer(timer, &it)) e(2); if (!EQITIMER(it, 0, 0, 0, 0)) e(3); } /* test actual timer functioning */ void test_timer() { struct itimerval it; subtest = 4; if (signal(sigs[timer], got_alarm) == SIG_ERR) e(1); FILLITIMER(it, 0, 1, 0, 1); if (setitimer(timer, &it, NULL)) e(2); signals = 0; busy_wait(1); FILLITIMER(it, 0, 0, 0, 0); if (setitimer(timer, &it, NULL)) e(3); /* we don't know how many signals we'll actually get in practice, * so these checks more or less cover the extremes of the acceptable */ if (signals < 2) e(4); if (signals > system_hz * 2) e(5); /* only for REAL timer can we check against the clock */ if (timer == ITIMER_REAL) { FILLITIMER(it, 1, 0, 0, 0); if (setitimer(timer, &it, NULL)) e(6); signals = 0; busy_wait(1); FILLITIMER(it, 0, 0, 0, 0); if (setitimer(timer, &it, NULL)) e(7); if (signals != 1) e(8); } signals = 0; busy_wait(1); if (signals != 0) e(9); } /* test itimer/alarm interaction */ void test_alarm(void) { struct itimerval it; /* only applicable for ITIMER_REAL */ if (timer != ITIMER_REAL) return; subtest = 5; if (signal(SIGALRM, got_alarm) == SIG_ERR) e(1); FILLITIMER(it, 3, 0, 1, 0); if (setitimer(timer, &it, NULL)) e(2); if (alarm(2) != 3) e(3); if (getitimer(timer, &it)) e(4); if (!LEITIMER(it, 2, 0, 0, 0)) e(5); signals = 0; busy_wait(5); if (signals != 1) e(6); if (getitimer(timer, &it)) e(7); if (!EQITIMER(it, 0, 0, 0, 0)) e(8); } /* test that the timer is reset on forking */ void test_fork(void) { struct itimerval it, oit; pid_t pid; int status; subtest = 6; FILLITIMER(it, 12, 34, 56, 78); if (setitimer(timer, &it, NULL)) e(1); pid = fork(); if (pid < 0) e(2); if (pid == 0) { if (getitimer(timer, &it)) exit(5); if (!EQITIMER(it, 0, 0, 0, 0)) exit(6); exit(0); } if (wait(&status) != pid) e(3); if (!WIFEXITED(status)) e(4); if (WEXITSTATUS(status) != 0) e(WEXITSTATUS(status)); FILLITIMER(it, 0, 0, 0, 0); if (setitimer(timer, &it, &oit)) e(7); if (!LEITIMER(oit, 12, 34, 56, 78)) e(8); } /* test if timer is carried over to exec()'ed process */ void test_exec(void) { struct itimerval it; pid_t pid; int status; char buf[2]; subtest = 7; pid = fork(); if (pid < 0) e(1); if (pid == 0) { FILLITIMER(it, 3, 0, 1, 0); if (setitimer(timer, &it, NULL)) exit(2); sprintf(buf, "%d", timer); execl(executable, "DO CHECK", buf, NULL); exit(3); } if (wait(&status) != pid) e(4); if (WIFSIGNALED(status)) { /* process should have died from corresponding signal */ if (WTERMSIG(status) != sigs[timer]) e(5); } else { if (WIFEXITED(status)) e(WEXITSTATUS(status)); else e(6); } } /* procedure of the exec()'ed process */ int do_check() { struct itimerval it; if (getitimer(timer, &it)) return(81); if (!LEITIMER(it, 3, 0, 1, 0)) return(82); busy_wait(60); return(83); } void busy_wait(secs) int secs; { time_t now, exp; int i; exp = time(&now) + secs + 1; while (now < exp) { for (i = 0; i < 100000; i++); time(&now); } } void got_alarm(sig) int sig; { if (sig != sigs[timer]) e(1001); signals++; } void e(n) int n; { printf("Timer %s, subtest %d, error %d, errno %d: %s\n", names[timer], subtest, n, errno, strerror(errno)); if (errct++ > MAX_ERROR) { printf("Too many errors; test aborted\n"); exit(1); } } void quit() { if (errct == 0) { printf("ok\n"); exit(0); } else { printf("%d errors\n", errct); exit(1); } }