diff options
Diffstat (limited to 'nptl/tst-pthread-attr-sigmask.c')
-rw-r--r-- | nptl/tst-pthread-attr-sigmask.c | 204 |
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 0000000000..8f854d8d11 --- /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> |