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();
}