aboutsummaryrefslogtreecommitdiff
path: root/nptl/tst-pthread-attr-sigmask.c
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/tst-pthread-attr-sigmask.c')
-rw-r--r--nptl/tst-pthread-attr-sigmask.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/nptl/tst-pthread-attr-sigmask.c b/nptl/tst-pthread-attr-sigmask.c
new file mode 100644
index 0000000..8f854d8
--- /dev/null
+++ b/nptl/tst-pthread-attr-sigmask.c
@@ -0,0 +1,204 @@
+/* Tests for pthread_attr_setsigmask_np, pthread_attr_getsigmask_np.
+ Copyright (C) 2020 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/>. */
+
+/* This thread uses different masked status for SIGUSR1, SIGUSR2,
+ SIGHUP to determine if signal masks are applied to new threads as
+ expected. */
+
+#include <signal.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <threads.h>
+
+typedef bool signals[_NSIG];
+
+static const char *
+masked_or_unmasked (bool masked)
+{
+ if (masked)
+ return "masked";
+ else
+ return "unmasked";
+}
+
+/* Report an error if ACTUAL_MASK does not match EXPECTED_MASK.
+ CONTEXT is used in error messages. */
+static void
+check_sigmask (const char *context, signals expected_mask,
+ const sigset_t *actual_mask)
+{
+ for (int sig = 1; sig < _NSIG; ++sig)
+ if (sigismember (actual_mask, sig) != expected_mask[sig])
+ {
+ support_record_failure ();
+ printf ("error: %s: signal %d should be %s, but is %s\n",
+ context, sig,
+ masked_or_unmasked (sigismember (actual_mask, sig)),
+ masked_or_unmasked (expected_mask[sig]));
+ }
+}
+
+/* Report an error if the current thread signal mask does not match
+ EXPECTED_MASK. CONTEXT is used in error messages. */
+static void
+check_current_sigmask (const char *context, signals expected_mask)
+{
+ sigset_t actual_mask;
+ xpthread_sigmask (SIG_SETMASK, NULL, &actual_mask);
+ check_sigmask (context, expected_mask, &actual_mask);
+}
+
+/* Thread start routine which checks the current thread signal mask
+ against CLOSURE. */
+static void *
+check_sigmask_thread_function (void *closure)
+{
+ check_current_sigmask ("on thread", closure);
+ return NULL;
+}
+
+/* Same for C11 threads. */
+static int
+check_sigmask_thread_function_c11 (void *closure)
+{
+ check_current_sigmask ("on C11 thread", closure);
+ return 0;
+}
+
+/* Launch a POSIX thread with ATTR (which can be NULL) and check that
+ it has the expected signal mask. */
+static void
+check_posix_thread (pthread_attr_t *attr, signals expected_mask)
+{
+ xpthread_join (xpthread_create (attr, check_sigmask_thread_function,
+ expected_mask));
+}
+
+/* Launch a C11 thread and check that it has the expected signal
+ mask. */
+static void
+check_c11_thread (signals expected_mask)
+{
+ thrd_t thr;
+ TEST_VERIFY_EXIT (thrd_create (&thr, check_sigmask_thread_function_c11,
+ expected_mask) == thrd_success);
+ TEST_VERIFY_EXIT (thrd_join (thr, NULL) == thrd_success);
+}
+
+static int
+do_test (void)
+{
+ check_current_sigmask ("initial mask", (signals) { false, });
+ check_posix_thread (NULL, (signals) { false, });
+ check_c11_thread ((signals) { false, });
+
+ sigset_t set;
+ sigemptyset (&set);
+ sigaddset (&set, SIGUSR1);
+ xpthread_sigmask (SIG_SETMASK, &set, NULL);
+ check_current_sigmask ("SIGUSR1 masked", (signals) { [SIGUSR1] = true, });
+ /* The signal mask is inherited by the new thread. */
+ check_posix_thread (NULL, (signals) { [SIGUSR1] = true, });
+ check_c11_thread ((signals) { [SIGUSR1] = true, });
+
+ pthread_attr_t attr;
+ xpthread_attr_init (&attr);
+ TEST_COMPARE (pthread_attr_getsigmask_np (&attr, &set),
+ PTHREAD_ATTR_NO_SIGMASK_NP);
+ /* By default, the signal mask is inherited (even with an explicit
+ thread attribute). */
+ check_posix_thread (&attr, (signals) { [SIGUSR1] = true, });
+
+ /* Check that pthread_attr_getsigmask_np can obtain the signal
+ mask. */
+ sigemptyset (&set);
+ sigaddset (&set, SIGUSR2);
+ TEST_COMPARE (pthread_attr_setsigmask_np (&attr, &set), 0);
+ sigemptyset (&set);
+ TEST_COMPARE (pthread_attr_getsigmask_np (&attr, &set), 0);
+ check_sigmask ("pthread_attr_getsigmask_np", (signals) { [SIGUSR2] = true, },
+ &set);
+
+ /* Check that a thread is launched with the configured signal
+ mask. */
+ check_current_sigmask ("SIGUSR1 masked", (signals) { [SIGUSR1] = true, });
+ check_posix_thread (&attr, (signals) { [SIGUSR2] = true, });
+ check_current_sigmask ("SIGUSR1 masked", (signals) { [SIGUSR1] = true, });
+
+ /* But C11 threads remain at inheritance. */
+ check_c11_thread ((signals) { [SIGUSR1] = true, });
+
+ /* Check that filling the original signal set does not affect thread
+ creation. */
+ sigfillset (&set);
+ check_posix_thread (&attr, (signals) { [SIGUSR2] = true, });
+
+ /* Check that clearing the signal in the attribute restores
+ inheritance. */
+ TEST_COMPARE (pthread_attr_setsigmask_np (&attr, NULL), 0);
+ TEST_COMPARE (pthread_attr_getsigmask_np (&attr, &set),
+ PTHREAD_ATTR_NO_SIGMASK_NP);
+ check_posix_thread (&attr, (signals) { [SIGUSR1] = true, });
+
+ /* Mask SIGHUP via the default thread attribute. */
+ sigemptyset (&set);
+ sigaddset (&set, SIGHUP);
+ TEST_COMPARE (pthread_attr_setsigmask_np (&attr, &set), 0);
+ TEST_COMPARE (pthread_setattr_default_np (&attr), 0);
+
+ /* Check that the mask was applied to the default attribute. */
+ xpthread_attr_destroy (&attr);
+ TEST_COMPARE (pthread_getattr_default_np (&attr), 0);
+ sigaddset (&set, SIGHUP);
+ TEST_COMPARE (pthread_attr_getsigmask_np (&attr, &set), 0);
+ check_sigmask ("default attribute", (signals) { [SIGHUP] = true, }, &set);
+ xpthread_attr_destroy (&attr);
+
+ /* Check that the default attribute is applied. */
+ check_posix_thread (NULL, (signals) { [SIGHUP] = true, });
+ check_c11_thread ((signals) { [SIGHUP] = true, });
+
+ /* An explicit attribute with no signal mask triggers inheritance
+ even if the default has been changed. */
+ xpthread_attr_init (&attr);
+ check_posix_thread (&attr, (signals) { [SIGUSR1] = true, });
+
+ /* Explicitly setting the signal mask affects the new thread even
+ with a default attribute. */
+ sigemptyset (&set);
+ sigaddset (&set, SIGUSR2);
+ TEST_COMPARE (pthread_attr_setsigmask_np (&attr, &set), 0);
+ check_posix_thread (&attr, (signals) { [SIGUSR2] = true, });
+
+ /* Resetting the default attribute brings back the old inheritance
+ behavior. */
+ xpthread_attr_destroy (&attr);
+ xpthread_attr_init (&attr);
+ TEST_COMPARE (pthread_setattr_default_np (&attr), 0);
+ xpthread_attr_destroy (&attr);
+ check_posix_thread (NULL, (signals) { [SIGUSR1] = true, });
+ check_c11_thread ((signals) { [SIGUSR1] = true, });
+
+ return 0;
+}
+
+#include <support/test-driver.c>