[hurd,commited] hurd: Fix cleaning on sigtimedwait timing out
Samuel Thibault
samuel.thibault@ens-lyon.org
Thu Mar 5 00:22:33 GMT 2026
sigtimedwait also needs to clean up preemptors and the blocked mask before
returning EAGAIN.
Also add some sigtimedwait testing.
---
signal/Makefile | 1 +
signal/tst-sigtimedwait-timeout.c | 99 +++++++++++++++++++++++++++++++
sysdeps/mach/hurd/sigtimedwait.c | 16 ++---
3 files changed, 108 insertions(+), 8 deletions(-)
create mode 100644 signal/tst-sigtimedwait-timeout.c
diff --git a/signal/Makefile b/signal/Makefile
index 7049c4b377..16050e82f6 100644
--- a/signal/Makefile
+++ b/signal/Makefile
@@ -61,6 +61,7 @@ tests := \
tst-sigset2 \
tst-sigsimple \
tst-sigwait-eintr \
+ tst-sigtimedwait-timeout \
# tests
include ../Rules
diff --git a/signal/tst-sigtimedwait-timeout.c b/signal/tst-sigtimedwait-timeout.c
new file mode 100644
index 0000000000..5acb079538
--- /dev/null
+++ b/signal/tst-sigtimedwait-timeout.c
@@ -0,0 +1,99 @@
+/* Test that sigtimedwait time out cleans up correctly for further signaling
+ Copyright (C) 2017-2026 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <time.h>
+#include <unistd.h>
+
+static int signaled;
+
+/* Handler for SIGUSR1. */
+static void
+sigusr1_handler (int signo)
+{
+ TEST_VERIFY (signo == SIGUSR1);
+ signaled++;
+}
+
+/* Spawn a subprocess to send two SIGUSR1 signals.
+ Return the PID of the process. */
+static pid_t
+signal_sender (void)
+{
+ pid_t pid = xfork ();
+ if (pid == 0)
+ {
+ static const struct timespec delay = { .tv_sec = 1 };
+ if (nanosleep (&delay, NULL) != 0)
+ FAIL_EXIT1 ("nanosleep: %m");
+ if (kill (getppid (), SIGUSR1) != 0)
+ FAIL_EXIT1 ("kill (SIGUSR1): %m");
+ if (nanosleep (&delay, NULL) != 0)
+ FAIL_EXIT1 ("nanosleep: %m");
+ if (kill (getppid (), SIGUSR1) != 0)
+ FAIL_EXIT1 ("kill (SIGUSR1): %m");
+ _exit (0);
+ }
+ return pid;
+}
+
+static int
+do_test (void)
+{
+ if (signal (SIGUSR1, sigusr1_handler) == SIG_ERR)
+ FAIL_EXIT1 ("signal (SIGUSR1): %m\n");
+
+ sigset_t sigs;
+ sigemptyset (&sigs);
+ sigaddset (&sigs, SIGUSR1);
+ if (sigprocmask (SIG_BLOCK, &sigs, NULL) != 0)
+ FAIL_EXIT1 ("sigprocmask (SIGBLOCK, SIGUSR1): %m");
+ pid_t pid = signal_sender ();
+
+ siginfo_t info;
+ struct timespec ts = { .tv_nsec = 500000000 };
+ int ret = sigtimedwait (&sigs, &info, &ts);
+ TEST_VERIFY (ret == -1);
+ TEST_VERIFY (errno == EAGAIN);
+
+ static const struct timespec delay = { .tv_sec = 1 };
+ if (nanosleep (&delay, NULL) != 0)
+ FAIL_EXIT1 ("nanosleep: %m");
+ TEST_VERIFY (signaled == 0);
+
+ if (sigprocmask (SIG_UNBLOCK, &sigs, NULL) != 0)
+ FAIL_EXIT1 ("sigprocmask (SIGBLOCK, SIGUSR1): %m");
+ TEST_VERIFY (signaled == 1);
+
+ if (nanosleep (&delay, NULL) != -1)
+ FAIL_EXIT1 ("nanosleep: %m");
+ TEST_VERIFY (errno == EINTR);
+ TEST_VERIFY (signaled == 2);
+
+ int status;
+ xwaitpid (pid, &status, 0);
+ TEST_VERIFY (status == 0);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/mach/hurd/sigtimedwait.c b/sysdeps/mach/hurd/sigtimedwait.c
index 918af14a47..4ffdc1b2e6 100644
--- a/sysdeps/mach/hurd/sigtimedwait.c
+++ b/sysdeps/mach/hurd/sigtimedwait.c
@@ -147,17 +147,17 @@ __sigtimedwait (const sigset_t *set, siginfo_t *info,
/* Timed out. */
signo = __hurd_fail (EAGAIN);
}
- else
- {
- assert (signo);
- _hurd_sigstate_lock (ss);
+ assert (signo);
- /* Delete our preemptor. */
- assert (ss->preemptors == &preemptor);
- ss->preemptors = preemptor.next;
- }
+ _hurd_sigstate_lock (ss);
+
+ /* Delete our preemptor. */
+ assert (ss->preemptors == &preemptor);
+ ss->preemptors = preemptor.next;
+ /* Restore the blocking mask. */
+ ss->blocked = blocked;
all_done:
_hurd_sigstate_unlock (ss);
--
2.51.0
More information about the Libc-alpha
mailing list