1/* Tests for pthread_attr_setsigmask_np, pthread_attr_getsigmask_np.
2 Copyright (C) 2020-2024 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
32typedef bool signals[_NSIG];
33
34static const char *
35masked_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. */
45static void
46check_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 (format: "error: %s: signal %d should be %s, but is %s\n",
54 context, sig,
55 masked_or_unmasked (masked: sigismember (actual_mask, sig)),
56 masked_or_unmasked (masked: 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. */
62static void
63check_current_sigmask (const char *context, signals expected_mask)
64{
65 sigset_t actual_mask;
66 xpthread_sigmask (SIG_SETMASK, NULL, oldset: &actual_mask);
67 check_sigmask (context, expected_mask, actual_mask: &actual_mask);
68}
69
70/* Thread start routine which checks the current thread signal mask
71 against CLOSURE. */
72static void *
73check_sigmask_thread_function (void *closure)
74{
75 check_current_sigmask (context: "on thread", expected_mask: closure);
76 return NULL;
77}
78
79/* Same for C11 threads. */
80static int
81check_sigmask_thread_function_c11 (void *closure)
82{
83 check_current_sigmask (context: "on C11 thread", expected_mask: 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. */
89static void
90check_posix_thread (pthread_attr_t *attr, signals expected_mask)
91{
92 xpthread_join (thr: xpthread_create (attr, thread_func: check_sigmask_thread_function,
93 closure: expected_mask));
94}
95
96/* Launch a C11 thread and check that it has the expected signal
97 mask. */
98static void
99check_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
107static int
108do_test (void)
109{
110 check_current_sigmask (context: "initial mask", expected_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

source code of glibc/nptl/tst-pthread-attr-sigmask.c