1 /* Tests for pthread_attr_setsigmask_np, pthread_attr_getsigmask_np.
2    Copyright (C) 2020-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 /* This thread uses different masked status for SIGUSR1, SIGUSR2,
20    SIGHUP to determine if signal masks are applied to new threads as
21    expected.  */
22 
23 #include <signal.h>
24 #include <stdbool.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <support/check.h>
28 #include <support/xsignal.h>
29 #include <support/xthread.h>
30 #include <threads.h>
31 
32 typedef bool signals[_NSIG];
33 
34 static const char *
masked_or_unmasked(bool masked)35 masked_or_unmasked (bool masked)
36 {
37   if (masked)
38     return "masked";
39   else
40     return "unmasked";
41 }
42 
43 /* Report an error if ACTUAL_MASK does not match EXPECTED_MASK.
44    CONTEXT is used in error messages.  */
45 static void
check_sigmask(const char * context,signals expected_mask,const sigset_t * actual_mask)46 check_sigmask (const char *context, signals expected_mask,
47                const sigset_t *actual_mask)
48 {
49   for (int sig = 1; sig < _NSIG; ++sig)
50     if (sigismember (actual_mask, sig) != expected_mask[sig])
51       {
52         support_record_failure ();
53         printf ("error: %s: signal %d should be %s, but is %s\n",
54                 context, sig,
55                 masked_or_unmasked (sigismember (actual_mask, sig)),
56                 masked_or_unmasked (expected_mask[sig]));
57       }
58 }
59 
60 /* Report an error if the current thread signal mask does not match
61    EXPECTED_MASK.  CONTEXT is used in error messages.  */
62 static void
check_current_sigmask(const char * context,signals expected_mask)63 check_current_sigmask (const char *context, signals expected_mask)
64 {
65   sigset_t actual_mask;
66   xpthread_sigmask (SIG_SETMASK, NULL, &actual_mask);
67   check_sigmask (context, expected_mask, &actual_mask);
68 }
69 
70 /* Thread start routine which checks the current thread signal mask
71    against CLOSURE.  */
72 static void *
check_sigmask_thread_function(void * closure)73 check_sigmask_thread_function (void *closure)
74 {
75   check_current_sigmask ("on thread", closure);
76   return NULL;
77 }
78 
79 /* Same for C11 threads.  */
80 static int
check_sigmask_thread_function_c11(void * closure)81 check_sigmask_thread_function_c11 (void *closure)
82 {
83   check_current_sigmask ("on C11 thread", closure);
84   return 0;
85 }
86 
87 /* Launch a POSIX thread with ATTR (which can be NULL) and check that
88    it has the expected signal mask.  */
89 static void
check_posix_thread(pthread_attr_t * attr,signals expected_mask)90 check_posix_thread (pthread_attr_t *attr, signals expected_mask)
91 {
92   xpthread_join (xpthread_create (attr, check_sigmask_thread_function,
93                                   expected_mask));
94 }
95 
96 /* Launch a C11 thread and check that it has the expected signal
97    mask.  */
98 static void
check_c11_thread(signals expected_mask)99 check_c11_thread (signals expected_mask)
100 {
101   thrd_t thr;
102   TEST_VERIFY_EXIT (thrd_create (&thr, check_sigmask_thread_function_c11,
103                                  expected_mask) == thrd_success);
104   TEST_VERIFY_EXIT (thrd_join (thr, NULL) == thrd_success);
105 }
106 
107 static int
do_test(void)108 do_test (void)
109 {
110   check_current_sigmask ("initial mask", (signals) { false, });
111   check_posix_thread (NULL, (signals) { false, });
112   check_c11_thread ((signals) { false, });
113 
114   sigset_t set;
115   sigemptyset (&set);
116   sigaddset (&set, SIGUSR1);
117   xpthread_sigmask (SIG_SETMASK, &set, NULL);
118   check_current_sigmask ("SIGUSR1 masked", (signals) { [SIGUSR1] = true, });
119   /* The signal mask is inherited by the new thread.  */
120   check_posix_thread (NULL, (signals) { [SIGUSR1] = true, });
121   check_c11_thread ((signals) { [SIGUSR1] = true, });
122 
123   pthread_attr_t attr;
124   xpthread_attr_init (&attr);
125   TEST_COMPARE (pthread_attr_getsigmask_np (&attr, &set),
126                 PTHREAD_ATTR_NO_SIGMASK_NP);
127   /* By default, the signal mask is inherited (even with an explicit
128      thread attribute).  */
129   check_posix_thread (&attr, (signals) { [SIGUSR1] = true, });
130 
131   /* Check that pthread_attr_getsigmask_np can obtain the signal
132      mask.  */
133   sigemptyset (&set);
134   sigaddset (&set, SIGUSR2);
135   TEST_COMPARE (pthread_attr_setsigmask_np (&attr, &set), 0);
136   sigemptyset (&set);
137   TEST_COMPARE (pthread_attr_getsigmask_np (&attr, &set), 0);
138   check_sigmask ("pthread_attr_getsigmask_np", (signals) { [SIGUSR2] = true, },
139                  &set);
140 
141   /* Check that a thread is launched with the configured signal
142      mask.  */
143   check_current_sigmask ("SIGUSR1 masked", (signals) { [SIGUSR1] = true, });
144   check_posix_thread (&attr, (signals) { [SIGUSR2] = true, });
145   check_current_sigmask ("SIGUSR1 masked", (signals) { [SIGUSR1] = true, });
146 
147   /* But C11 threads remain at inheritance.  */
148   check_c11_thread ((signals) { [SIGUSR1] = true, });
149 
150   /* Check that filling the original signal set does not affect thread
151      creation.  */
152   sigfillset (&set);
153   check_posix_thread (&attr, (signals) { [SIGUSR2] = true, });
154 
155   /* Check that clearing the signal in the attribute restores
156      inheritance.  */
157   TEST_COMPARE (pthread_attr_setsigmask_np (&attr, NULL), 0);
158   TEST_COMPARE (pthread_attr_getsigmask_np (&attr, &set),
159                 PTHREAD_ATTR_NO_SIGMASK_NP);
160   check_posix_thread (&attr, (signals) { [SIGUSR1] = true, });
161 
162   /* Mask SIGHUP via the default thread attribute.  */
163   sigemptyset (&set);
164   sigaddset (&set, SIGHUP);
165   TEST_COMPARE (pthread_attr_setsigmask_np (&attr, &set), 0);
166   TEST_COMPARE (pthread_setattr_default_np (&attr), 0);
167 
168   /* Check that the mask was applied to the default attribute.  */
169   xpthread_attr_destroy (&attr);
170   TEST_COMPARE (pthread_getattr_default_np (&attr), 0);
171   sigaddset (&set, SIGHUP);
172   TEST_COMPARE (pthread_attr_getsigmask_np (&attr, &set), 0);
173   check_sigmask ("default attribute", (signals) { [SIGHUP] = true, }, &set);
174   xpthread_attr_destroy (&attr);
175 
176   /* Check that the default attribute is applied.  */
177   check_posix_thread (NULL, (signals) { [SIGHUP] = true, });
178   check_c11_thread ((signals) { [SIGHUP] = true, });
179 
180   /* An explicit attribute with no signal mask triggers inheritance
181      even if the default has been changed.  */
182   xpthread_attr_init (&attr);
183   check_posix_thread (&attr, (signals) { [SIGUSR1] = true, });
184 
185   /* Explicitly setting the signal mask affects the new thread even
186      with a default attribute.  */
187   sigemptyset (&set);
188   sigaddset (&set, SIGUSR2);
189   TEST_COMPARE (pthread_attr_setsigmask_np (&attr, &set), 0);
190   check_posix_thread (&attr, (signals) { [SIGUSR2] = true, });
191 
192   /* Resetting the default attribute brings back the old inheritance
193      behavior.  */
194   xpthread_attr_destroy (&attr);
195   xpthread_attr_init (&attr);
196   TEST_COMPARE (pthread_setattr_default_np (&attr), 0);
197   xpthread_attr_destroy (&attr);
198   check_posix_thread (NULL, (signals) { [SIGUSR1] = true, });
199   check_c11_thread ((signals) { [SIGUSR1] = true, });
200 
201   return 0;
202 }
203 
204 #include <support/test-driver.c>
205