These patches add the 'sigdelay' module, that I already presented a couple of days ago. It blocks a signal from delivery across the entire process, not only in a single thread.
2026-04-15 Bruno Haible <[email protected]> sigdelay: Add tests. * tests/test-sigdelay1.c: New file, based on tests/test-pthread_sigmask1.c. * tests/test-sigdelay2.c: New file, based on tests/test-pthread_sigmask2.c. * modules/sigdelay-tests: New file. sigdelay: New module. * lib/sigdelay.h: New file. * lib/sigdelay.c: New file. * modules/sigdelay: New file. 2026-04-15 Bruno Haible <[email protected]> pthread_sigmask tests: Enhance test. * tests/test-pthread_sigmask2.c (killer_thread1): Renamed from killer_thread. (killer_thread2): New variable. (killer_thread1_func): Renamed from killer_thread_func. (killer_thread2_func): New function. (main): Add a second test with killer_thread2. 2026-04-15 Bruno Haible <[email protected]> pthread_sigmask tests: More details about VirtualBox / KVM bug. * tests/test-pthread_sigmask1.c (main): Refine comment regarding VirtualBox / KVM bug. * tests/test-pthread_sigmask2.c (main): Likewise.
From 3daeaa60a16bd320950b402b64164f96316c2196 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Wed, 15 Apr 2026 13:45:35 +0200 Subject: [PATCH 1/4] pthread_sigmask tests: More details about VirtualBox / KVM bug. * tests/test-pthread_sigmask1.c (main): Refine comment regarding VirtualBox / KVM bug. * tests/test-pthread_sigmask2.c (main): Likewise. --- ChangeLog | 7 +++++++ tests/test-pthread_sigmask1.c | 3 ++- tests/test-pthread_sigmask2.c | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index fb6babd1ff..4bef6f5975 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2026-04-15 Bruno Haible <[email protected]> + + pthread_sigmask tests: More details about VirtualBox / KVM bug. + * tests/test-pthread_sigmask1.c (main): Refine comment regarding + VirtualBox / KVM bug. + * tests/test-pthread_sigmask2.c (main): Likewise. + 2026-04-14 Bruno Haible <[email protected]> sigprocmask: On mingw, avoid dependency on libwinpthread. diff --git a/tests/test-pthread_sigmask1.c b/tests/test-pthread_sigmask1.c index d97e75d27a..e088eb61ea 100644 --- a/tests/test-pthread_sigmask1.c +++ b/tests/test-pthread_sigmask1.c @@ -46,7 +46,8 @@ int main () { /* This test occasionally fails on Linux (glibc or musl libc), in a - VirtualBox VM with paravirtualization = Default or KVM, with ??? 2 CPUs. + VirtualBox VM with paravirtualization = Default or KVM, with ??? 2 CPUs, + when "Nested VT-x/AMD-V" and "PAE/NX" are not both enabled. Skip the test in this situation. */ if (is_running_under_virtualbox_kvm () && num_cpus () > 1) { diff --git a/tests/test-pthread_sigmask2.c b/tests/test-pthread_sigmask2.c index 7c71984ac6..c4b6c1af44 100644 --- a/tests/test-pthread_sigmask2.c +++ b/tests/test-pthread_sigmask2.c @@ -53,7 +53,8 @@ int main () { /* This test occasionally fails on Linux (glibc or musl libc), in a - VirtualBox VM with paravirtualization = Default or KVM, with ??? 2 CPUs. + VirtualBox VM with paravirtualization = Default or KVM, with ??? 2 CPUs, + when "Nested VT-x/AMD-V" and "PAE/NX" are not both enabled. Skip the test in this situation. */ if (is_running_under_virtualbox_kvm () && num_cpus () > 1) { -- 2.52.0
>From 2448235dbfa03df0814f3ed823fb9cd7b11cc5ef Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Wed, 15 Apr 2026 13:45:44 +0200 Subject: [PATCH 2/4] pthread_sigmask tests: Enhance test. * tests/test-pthread_sigmask2.c (killer_thread1): Renamed from killer_thread. (killer_thread2): New variable. (killer_thread1_func): Renamed from killer_thread_func. (killer_thread2_func): New function. (main): Add a second test with killer_thread2. --- ChangeLog | 10 ++++++++ tests/test-pthread_sigmask2.c | 43 +++++++++++++++++++++++++++++------ 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4bef6f5975..318316cd17 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2026-04-15 Bruno Haible <[email protected]> + + pthread_sigmask tests: Enhance test. + * tests/test-pthread_sigmask2.c (killer_thread1): Renamed from + killer_thread. + (killer_thread2): New variable. + (killer_thread1_func): Renamed from killer_thread_func. + (killer_thread2_func): New function. + (main): Add a second test with killer_thread2. + 2026-04-15 Bruno Haible <[email protected]> pthread_sigmask tests: More details about VirtualBox / KVM bug. diff --git a/tests/test-pthread_sigmask2.c b/tests/test-pthread_sigmask2.c index c4b6c1af44..31a880a840 100644 --- a/tests/test-pthread_sigmask2.c +++ b/tests/test-pthread_sigmask2.c @@ -31,16 +31,25 @@ #if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS static pthread_t main_thread; -static pthread_t killer_thread; +static pthread_t killer_thread1; +static pthread_t killer_thread2; static void * -killer_thread_func (_GL_UNUSED void *arg) +killer_thread1_func (_GL_UNUSED void *arg) { sleep (1); pthread_kill (main_thread, SIGINT); return NULL; } +static void * +killer_thread2_func (_GL_UNUSED void *arg) +{ + sleep (1); + pthread_kill (pthread_self (), SIGINT); + return NULL; +} + static volatile int sigint_occurred; static void @@ -63,10 +72,9 @@ main () return 77; } - sigset_t set; - signal (SIGINT, sigint_handler); + sigset_t set; sigemptyset (&set); sigaddset (&set, SIGINT); @@ -81,7 +89,8 @@ main () /* Request a SIGINT signal from another thread. */ main_thread = pthread_self (); - ASSERT (pthread_create (&killer_thread, NULL, killer_thread_func, NULL) == 0); + ASSERT (pthread_create (&killer_thread1, NULL, killer_thread1_func, NULL) + == 0); /* Wait. */ sleep (2); @@ -98,9 +107,29 @@ main () before the call to pthread_sigmask() returns." */ ASSERT (sigint_occurred == 1); - /* Clean up the thread. This avoid a "ThreadSanitizer: thread leak" warning + /* Request a SIGINT signal from another thread. */ + ASSERT (pthread_create (&killer_thread2, NULL, killer_thread2_func, NULL) + == 0); + + /* Block SIGINT. */ + ASSERT (pthread_sigmask (SIG_BLOCK, &set, NULL) == 0); + + /* Wait. */ + sleep (2); + + /* The signal should have arrived yet, because it is blocked only in the + main thread, not in killer_thread2. */ + ASSERT (sigint_occurred == 2); + + /* Unblock SIGINT. */ + ASSERT (pthread_sigmask (SIG_UNBLOCK, &set, NULL) == 0); + + ASSERT (sigint_occurred == 2); + + /* Clean up the threads. This avoids a "ThreadSanitizer: thread leak" warning from "gcc -fsanitize=thread". */ - ASSERT (pthread_join (killer_thread, NULL) == 0); + ASSERT (pthread_join (killer_thread1, NULL) == 0); + ASSERT (pthread_join (killer_thread2, NULL) == 0); return test_exit_status; } -- 2.52.0
From 006d544083a6a595b1220b4fec409ea9f2dbf501 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Wed, 15 Apr 2026 13:45:52 +0200 Subject: [PATCH 3/4] sigdelay: New module. * lib/sigdelay.h: New file. * lib/sigdelay.c: New file. * modules/sigdelay: New file. --- ChangeLog | 7 +++ lib/sigdelay.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++ lib/sigdelay.h | 54 +++++++++++++++++++++ modules/sigdelay | 31 ++++++++++++ 4 files changed, 211 insertions(+) create mode 100644 lib/sigdelay.c create mode 100644 lib/sigdelay.h create mode 100644 modules/sigdelay diff --git a/ChangeLog b/ChangeLog index 318316cd17..b1079e902d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2026-04-15 Bruno Haible <[email protected]> + + sigdelay: New module. + * lib/sigdelay.h: New file. + * lib/sigdelay.c: New file. + * modules/sigdelay: New file. + 2026-04-15 Bruno Haible <[email protected]> pthread_sigmask tests: Enhance test. diff --git a/lib/sigdelay.c b/lib/sigdelay.c new file mode 100644 index 0000000000..d69fa6126b --- /dev/null +++ b/lib/sigdelay.c @@ -0,0 +1,119 @@ +/* Delaying the delivery of signals to the current process. + Copyright (C) 2026 Free Software Foundation, Inc. + + This file 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. + + This file 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 this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible. */ + +#include <config.h> + +/* Specification. */ +#include "sigdelay.h" + +#include <errno.h> +#include <stdcountof.h> +#include <stdlib.h> + +#include "glthread/lock.h" +#include "thread-optim.h" +#include "sig-handler.h" + +/* State regarding a single signal. */ +struct state +{ + /* Number of times sigdelay (SIG_BLOCK, ...) was invoked for this signal. */ + unsigned int count; + /* If count > 0: The original action for the signal. */ + struct sigaction saved_action; + /* Whether this signal was caught and is waiting to be re-delivered. */ + unsigned int volatile caught; +}; + +/* The state for all signals. + Size 32 would not be sufficient: On HP-UX, SIGXCPU = 33, SIGXFSZ = 34. */ +static struct state states[64]; + +static _GL_ASYNC_SAFE void +delaying_handler (int sig) +{ + if (sig >= 0 && sig < countof (states)) + states[sig].caught = 1; +} + +/* Lock that makes sigdelay multi-thread safe. */ +gl_lock_define_initialized (static, sigdelay_lock) + +int +sigdelay (int how, const sigset_t *restrict set, sigset_t *restrict old_set) +{ + if (!(how == SIG_BLOCK || how == SIG_UNBLOCK)) + { + errno = EINVAL; + return -1; + } + + if (old_set != NULL) + sigemptyset (old_set); + + bool mt = gl_multithreaded (); + + if (mt) gl_lock_lock (sigdelay_lock); + + if (old_set != NULL) + for (int sig = 1; sig < countof (states); sig++) + if (states[sig].count > 0) + sigaddset (old_set, sig); + + for (int sig = 1; sig < countof (states); sig++) + if (sigismember (set, sig)) + { + switch (how) + { + case SIG_BLOCK: + if (states[sig].count == 0) + { + states[sig].caught = 0; + + struct sigaction delaying_action; + delaying_action.sa_handler = delaying_handler; + delaying_action.sa_flags = SA_NODEFER; + sigemptyset (&delaying_action.sa_mask); + if (sigaction (sig, &delaying_action, + &states[sig].saved_action) < 0) + abort (); + } + states[sig].count++; + break; + + case SIG_UNBLOCK: + if (states[sig].count == 0) + /* Invalid call. */ + abort (); + states[sig].count--; + if (states[sig].count == 0) + { + unsigned int caught = states[sig].caught; + if (sigaction (sig, &states[sig].saved_action, NULL) < 0) + abort (); + if (caught) + raise (sig); + } + break; + } + } + + if (mt) gl_lock_unlock (sigdelay_lock); + + return 0; +} diff --git a/lib/sigdelay.h b/lib/sigdelay.h new file mode 100644 index 0000000000..18489bfb1d --- /dev/null +++ b/lib/sigdelay.h @@ -0,0 +1,54 @@ +/* Delaying the delivery of signals to the current process. + Copyright (C) 2026 Free Software Foundation, Inc. + + This file 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. + + This file 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 this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible. */ + +#ifndef _SIGDELAY_H +#define _SIGDELAY_H + +#include <signal.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* While pthread_sigmask() can block the delivery of a signal to a particular + thread and thus ??? in the case of a process with a single thread ??? actually + delay the signal, POSIX lacks a facility for blocking or delaying a signal + process-wide, i.e. for all threads of the process at once. + + The sigdelay() function is such a facility. + It assumes that the signal handler for the affected signals does not change + between matching sigdelay (SIG_BLOCK, ...) and sigdelay (SIG_UNBLOCK, ...) + invocations. */ + +/* With HOW = SIG_BLOCK, this function adds the signals from SET to the set + of delayed signals. + With HOW = SIG_UNBLOCK, this function removes the signals from SET from the + set of delayed signals. + This function works cumulatively, that is, when a signal was added N times, + it also needs to be removed N times in order to restore the initial state. + If OLD_SET is non-NULL, this function also stores the previous set of + delayed signals in *OLD_SET. + Returns 0 if successful, or -1 with errno set in case of failure. */ +extern int sigdelay (int how, const sigset_t *restrict set, + sigset_t *restrict old_set); + +#ifdef __cplusplus +} +#endif + +#endif /* _SIGDELAY_H */ diff --git a/modules/sigdelay b/modules/sigdelay new file mode 100644 index 0000000000..a370a2d607 --- /dev/null +++ b/modules/sigdelay @@ -0,0 +1,31 @@ +Description: +Delaying the delivery of signals to the current process. + +Files: +lib/sigdelay.h +lib/sigdelay.c + +Depends-on: +lock +sigaction +thread-optim +raise +stdcountof-h + +configure.ac: +AC_REQUIRE([AC_C_RESTRICT]) + +Makefile.am: +lib_SOURCES += sigdelay.c + +Include: +"sigdelay.h" + +Link: +$(LIBTHREAD) + +License: +LGPLv2+ + +Maintainer: +Bruno Haible -- 2.52.0
From 001a31578623e5bffceb5845cddaad46a9c9505d Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Wed, 15 Apr 2026 13:45:58 +0200 Subject: [PATCH 4/4] sigdelay: Add tests. * tests/test-sigdelay1.c: New file, based on tests/test-pthread_sigmask1.c. * tests/test-sigdelay2.c: New file, based on tests/test-pthread_sigmask2.c. * modules/sigdelay-tests: New file. --- ChangeLog | 7 ++ modules/sigdelay-tests | 20 ++++++ tests/test-sigdelay1.c | 104 ++++++++++++++++++++++++++++++ tests/test-sigdelay2.c | 143 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+) create mode 100644 modules/sigdelay-tests create mode 100644 tests/test-sigdelay1.c create mode 100644 tests/test-sigdelay2.c diff --git a/ChangeLog b/ChangeLog index b1079e902d..761d1edc0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2026-04-15 Bruno Haible <[email protected]> + sigdelay: Add tests. + * tests/test-sigdelay1.c: New file, based on + tests/test-pthread_sigmask1.c. + * tests/test-sigdelay2.c: New file, based on + tests/test-pthread_sigmask2.c. + * modules/sigdelay-tests: New file. + sigdelay: New module. * lib/sigdelay.h: New file. * lib/sigdelay.c: New file. diff --git a/modules/sigdelay-tests b/modules/sigdelay-tests new file mode 100644 index 0000000000..2c56ff4ba5 --- /dev/null +++ b/modules/sigdelay-tests @@ -0,0 +1,20 @@ +Files: +tests/test-sigdelay1.c +tests/test-sigdelay2.c +tests/virtualbox.h +tests/macros.h + +Depends-on: +inttypes-h +sleep +pthread-thread +streq +memeq + +configure.ac: + +Makefile.am: +TESTS += test-sigdelay1 test-sigdelay2 +check_PROGRAMS += test-sigdelay1 test-sigdelay2 +test_sigdelay1_LDADD = $(LDADD) @LIBTHREAD@ +test_sigdelay2_LDADD = $(LDADD) @LIBMULTITHREAD@ diff --git a/tests/test-sigdelay1.c b/tests/test-sigdelay1.c new file mode 100644 index 0000000000..a6b3e4b54f --- /dev/null +++ b/tests/test-sigdelay1.c @@ -0,0 +1,104 @@ +/* Test of sigdelay in a single-threaded program. + Copyright (C) 2011-2026 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <[email protected]>, 2026. */ + +#include <config.h> + +/* Specification. */ +#include "sigdelay.h" + +#include <errno.h> +#include <inttypes.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "virtualbox.h" +#include "macros.h" + +#if !(defined _WIN32 && !defined __CYGWIN__) + +static volatile int sigint_occurred; + +static void +sigint_handler (_GL_UNUSED int sig) +{ + sigint_occurred++; +} + +int +main () +{ + /* This test occasionally fails on Linux (glibc or musl libc), in a + VirtualBox VM with paravirtualization = Default or KVM, with ??? 2 CPUs, + when "Nested VT-x/AMD-V" and "PAE/NX" are not both enabled. + Skip the test in this situation. */ + if (is_running_under_virtualbox_kvm () && num_cpus () > 1) + { + fputs ("Skipping test: avoiding VirtualBox bug with KVM paravirtualization\n", + stderr); + return 77; + } + + signal (SIGINT, sigint_handler); + + sigset_t set; + sigemptyset (&set); + sigaddset (&set, SIGINT); + + /* Check error handling. */ + ASSERT (sigdelay (1729, &set, NULL) == -1); + ASSERT (errno == EINVAL); + + /* Block SIGINT. */ + ASSERT (sigdelay (SIG_BLOCK, &set, NULL) == 0); + + /* Request a SIGINT signal from outside. */ + char command[80]; + intmax_t pid = getpid (); + sprintf (command, "sh -c 'sleep 1; kill -INT %"PRIdMAX"' &", pid); + ASSERT (system (command) == 0); + + /* Wait. */ + sleep (2); + + /* The signal should not have arrived yet, because it is blocked. */ + ASSERT (sigint_occurred == 0); + + /* Unblock SIGINT. */ + ASSERT (sigdelay (SIG_UNBLOCK, &set, NULL) == 0); + + /* The signal should have arrived now. */ + ASSERT (sigint_occurred == 1); + + return test_exit_status; +} + +#else + +/* On native Windows, getpid() values and the arguments that are passed to + the (Cygwin?) 'kill' program are not necessarily related. */ + +int +main () +{ + fputs ("Skipping test: native Windows platform\n", stderr); + return 77; +} + +#endif diff --git a/tests/test-sigdelay2.c b/tests/test-sigdelay2.c new file mode 100644 index 0000000000..7d15d6de5b --- /dev/null +++ b/tests/test-sigdelay2.c @@ -0,0 +1,143 @@ +/* Test of sigdelay in a multi-threaded process. + Copyright (C) 2011-2026 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <[email protected]>, 2026. */ + +#include <config.h> + +/* Specification. */ +#include "sigdelay.h" + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +#include "virtualbox.h" +#include "macros.h" + +#if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS + +static pthread_t main_thread; +static pthread_t killer_thread1; +static pthread_t killer_thread2; + +static void * +killer_thread1_func (_GL_UNUSED void *arg) +{ + sleep (1); + pthread_kill (main_thread, SIGINT); + return NULL; +} + +static void * +killer_thread2_func (_GL_UNUSED void *arg) +{ + sleep (1); + pthread_kill (pthread_self (), SIGINT); + return NULL; +} + +static volatile int sigint_occurred; + +static void +sigint_handler (_GL_UNUSED int sig) +{ + sigint_occurred++; +} + +int +main () +{ + /* This test occasionally fails on Linux (glibc or musl libc), in a + VirtualBox VM with paravirtualization = Default or KVM, with ??? 2 CPUs, + when "Nested VT-x/AMD-V" and "PAE/NX" are not both enabled. + Skip the test in this situation. */ + if (is_running_under_virtualbox_kvm () && num_cpus () > 1) + { + fputs ("Skipping test: avoiding VirtualBox bug with KVM paravirtualization\n", + stderr); + return 77; + } + + signal (SIGINT, sigint_handler); + + sigset_t set; + sigemptyset (&set); + sigaddset (&set, SIGINT); + + /* Check error handling. */ + ASSERT (sigdelay (1729, &set, NULL) == -1); + ASSERT (errno == EINVAL); + + /* Block SIGINT. */ + ASSERT (sigdelay (SIG_BLOCK, &set, NULL) == 0); + + /* Request a SIGINT signal from another thread. */ + main_thread = pthread_self (); + ASSERT (pthread_create (&killer_thread1, NULL, killer_thread1_func, NULL) + == 0); + + /* Wait. */ + sleep (2); + + /* The signal should not have arrived yet, because it is blocked. */ + ASSERT (sigint_occurred == 0); + + /* Unblock SIGINT. */ + ASSERT (sigdelay (SIG_UNBLOCK, &set, NULL) == 0); + + /* The signal should have arrived now. */ + ASSERT (sigint_occurred == 1); + + /* Request a SIGINT signal from another thread. */ + ASSERT (pthread_create (&killer_thread2, NULL, killer_thread2_func, NULL) + == 0); + + /* Block SIGINT. */ + ASSERT (sigdelay (SIG_BLOCK, &set, NULL) == 0); + + /* Wait. */ + sleep (2); + + /* The signal should not have arrived yet, because it is blocked. */ + ASSERT (sigint_occurred == 1); + + /* Unblock SIGINT. */ + ASSERT (sigdelay (SIG_UNBLOCK, &set, NULL) == 0); + + /* The signal should have arrived now. */ + ASSERT (sigint_occurred == 2); + + /* Clean up the threads. This avoids a "ThreadSanitizer: thread leak" warning + from "gcc -fsanitize=thread". */ + ASSERT (pthread_join (killer_thread1, NULL) == 0); + ASSERT (pthread_join (killer_thread2, NULL) == 0); + + return test_exit_status; +} + +#else + +int +main () +{ + fputs ("Skipping test: POSIX threads not enabled\n", stderr); + return 77; +} + +#endif -- 2.52.0
