NetBSD Problem Report #59586

From www@netbsd.org  Sun Aug 10 21:53:21 2025
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)
	 client-signature RSA-PSS (2048 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id B0DF81A923A
	for <gnats-bugs@gnats.NetBSD.org>; Sun, 10 Aug 2025 21:53:21 +0000 (UTC)
Message-Id: <20250810215320.7DA0C1A923C@mollari.NetBSD.org>
Date: Sun, 10 Aug 2025 21:53:20 +0000 (UTC)
From: furkanonder@protonmail.com
Reply-To: furkanonder@protonmail.com
To: gnats-bugs@NetBSD.org
Subject: sigwaitinfo() returns ECANCELED instead of EINTR - POSIX compliance violation
X-Send-Pr-Version: www-1.0

>Number:         59586
>Notify-List:    riastradh@NetBSD.org
>Category:       standards
>Synopsis:       sigwaitinfo() returns ECANCELED instead of EINTR - POSIX compliance violation
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    riastradh
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Aug 10 21:55:00 +0000 2025
>Closed-Date:    Tue May 19 00:32:02 +0000 2026
>Last-Modified:  Tue May 19 00:32:02 +0000 2026
>Originator:     Furkan Onder
>Release:        NetBSD 10.0
>Organization:
CPython
>Environment:
NetBSD home.localhost 10.0 NetBSD 10.0 (GENERIC) #0: Thu Mar 28 08:33:33 UTC 2024  mkrepro@mkrepro.NetBSD.org:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
NetBSD's implementation of sigwaitinfo() violates the POSIX standard by returning errno = ECANCELED (87) instead of errno = EINTR (4)
when the function is interrupted by an unblocked, caught signal that is not in the specified wait set.

This issue was discovered through Python's comprehensive signal handling tests (https://github.com/python/cpython/issues/137490)
where the test suite expects EINTR but receives ECANCELED, causing test failure.

A review of NetBSD's manual pages reveals that ECANCELED is documented for several functions including aio_cancel, strtou, 
errno, aio_write, timerfd_create and strtoi. However, the sigwaitinfo manual page makes no mention of ECANCELED as a possible return value.

Critical Questions for NetBSD Developers
- Is repeating sigwaitinfo() after getting ECANCELED safe?
- What other signal-related functions return ECANCELED instead of EINTR?
- Is this behavior documented anywhere as a NetBSD-specific behavior?
>How-To-Repeat:
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

volatile sig_atomic_t got_sigalrm = 0;

void sigalrm_handler(int sig) {
    got_sigalrm = 1;
    printf("SIGALRM handler called\n");
}

int main() {
    printf("sigwaitinfo interruption test\n");

    sigset_t sigset;
    siginfo_t info;
    int target_signal = SIGUSR1;

    // Set SIGALRM handler
    struct sigaction sa = {0};
    sa.sa_handler = sigalrm_handler;
    sigaction(SIGALRM, &sa, NULL);

    // Block SIGUSR1 and save old mask
    sigemptyset(&sigset);
    sigaddset(&sigset, target_signal);
    pthread_sigmask(SIG_BLOCK, &sigset, NULL);

    printf("Blocked SIGUSR1, waiting with sigwaitinfo...\n");

    pid_t pid = fork();
    if (pid == 0) {
        sleep(1);
        printf("Child: sending SIGALRM to interrupt parent\n");
        kill(getppid(), SIGALRM);
        exit(0);
    }

    printf("Parent: calling sigwaitinfo([SIGUSR1])...\n");
    int result = sigwaitinfo(&sigset, &info);

    if (result == -1) {
        printf("sigwaitinfo failed: errno = %d (%s)\n", errno, strerror(errno));
        printf("Expected: errno = 4 (EINTR)\n");
        printf("Actual:   errno = %d (%s)\n", errno, strerror(errno));
    }

    printf("SIGALRM handler was called: %s\n", got_sigalrm ? "yes" : "no");

    int status;
    waitpid(pid, &status, 0);
    printf("Child exited with status: %d\n", WEXITSTATUS(status));

    return 0;
}

gcc -o sigwaitinfo_test sigwaitinfo_test.c
./sigwaitinfo_test

Expected Output (POSIX-compliant systems like Linux):

sigwaitinfo interruption test
Blocked SIGUSR1, waiting with sigwaitinfo...
Parent: calling sigwaitinfo([SIGUSR1])...
Child: sending SIGALRM to interrupt parent
SIGALRM handler called
sigwaitinfo failed: errno = 4 (Interrupted system call)
Expected: errno = 4 (EINTR)
Actual:   errno = 4 (Interrupted system call)
SIGALRM handler was called: yes
Child exited with status: 0

Actual Output on NetBSD 10.0:

sigwaitinfo interruption test
Blocked SIGUSR1, waiting with sigwaitinfo...
Parent: calling sigwaitinfo([SIGUSR1])...
Child: sending SIGALRM to interrupt parent
SIGALRM handler called
sigwaitinfo failed: errno = 87 (Operation canceled)
Expected: errno = 4 (EINTR)
Actual:   errno = 87 (Operation canceled)
SIGALRM handler was called: yes
Child exited with status: 0
>Fix:

>Release-Note:

>Audit-Trail:

Responsible-Changed-From-To: kern-bug-people->standards-manager
Responsible-Changed-By: dholland@NetBSD.org
Responsible-Changed-When: Sun, 10 Aug 2025 22:30:46 +0000
Responsible-Changed-Why:
Use correct category


State-Changed-From-To: open->analyzed
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Thu, 18 Dec 2025 14:43:43 +0000
State-Changed-Why:
Sorry for the delay.  Looks like this was a mistake that traces back to
vestiges of an earlier architecture for multithreading that NetBSD
abandoned in the mid-2000s, scheduler activations (PTHREAD_SA); it was
never intended to be exposed to userland even then, when the latest
POSIX spec, POSIX.1-2001, prescribed EINTR:

https://pubs.opengroup.org/onlinepubs/009604499/functions/sigtimedwait.html

The code was added in kern_sig.c rev. 1.135 in 2003 with logic to
return ECANCELED if the thread was woken, not by a signal for _this_
thread but by a signal for _some other thread_:

/* kern_sig.c 1.135 */
+	/*
+	 * Wait for signal to arrive. We can either be woken up or
+	 * time out.
+	 */
+	error = tsleep(&p->p_sigctx.ps_sigwait, PPAUSE|PCATCH, "sigwait", timo);
+
+	/*
+	 * Check if a signal from our wait set has arrived, or if it
+	 * was mere wakeup.
+	 */
+	if (!error) {
+		if ((signum = p->p_sigctx.ps_sigwaited) <= 0) {
+			/* wakeup via _lwp_wakeup() */
+			error = ECANCELED;
+		}
+	}

/* pthread_sig.c 1.9 */
+		/*
+		 * We are either the only one, or wait set was setup already.
+		 * Just do the syscall now.
+		 */
+		error = __sigtimedwait(&wset, info, (timeout) ? &timo : NULL);
+
+		pthread_spinlock(self, &pt_sigwaiting_lock);
+		if ((error && errno != ECANCELED)
+		    || (!error && __sigismember14(set, info->si_signo)) ) {
...
+		}
+
+		if (!error) {
+			/*
+			 * Got a signal, but not from _our_ wait set.
+			 * Scan the queue of sigwaiters and wakeup
+			 * the first thread waiting for this signal.
+			 */
...


https://cvsweb.netbsd.org/bsdweb.cgi/src/sys/kern/kern_sig.c#rev1.135
https://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libpthread/Attic/pthread_sig.c#rev1.9

EINTR doesn't appear in those diffs, but it can come flying out of
tsleep(9) and the sys___sigtimedwait function implementing the guts of
the sigtimedwait(2) syscall would pass it through in the error branch.
ECANCELED was used as a special error code meant only for use inside
libpthread, and was not supposed to leak outside.

However, this was buggy because the erstwhile tsleep(9) logic would
return EINTR in the `cancelled' case, so the code was tweaked a few
months later to check for EINTR and _none_ of the listed signals:

 	/*
-	 * Check if a signal from our wait set has arrived, or if it
-	 * was mere wakeup.
+	 * Need to find out if we woke as a result of lwp_wakeup()
+	 * or a signal outside our wait set.
 	 */
-	if (!error) {
-		if ((signum = p->p_sigctx.ps_sigwaited) <= 0) {
-			/* wakeup via _lwp_wakeup() */
-			error = ECANCELED;
-		}
+	if (error == EINTR && p->p_sigctx.ps_sigwaited
+	    && !firstsig(&p->p_sigctx.ps_siglist)) {
+		/* wakeup via _lwp_wakeup() */
+		error = ECANCELED;
+	} else if (!error && p->p_sigctx.ps_sigwaited) {
+		/* spurious wakeup - arrange for syscall restart */
+		error = ERESTART;
+		goto fail;
 	}

https://cvsweb.netbsd.org/bsdweb.cgi/src/sys/kern/kern_sig.c#rev1.171

That code might have been fine, since it only maps EINTR to ECANCELED
if none of the signals we're waiting for were delivered (not 100% sure
about that, perhaps ps_siglist had other entries too, but it's not
worthwhile to dig any deeper into 20-year-old abandoned logic!).

But later, in the renovation to remove SA on the newlock2 branch in
2007, this logic garbled in translation into `map EINTR to ECANCELED'
no matter what signals had been delivered in the interim:

/* kern_sig.c 1.228.2.2 */
-       /*
-        * Need to find out if we woke as a result of lwp_wakeup()
-        * or a signal outside our wait set.
-        */
-       if (error == EINTR && p->p_sigctx.ps_sigwaited
-           && !firstsig(&p->p_sigctx.ps_siglist)) {
-               /* wakeup via _lwp_wakeup() */
-               error = ECANCELED;
-       } else if (!error && p->p_sigctx.ps_sigwaited) {
-               /* spurious wakeup - arrange for syscall restart */
-               error = ERESTART;
-               goto fail;
-       }

/* sys_sig.c 1.1.2.1 */
+       /*
+        * Need to find out if we woke as a result of lwp_wakeup() or a
+        * signal outside our wait set.
+        */
+       if (l->l_sigwaited != NULL) {
+               if (error == EINTR) {
+                       /* wakeup via _lwp_wakeup() */
+                       error = ECANCELED;
+               } else if (!error) {
+                       /* spurious wakeup - arrange for syscall restart */
+                       error = ERESTART;
+               }
+       }

https://cvsweb.netbsd.org/bsdweb.cgi/src/sys/kern/sys_sig.c#rev1.1.2.1
https://cvsweb.netbsd.org/bsdweb.cgi/src/sys/kern/kern_sig.c#rev1.228.2.2

And that is the bug that you hit here.

Since the SA logic to request userland to yield is no longer relevant,
the internal ECANCELED magic is no longer relevant, and we should just
delete the `if (error == EINTR) { error = ECANCELED; }' branch.  And,
of course, we should add some automatic tests for this case, yesterday.


Responsible-Changed-From-To: standards-manager->riastradh
Responsible-Changed-By: riastradh@NetBSD.org
Responsible-Changed-When: Fri, 19 Dec 2025 04:46:52 +0000
Responsible-Changed-Why:
fixed in HEAD
needs pullup-11, pullup-10, pullup-9


State-Changed-From-To: analyzed->needs-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Fri, 19 Dec 2025 04:46:52 +0000
State-Changed-Why:
mine


From: "Taylor R Campbell" <riastradh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59586 CVS commit: src/sys/kern
Date: Fri, 19 Dec 2025 04:43:17 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Fri Dec 19 04:43:16 UTC 2025

 Modified Files:
 	src/sys/kern: sys_sig.c

 Log Message:
 sigtimedwait(2): Clarify some comments.

 No functional change intended.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation


 To generate a diff of this commit:
 cvs rdiff -u -r1.60 -r1.61 src/sys/kern/sys_sig.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/59586 CVS commit: src
Date: Fri, 19 Dec 2025 04:40:43 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Fri Dec 19 04:40:43 UTC 2025

 Modified Files:
 	src/sys/kern: sys_sig.c
 	src/tests/lib/libc/sys: t_sigtimedwait.c

 Log Message:
 sigtimedwait(2): Return EINTR, not ECANCELED.

 The return value ECANCELED was a vestige of the logic to implement
 sigtimedwait(2) in the SA (scheduler activations) era of NetBSD
 multithreading.  It was meant to be used purely internally to
 libpthread, not meant to leak outside to the caller of
 sigtimedwait(2).  But in the removal of SA in the newlock2 branch,
 something got lost in translation and we wound up having
 sigtimedwait(2) return ECANCELED when it should return EINTR when it
 is interrupted by an unblocked signal that was not in the signal set
 passed as an argument to wait for.

 POSIX.1-2024 sigtimedwait(2) spec:

 https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/sigtimedwait.html

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation


 To generate a diff of this commit:
 cvs rdiff -u -r1.58 -r1.59 src/sys/kern/sys_sig.c
 cvs rdiff -u -r1.3 -r1.4 src/tests/lib/libc/sys/t_sigtimedwait.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/59586 CVS commit: src
Date: Fri, 19 Dec 2025 04:41:02 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Fri Dec 19 04:41:02 UTC 2025

 Modified Files:
 	src/sys/kern: sys_sig.c
 	src/tests/lib/libc/sys: t_sigtimedwait.c

 Log Message:
 sigtimedwait(2): Return EINTR, not zero, if interrupted.

 sigtimedwait(2) should never return zero: zero is not a valid signal
 number, and sigtimedwait(2) is only supposed to return a valid signal
 number (one of the signals in the input set) or -1.

 Previously, if there was a timeout and the call was interrupted with
 ERESTART/EINTR for a signal other than one we're waiting for, the
 logic would call copyout to update the timeout -- and overwrite the
 error code we were supposed to return (ERESTART/EINTR) with the error
 code of copyout, even if copyout succeeds, leading the syscall to
 return the zero-initialized value of ksi.ksi_signo.  This also had
 the effect of completely neutering the ERESTART logic: instead of
 restarting, it would just return 0.

 Now we overwrite the error code only if copyout fails.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation


 To generate a diff of this commit:
 cvs rdiff -u -r1.59 -r1.60 src/sys/kern/sys_sig.c
 cvs rdiff -u -r1.4 -r1.5 src/tests/lib/libc/sys/t_sigtimedwait.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/59586 CVS commit: src/tests/lib/libc/sys
Date: Fri, 19 Dec 2025 04:40:19 +0000

 Module Name:	src
 Committed By:	riastradh
 Date:		Fri Dec 19 04:40:18 UTC 2025

 Modified Files:
 	src/tests/lib/libc/sys: t_sigtimedwait.c

 Log Message:
 t_sigtimedwait: Spruce up and add tests for interruption by signal.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation


 To generate a diff of this commit:
 cvs rdiff -u -r1.2 -r1.3 src/tests/lib/libc/sys/t_sigtimedwait.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: needs-pullups->pending-pullups
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Mon, 02 Feb 2026 04:36:55 +0000
State-Changed-Why:
pullup-11 #175 https://releng.netbsd.org/cgi-bin/req-11.cgi?show=175
pullup-10 #1233 https://releng.netbsd.org/cgi-bin/req-10.cgi?show=1233
pullup-9 #2003 https://releng.netbsd.org/cgi-bin/req-9.cgi?show=2003


From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59586 CVS commit: [netbsd-11] src
Date: Mon, 2 Feb 2026 19:41:51 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Mon Feb  2 19:41:51 UTC 2026

 Modified Files:
 	src/sys/kern [netbsd-11]: sys_sig.c
 	src/tests/lib/libc/sys [netbsd-11]: t_sigtimedwait.c

 Log Message:
 Pull up following revision(s) (requested by riastradh in ticket #175):

 	tests/lib/libc/sys/t_sigtimedwait.c: revision 1.3
 	tests/lib/libc/sys/t_sigtimedwait.c: revision 1.4
 	tests/lib/libc/sys/t_sigtimedwait.c: revision 1.5
 	sys/kern/sys_sig.c: revision 1.59
 	sys/kern/sys_sig.c: revision 1.60
 	sys/kern/sys_sig.c: revision 1.61

 t_sigtimedwait: Spruce up and add tests for interruption by signal.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation

 sigtimedwait(2): Return EINTR, not ECANCELED.

 The return value ECANCELED was a vestige of the logic to implement
 sigtimedwait(2) in the SA (scheduler activations) era of NetBSD
 multithreading.  It was meant to be used purely internally to
 libpthread, not meant to leak outside to the caller of
 sigtimedwait(2).  But in the removal of SA in the newlock2 branch,
 something got lost in translation and we wound up having
 sigtimedwait(2) return ECANCELED when it should return EINTR when it
 is interrupted by an unblocked signal that was not in the signal set
 passed as an argument to wait for.

 POSIX.1-2024 sigtimedwait(2) spec:
 https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/sigtimedwait.html

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation

 sigtimedwait(2): Return EINTR, not zero, if interrupted.

 sigtimedwait(2) should never return zero: zero is not a valid signal
 number, and sigtimedwait(2) is only supposed to return a valid signal
 number (one of the signals in the input set) or -1.

 Previously, if there was a timeout and the call was interrupted with
 ERESTART/EINTR for a signal other than one we're waiting for, the
 logic would call copyout to update the timeout -- and overwrite the
 error code we were supposed to return (ERESTART/EINTR) with the error
 code of copyout, even if copyout succeeds, leading the syscall to
 return the zero-initialized value of ksi.ksi_signo.  This also had
 the effect of completely neutering the ERESTART logic: instead of
 restarting, it would just return 0.

 Now we overwrite the error code only if copyout fails.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation
 sigtimedwait(2): Clarify some comments.
 No functional change intended.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation


 To generate a diff of this commit:
 cvs rdiff -u -r1.58 -r1.58.2.1 src/sys/kern/sys_sig.c
 cvs rdiff -u -r1.2 -r1.2.52.1 src/tests/lib/libc/sys/t_sigtimedwait.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59586 CVS commit: [netbsd-10] src
Date: Mon, 2 Feb 2026 19:43:28 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Mon Feb  2 19:43:28 UTC 2026

 Modified Files:
 	src/sys/kern [netbsd-10]: sys_sig.c
 	src/tests/lib/libc/sys [netbsd-10]: t_sigtimedwait.c

 Log Message:
 Pull up following revision(s) (requested by riastradh in ticket #1233):

 	tests/lib/libc/sys/t_sigtimedwait.c: revision 1.3
 	tests/lib/libc/sys/t_sigtimedwait.c: revision 1.4
 	tests/lib/libc/sys/t_sigtimedwait.c: revision 1.5
 	sys/kern/sys_sig.c: revision 1.59
 	sys/kern/sys_sig.c: revision 1.60
 	sys/kern/sys_sig.c: revision 1.61

 t_sigtimedwait: Spruce up and add tests for interruption by signal.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation

 sigtimedwait(2): Return EINTR, not ECANCELED.

 The return value ECANCELED was a vestige of the logic to implement
 sigtimedwait(2) in the SA (scheduler activations) era of NetBSD
 multithreading.  It was meant to be used purely internally to
 libpthread, not meant to leak outside to the caller of
 sigtimedwait(2).  But in the removal of SA in the newlock2 branch,
 something got lost in translation and we wound up having
 sigtimedwait(2) return ECANCELED when it should return EINTR when it
 is interrupted by an unblocked signal that was not in the signal set
 passed as an argument to wait for.

 POSIX.1-2024 sigtimedwait(2) spec:
 https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/sigtimedwait.html

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation

 sigtimedwait(2): Return EINTR, not zero, if interrupted.

 sigtimedwait(2) should never return zero: zero is not a valid signal
 number, and sigtimedwait(2) is only supposed to return a valid signal
 number (one of the signals in the input set) or -1.

 Previously, if there was a timeout and the call was interrupted with
 ERESTART/EINTR for a signal other than one we're waiting for, the
 logic would call copyout to update the timeout -- and overwrite the
 error code we were supposed to return (ERESTART/EINTR) with the error
 code of copyout, even if copyout succeeds, leading the syscall to
 return the zero-initialized value of ksi.ksi_signo.  This also had
 the effect of completely neutering the ERESTART logic: instead of
 restarting, it would just return 0.

 Now we overwrite the error code only if copyout fails.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation
 sigtimedwait(2): Clarify some comments.
 No functional change intended.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation


 To generate a diff of this commit:
 cvs rdiff -u -r1.56.4.1 -r1.56.4.2 src/sys/kern/sys_sig.c
 cvs rdiff -u -r1.2 -r1.2.48.1 src/tests/lib/libc/sys/t_sigtimedwait.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/59586 CVS commit: [netbsd-9] src
Date: Mon, 2 Feb 2026 20:53:20 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Mon Feb  2 20:53:20 UTC 2026

 Modified Files:
 	src/sys/kern [netbsd-9]: sys_sig.c
 	src/tests/lib/libc/sys [netbsd-9]: t_sigtimedwait.c

 Log Message:
 Pull up following revision(s) (requested by riastradh in ticket #2003):

 	tests/lib/libc/sys/t_sigtimedwait.c: revision 1.3
 	tests/lib/libc/sys/t_sigtimedwait.c: revision 1.4
 	tests/lib/libc/sys/t_sigtimedwait.c: revision 1.5
 	sys/kern/sys_sig.c: revision 1.59
 	sys/kern/sys_sig.c: revision 1.60
 	sys/kern/sys_sig.c: revision 1.61

 t_sigtimedwait: Spruce up and add tests for interruption by signal.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation

 sigtimedwait(2): Return EINTR, not ECANCELED.

 The return value ECANCELED was a vestige of the logic to implement
 sigtimedwait(2) in the SA (scheduler activations) era of NetBSD
 multithreading.  It was meant to be used purely internally to
 libpthread, not meant to leak outside to the caller of
 sigtimedwait(2).  But in the removal of SA in the newlock2 branch,
 something got lost in translation and we wound up having
 sigtimedwait(2) return ECANCELED when it should return EINTR when it
 is interrupted by an unblocked signal that was not in the signal set
 passed as an argument to wait for.
 POSIX.1-2024 sigtimedwait(2) spec:
    https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/sigtimedwait.html

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation

 sigtimedwait(2): Return EINTR, not zero, if interrupted.

 sigtimedwait(2) should never return zero: zero is not a valid signal
 number, and sigtimedwait(2) is only supposed to return a valid signal
 number (one of the signals in the input set) or -1.

 Previously, if there was a timeout and the call was interrupted with
 ERESTART/EINTR for a signal other than one we're waiting for, the
 logic would call copyout to update the timeout -- and overwrite the
 error code we were supposed to return (ERESTART/EINTR) with the error
 code of copyout, even if copyout succeeds, leading the syscall to
 return the zero-initialized value of ksi.ksi_signo.  This also had
 the effect of completely neutering the ERESTART logic: instead of
 restarting, it would just return 0.

 Now we overwrite the error code only if copyout fails.
 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation
 sigtimedwait(2): Clarify some comments.

 No functional change intended.

 PR standards/59586: sigwaitinfo() returns ECANCELED instead of EINTR
 - POSIX compliance violation


 To generate a diff of this commit:
 cvs rdiff -u -r1.47.4.4 -r1.47.4.5 src/sys/kern/sys_sig.c
 cvs rdiff -u -r1.2 -r1.2.36.1 src/tests/lib/libc/sys/t_sigtimedwait.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: pending-pullups->closed
State-Changed-By: riastradh@NetBSD.org
State-Changed-When: Tue, 19 May 2026 00:32:02 +0000
State-Changed-Why:
fixed in HEAD and pulled up to all branches


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.49 2026/05/14 01:52:41 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.