NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/58919: timer_settime fails to trigger for past times



The following reply was made to PR kern/58919; it has been noted by GNATS.

From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
To: gnats-bugs%NetBSD.org@localhost, netbsd-bugs%NetBSD.org@localhost
Cc: 
Subject: Re: kern/58919: timer_settime fails to trigger for past times
Date: Thu, 19 Dec 2024 22:12:16 +0000

 For relative timers, the language in POSIX.1-2024 is not very clear
 (does the part I quoted apply to the whole paragraph, or only to the
 half of the paragraph about absolute timers?), but by analogy with
 more explicit language about setitimer in POSIX.1-2008, we might
 reasonably conclude that negative relative timers are intended to fail
 with EINVAL (not ETIMEDOUT) rather than be treated as having fired
 already:
 
 > The setitimer() function shall fail if:
 > 
 > [EINVAL]
 >     The value argument is not in canonical form. (In canonical form,
 >     the number of microseconds is a non-negative integer less than
 >     1000000 and the number of seconds is a non-negative integer.)
 > 
 https://pubs.opengroup.org/onlinepubs/9699919799/functions/setitimer.html
 
 For absolute timers, the issue is that the timer expiration occurs on
 the _next tick_ rather than immediately.
 
 This strikes me as wrong: the timer should have fired already, so it
 seems to me the signal should be delivered synchronously with the
 timer_settime syscall, just like a pending signal is delivered
 synchronously with the sigprocmask(SIG_UNBLOCK) syscall.  But we're
 not alone in this behaviour (at least Linux defers it a tiny bit too).
 
 The following variant of the how-to-repeat program, which sleeps for
 the smallest possible nonzero increment of time (rounded up to one
 tick), shows this (and I've incorporated it into t_timer_create.c and
 t_timerfd.c):
 
 $ cat timerpastabs1.c
 #include <err.h>
 #include <signal.h>
 #include <time.h>
 
 sig_atomic_t woken;
 
 static void
 wakeup(int signo)
 {
 
 	woken = 1;
 }
 
 int
 main(void)
 {
 	timer_t t;
 	struct itimerspec it = {.it_value = {-1, 0}};
 	struct timespec t0;
 
 	if (signal(SIGALRM, wakeup) == SIG_ERR)
 		err(1, "signal(SIGALRM)");
 	if (timer_create(CLOCK_MONOTONIC, NULL, &t) == -1)
 		err(1, "timer_create");
 	if (clock_gettime(CLOCK_MONOTONIC, &t0) == -1)
 		err(1, "clock_gettime");
 	timespecadd(&t0, &it.it_value, &it.it_value);
 	if (timer_settime(t, TIMER_ABSTIME, &it, NULL) == -1)
 		err(1, "timer_settime");
 	if (clock_nanosleep(CLOCK_MONOTONIC, 0,
 		&(const struct timespec){0,1}, NULL) == -1)
 		err(1, "clock_nanosleep");
 	return woken ? 0 : 1;
 }
 $ make timerpastabs1
 cc -O2   -o timerpastabs1 timerpastabs1.c 
 $ ./timerpastabs1
 0
 


Home | Main Index | Thread Index | Old Index