Module Name: src Committed By: riastradh Date: Wed Dec 18 22:26:53 UTC 2024
Modified Files: src/tests/lib/libc/sys: t_timer_create.c Log Message: t_timer_create: Add some more test cases. PR kern/58917: timer_settime and timerfd_settime return absolute time of next event PR kern/58919: timer_settime fails to trigger for past times To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/tests/lib/libc/sys/t_timer_create.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/lib/libc/sys/t_timer_create.c diff -u src/tests/lib/libc/sys/t_timer_create.c:1.5 src/tests/lib/libc/sys/t_timer_create.c:1.6 --- src/tests/lib/libc/sys/t_timer_create.c:1.5 Mon Jan 16 16:32:13 2017 +++ src/tests/lib/libc/sys/t_timer_create.c Wed Dec 18 22:26:53 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: t_timer_create.c,v 1.5 2017/01/16 16:32:13 christos Exp $ */ +/* $NetBSD: t_timer_create.c,v 1.6 2024/12/18 22:26:53 riastradh Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -34,8 +34,16 @@ #include <time.h> #include <unistd.h> +#include "h_macros.h" + static timer_t t; -static bool fail = true; +static sig_atomic_t expired; + +enum mode { + PAST, + EXPIRE, + NOEXPIRE, +}; static void timer_signal_handler(int signo, siginfo_t *si, void *osi __unused) @@ -45,21 +53,22 @@ timer_signal_handler(int signo, siginfo_ tp = si->si_value.sival_ptr; if (*tp == t && signo == SIGALRM) - fail = false; + expired = 1; (void)fprintf(stderr, "%s: %s\n", __func__, strsignal(signo)); } static void -timer_signal_create(clockid_t cid, bool expire) +timer_signal_create(clockid_t cid, enum mode mode, int flags) { - struct itimerspec tim; + struct itimerspec tim, rtim, otim; + struct timespec t0, t1, dt; struct sigaction act; struct sigevent evt; sigset_t set; t = 0; - fail = true; + expired = 0; (void)memset(&evt, 0, sizeof(struct sigevent)); (void)memset(&act, 0, sizeof(struct sigaction)); @@ -91,22 +100,131 @@ timer_signal_create(clockid_t cid, bool ATF_REQUIRE(timer_create(cid, &evt, &t) == 0); /* - * Start the timer. After this, unblock the signal. + * Configure the timer for -1, 1, or 5 sec from now, depending + * on whether we want it to have fired, to fire within 2sec, or + * to not fire within 2sec. */ - tim.it_value.tv_sec = expire ? 5 : 1; + switch (mode) { + case PAST: + tim.it_value.tv_sec = -1; + break; + case EXPIRE: + tim.it_value.tv_sec = 1; + break; + case NOEXPIRE: + tim.it_value.tv_sec = 5; + break; + } tim.it_value.tv_nsec = 0; - ATF_REQUIRE(timer_settime(t, 0, &tim, NULL) == 0); + /* + * Save the relative time and adjust for absolute time of + * requested. + */ + rtim = tim; + RL(clock_gettime(cid, &t0)); + if (flags & TIMER_ABSTIME) + timespecadd(&t0, &tim.it_value, &tim.it_value); + + fprintf(stderr, "now is %lld sec %d nsec\n", + (long long)t0.tv_sec, (int)t0.tv_nsec); + fprintf(stderr, "expire at %lld sec %d nsec\n", + (long long)tim.it_value.tv_sec, (int)tim.it_value.tv_nsec); + if (mode == PAST && (flags & TIMER_ABSTIME) == 0) { + atf_tc_expect_fail("PR kern/58919:" + " timer_settime fails to trigger for past times"); + } + RL(timer_settime(t, flags, &tim, NULL)); + RL(timer_settime(t, flags, &tim, &otim)); + if (mode == PAST && (flags & TIMER_ABSTIME) == 0) { + atf_tc_expect_pass(); + } + + RL(clock_gettime(cid, &t1)); + timespecsub(&t1, &t0, &dt); + fprintf(stderr, "%lld sec %d nsec elapsed\n", + (long long)dt.tv_sec, (int)dt.tv_nsec); - (void)sigprocmask(SIG_UNBLOCK, &set, NULL); - (void)sleep(2); + /* + * Check to make sure the time remaining is at most the + * relative time we expected. + */ + atf_tc_expect_fail("PR kern/58917:" + " timer_settime and timerfd_settime return" + " absolute time of next event"); + ATF_CHECK_MSG(timespeccmp(&otim.it_value, &rtim.it_value, <=), + "time remaining %lld sec %d nsec," + " expected at most %lld sec %d nsec", + (long long)otim.it_value.tv_sec, (int)otim.it_value.tv_nsec, + (long long)rtim.it_value.tv_sec, (int)rtim.it_value.tv_nsec); + atf_tc_expect_pass(); + + /* + * Until we fix PR kern/58917, adjust it to be relative to the + * start time. + */ + timespecsub(&otim.it_value, &t0, &otim.it_value); + fprintf(stderr, "adjust otim to %lld sec %d nsec\n", + (long long)otim.it_value.tv_sec, (int)otim.it_value.tv_nsec); - if (expire) { - if (!fail) - atf_tc_fail("timer fired too soon"); - } else { - if (fail) - atf_tc_fail("timer failed to fire"); +#if 0 + /* + * Check to make sure that the amount the time remaining has + * gone down is at most the time elapsed. + * + * XXX Currently the time returned by timer_settime is only + * good to the nearest kernel tick (typically 10ms or 1ms), not + * to the resolution of the underlying clock -- unlike + * clock_gettime. So we can't set this bound. Not sure + * whether this is a bug or not, hence #if 0 instead of + * atf_tc_expect_fail. + */ + timespecsub(&t1, &t0, &dt); + timespecsub(&rtim.it_value, &otim.it_value, &rtim.it_value); + ATF_CHECK_MSG(timespeccmp(&rtim.it_value, &dt, <=), + "time remaining went down by %lld sec %d nsec," + " expected at most %lld sec %d nsec", + (long long)rtim.it_value.tv_sec, (int)rtim.it_value.tv_nsec, + (long long)dt.tv_sec, (int)dt.tv_nsec); +#endif + + /* + * Check to make sure the reload interval is what we set. + */ + ATF_CHECK_MSG(timespeccmp(&otim.it_interval, &rtim.it_interval, ==), + "interval %lld sec %d nsec," + " expected %lld sec %d nsec", + (long long)otim.it_interval.tv_sec, (int)otim.it_interval.tv_nsec, + (long long)rtim.it_interval.tv_sec, (int)rtim.it_interval.tv_nsec); + + (void)sigprocmask(SIG_UNBLOCK, &set, NULL); + switch (mode) { + case PAST: + if (flags & TIMER_ABSTIME) { + atf_tc_expect_fail("PR kern/58919:" + " timer_settime fails to trigger for past times"); + } + ATF_CHECK_MSG(expired, "timer failed to fire immediately"); + if (flags & TIMER_ABSTIME) { + atf_tc_expect_pass(); + } + break; + case EXPIRE: + case NOEXPIRE: + ATF_CHECK_MSG(!expired, "timer fired too soon"); + (void)sleep(2); + switch (mode) { + case PAST: + __unreachable(); + case EXPIRE: + ATF_CHECK_MSG(expired, + "timer failed to fire immediately"); + break; + case NOEXPIRE: + ATF_CHECK_MSG(!expired, "timer fired too soon"); + break; + } + break; } ATF_REQUIRE(timer_delete(t) == 0); @@ -116,7 +234,7 @@ ATF_TC(timer_create_err); ATF_TC_HEAD(timer_create_err, tc) { atf_tc_set_md_var(tc, "descr", - "Check errors from timer_create(2) (PR lib/42434"); + "Check errors from timer_create(2) (PR lib/42434)"); } ATF_TC_BODY(timer_create_err, tc) @@ -149,7 +267,21 @@ ATF_TC_HEAD(timer_create_real, tc) ATF_TC_BODY(timer_create_real, tc) { - timer_signal_create(CLOCK_REALTIME, false); + timer_signal_create(CLOCK_REALTIME, NOEXPIRE, 0); +} + +ATF_TC(timer_create_real_abs); +ATF_TC_HEAD(timer_create_real_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), " + "SIGEV_SIGNAL, using absolute time"); +} + +ATF_TC_BODY(timer_create_real_abs, tc) +{ + timer_signal_create(CLOCK_REALTIME, NOEXPIRE, TIMER_ABSTIME); } ATF_TC(timer_create_mono); @@ -163,7 +295,21 @@ ATF_TC_HEAD(timer_create_mono, tc) ATF_TC_BODY(timer_create_mono, tc) { - timer_signal_create(CLOCK_MONOTONIC, false); + timer_signal_create(CLOCK_MONOTONIC, NOEXPIRE, 0); +} + +ATF_TC(timer_create_mono_abs); +ATF_TC_HEAD(timer_create_mono_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), " + "SIGEV_SIGNAL, using absolute time"); +} + +ATF_TC_BODY(timer_create_mono_abs, tc) +{ + timer_signal_create(CLOCK_MONOTONIC, NOEXPIRE, TIMER_ABSTIME); } ATF_TC(timer_create_real_expire); @@ -177,7 +323,21 @@ ATF_TC_HEAD(timer_create_real_expire, tc ATF_TC_BODY(timer_create_real_expire, tc) { - timer_signal_create(CLOCK_REALTIME, true); + timer_signal_create(CLOCK_REALTIME, EXPIRE, 0); +} + +ATF_TC(timer_create_real_expire_abs); +ATF_TC_HEAD(timer_create_real_expire_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), " + "SIGEV_SIGNAL, with expiration, using absolute time"); +} + +ATF_TC_BODY(timer_create_real_expire_abs, tc) +{ + timer_signal_create(CLOCK_REALTIME, EXPIRE, TIMER_ABSTIME); } ATF_TC(timer_create_mono_expire); @@ -191,7 +351,119 @@ ATF_TC_HEAD(timer_create_mono_expire, tc ATF_TC_BODY(timer_create_mono_expire, tc) { - timer_signal_create(CLOCK_MONOTONIC, true); + timer_signal_create(CLOCK_MONOTONIC, EXPIRE, 0); +} + +ATF_TC(timer_create_mono_expire_abs); +ATF_TC_HEAD(timer_create_mono_expire_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), " + "SIGEV_SIGNAL, with expiration, using absolute time"); +} + +ATF_TC_BODY(timer_create_mono_expire_abs, tc) +{ + timer_signal_create(CLOCK_MONOTONIC, EXPIRE, TIMER_ABSTIME); +} + +ATF_TC(timer_create_real_past); +ATF_TC_HEAD(timer_create_real_past, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), " + "SIGEV_SIGNAL, with expiration passed before timer_settime(2)"); +} + +ATF_TC_BODY(timer_create_real_past, tc) +{ + timer_signal_create(CLOCK_REALTIME, PAST, 0); +} + +ATF_TC(timer_create_real_past_abs); +ATF_TC_HEAD(timer_create_real_past_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), " + "SIGEV_SIGNAL, with expiration passed before timer_settime(2)," + " using absolute time"); +} + +ATF_TC_BODY(timer_create_real_past_abs, tc) +{ + timer_signal_create(CLOCK_REALTIME, PAST, TIMER_ABSTIME); +} + +ATF_TC(timer_create_mono_past); +ATF_TC_HEAD(timer_create_mono_past, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), " + "SIGEV_SIGNAL, with expiration passed before timer_settime(2)"); +} + +ATF_TC_BODY(timer_create_mono_past, tc) +{ + timer_signal_create(CLOCK_MONOTONIC, PAST, 0); +} + +ATF_TC(timer_create_mono_past_abs); +ATF_TC_HEAD(timer_create_mono_past_abs, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), " + "SIGEV_SIGNAL, with expiration passed before timer_settime(2)," + " using absolute time"); +} + +ATF_TC_BODY(timer_create_mono_past_abs, tc) +{ + timer_signal_create(CLOCK_MONOTONIC, PAST, TIMER_ABSTIME); +} + +ATF_TC(timer_invalidtime); +ATF_TC_HEAD(timer_invalidtime, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify timer_settime(2) rejects invalid times"); +} + +ATF_TC_BODY(timer_invalidtime, tc) +{ + const struct itimerspec einval_its[] = { + [0] = { .it_value = { -1, -1 } }, + [1] = { .it_value = { 1, -1 } }, + [2] = { .it_value = { 0, 1000000001 } }, + [3] = { .it_interval = { -1, -1 } }, + [4] = { .it_interval = { 1, -1 } }, + [5] = { .it_interval = { 0, 1000000001 } }, + }; + struct timespec now; + unsigned i; + + RL(clock_gettime(CLOCK_MONOTONIC, &now)); + + RL(timer_create(CLOCK_MONOTONIC, NULL, &t)); + + for (i = 0; i < __arraycount(einval_its); i++) { + struct itimerspec its; + + ATF_CHECK_ERRNO(EINVAL, + timer_settime(t, 0, &einval_its[i], NULL) == -1); + + /* Try the same with an absolute time near now. */ + its.it_value = einval_its[i].it_value; + its.it_value.tv_sec += now.tv_sec + 60; + ATF_CHECK_ERRNO(EINVAL, + timer_settime(t, TIMER_ABSTIME, &its, NULL) == -1); + } + + RL(timer_delete(t)); } ATF_TP_ADD_TCS(tp) @@ -199,9 +471,18 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, timer_create_err); ATF_TP_ADD_TC(tp, timer_create_real); + ATF_TP_ADD_TC(tp, timer_create_real_abs); ATF_TP_ADD_TC(tp, timer_create_mono); + ATF_TP_ADD_TC(tp, timer_create_mono_abs); ATF_TP_ADD_TC(tp, timer_create_real_expire); + ATF_TP_ADD_TC(tp, timer_create_real_expire_abs); ATF_TP_ADD_TC(tp, timer_create_mono_expire); + ATF_TP_ADD_TC(tp, timer_create_mono_expire_abs); + ATF_TP_ADD_TC(tp, timer_create_real_past); + ATF_TP_ADD_TC(tp, timer_create_real_past_abs); + ATF_TP_ADD_TC(tp, timer_create_mono_past); + ATF_TP_ADD_TC(tp, timer_create_mono_past_abs); + ATF_TP_ADD_TC(tp, timer_invalidtime); return atf_no_error(); }