NetBSD Problem Report #58919
From www@netbsd.org Wed Dec 18 22:12:56 2024
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256
client-signature RSA-PSS (2048 bits) client-digest SHA256)
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id BBA371A9238
for <gnats-bugs@gnats.NetBSD.org>; Wed, 18 Dec 2024 22:12:56 +0000 (UTC)
Message-Id: <20241218221255.0CB4D1A923A@mollari.NetBSD.org>
Date: Wed, 18 Dec 2024 22:12:54 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: timer_settime fails to trigger for past times
X-Send-Pr-Version: www-1.0
>Number: 58919
>Category: kern
>Synopsis: timer_settime fails to trigger for past times
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Dec 18 22:15:00 +0000 2024
>Last-Modified: Thu Dec 19 22:15:01 +0000 2024
>Originator: Taylor R Campbell
>Release: current, 10, 9, ...
>Organization:
The NetBSD Tachyondation
>Environment:
>Description:
POSIX says:
> If the specified time has already passed, the function shall succeed and the expiration notification shall be made.
https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/timer_settime.html
But for relative timers, timer_settime fails with ETIMEDOUT, and for absolute timers, nothing happens at all.
>How-To-Repeat:
$ cat timerpastabs.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 = { .tv_sec = -1, .tv_nsec = 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");
return woken ? 0 : 1;
}
$ cat timerpastrel
cat: timerpastrel: No such file or directory
$ cat timerpastrel.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 = { .tv_sec = -1, .tv_nsec = 0 } };
if (signal(SIGALRM, wakeup) == SIG_ERR)
err(1, "signal(SIGALRM)");
if (timer_create(CLOCK_MONOTONIC, NULL, &t) == -1)
err(1, "timer_create");
if (timer_settime(t, 0, &it, NULL) == -1)
err(1, "timer_settime");
return woken ? 0 : 1;
}
$ make timerpastabs timerpastrel
cc -O2 -o timerpastabs timerpastabs.c
cc -O2 -o timerpastrel timerpastrel.c
$ ./timerpastabs
$ echo $?
1
$ ./timerpastrel
timerpastrel: timer_settime: Connection timed out
>Fix:
Yes, please!
>Audit-Trail:
From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/58919 CVS commit: src/tests/lib/libc/sys
Date: Wed, 18 Dec 2024 22:26:53 +0000
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.
From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/58919 CVS commit: src/tests/lib/libc/sys
Date: Thu, 19 Dec 2024 20:07:29 +0000
Module Name: src
Committed By: riastradh
Date: Thu Dec 19 20:07:29 UTC 2024
Modified Files:
src/tests/lib/libc/sys: t_timer_create.c
Log Message:
t_timer_create: Fix up tests for edge cases.
While here, save and restore errno in signal handler.
PR kern/58919: timer_settime fails to trigger for past times
PR kern/58920: timer_settime fails ETIMEDOUT on negative interval, not
EINVAL
To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 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.
From: Taylor R Campbell <riastradh@NetBSD.org>
To: gnats-bugs@NetBSD.org, netbsd-bugs@NetBSD.org
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
(Contact us)
$NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2024
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.