1 /*
2 * Copyright (c) 2023 Meta
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <pthread.h>
9 #include <signal.h>
10 #include <stdio.h>
11
12 #include <zephyr/sys/util.h>
13 #include <zephyr/ztest.h>
14
ZTEST(posix_signals,test_sigemptyset)15 ZTEST(posix_signals, test_sigemptyset)
16 {
17 sigset_t set;
18
19 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
20 set.sig[i] = -1;
21 }
22
23 zassert_ok(sigemptyset(&set));
24
25 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
26 zassert_equal(set.sig[i], 0u, "set.sig[%d] is not empty: 0x%lx", i, set.sig[i]);
27 }
28 }
29
ZTEST(posix_signals,test_sigfillset)30 ZTEST(posix_signals, test_sigfillset)
31 {
32 sigset_t set = (sigset_t){0};
33
34 zassert_ok(sigfillset(&set));
35
36 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
37 zassert_equal(set.sig[i], -1, "set.sig[%d] is not filled: 0x%lx", i, set.sig[i]);
38 }
39 }
40
ZTEST(posix_signals,test_sigaddset_oor)41 ZTEST(posix_signals, test_sigaddset_oor)
42 {
43 sigset_t set = (sigset_t){0};
44
45 zassert_equal(sigaddset(&set, -1), -1, "rc should be -1");
46 zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL");
47
48 zassert_equal(sigaddset(&set, 0), -1, "rc should be -1");
49 zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL");
50
51 zassert_equal(sigaddset(&set, _NSIG), -1, "rc should be -1");
52 zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL");
53 }
54
ZTEST(posix_signals,test_sigaddset)55 ZTEST(posix_signals, test_sigaddset)
56 {
57 int signo;
58 sigset_t set = (sigset_t){0};
59 sigset_t target = (sigset_t){0};
60
61 signo = SIGHUP;
62 zassert_ok(sigaddset(&set, signo));
63 WRITE_BIT(target.sig[0], signo, 1);
64 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
65 zassert_equal(set.sig[i], target.sig[i],
66 "set.sig[%d of %d] has content: %lx, expected %lx", i,
67 ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]);
68 }
69
70 signo = SIGSYS;
71 zassert_ok(sigaddset(&set, signo));
72 WRITE_BIT(target.sig[0], signo, 1);
73 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
74 zassert_equal(set.sig[i], target.sig[i],
75 "set.sig[%d of %d] has content: %lx, expected %lx", i,
76 ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]);
77 }
78
79 signo = SIGRTMIN; /* >=32, will be in the second sig set for 32bit */
80 zassert_ok(sigaddset(&set, signo));
81 #ifdef CONFIG_64BIT
82 WRITE_BIT(target.sig[0], signo, 1);
83 #else /* 32BIT */
84 WRITE_BIT(target.sig[1], (signo)-BITS_PER_LONG, 1);
85 #endif
86 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
87 zassert_equal(set.sig[i], target.sig[i],
88 "set.sig[%d of %d] has content: %lx, expected %lx", i,
89 ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]);
90 }
91
92 signo = SIGRTMAX;
93 zassert_ok(sigaddset(&set, signo));
94 WRITE_BIT(target.sig[signo / BITS_PER_LONG], signo % BITS_PER_LONG, 1);
95 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
96 zassert_equal(set.sig[i], target.sig[i],
97 "set.sig[%d of %d] has content: %lx, expected %lx", i,
98 ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]);
99 }
100 }
101
ZTEST(posix_signals,test_sigdelset_oor)102 ZTEST(posix_signals, test_sigdelset_oor)
103 {
104 sigset_t set = (sigset_t){0};
105
106 zassert_equal(sigdelset(&set, -1), -1, "rc should be -1");
107 zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL");
108
109 zassert_equal(sigdelset(&set, 0), -1, "rc should be -1");
110 zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL");
111
112 zassert_equal(sigdelset(&set, _NSIG), -1, "rc should be -1");
113 zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL");
114 }
115
ZTEST(posix_signals,test_sigdelset)116 ZTEST(posix_signals, test_sigdelset)
117 {
118 int signo;
119 sigset_t set = (sigset_t){0};
120 sigset_t target = (sigset_t){0};
121
122 signo = SIGHUP;
123 zassert_ok(sigdelset(&set, signo));
124 WRITE_BIT(target.sig[0], signo, 0);
125 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
126 zassert_equal(set.sig[i], target.sig[i],
127 "set.sig[%d of %d] has content: %lx, expected %lx", i,
128 ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]);
129 }
130
131 signo = SIGSYS;
132 zassert_ok(sigdelset(&set, signo));
133 WRITE_BIT(target.sig[0], signo, 0);
134 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
135 zassert_equal(set.sig[i], target.sig[i],
136 "set.sig[%d of %d] has content: %lx, expected %lx", i,
137 ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]);
138 }
139
140 signo = SIGRTMIN; /* >=32, will be in the second sig set for 32bit */
141 zassert_ok(sigdelset(&set, signo));
142 #ifdef CONFIG_64BIT
143 WRITE_BIT(target.sig[0], signo, 0);
144 #else /* 32BIT */
145 WRITE_BIT(target.sig[1], (signo)-BITS_PER_LONG, 0);
146 #endif
147 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
148 zassert_equal(set.sig[i], target.sig[i],
149 "set.sig[%d of %d] has content: %lx, expected %lx", i,
150 ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]);
151 }
152
153 signo = SIGRTMAX;
154 zassert_ok(sigdelset(&set, signo));
155 WRITE_BIT(target.sig[signo / BITS_PER_LONG], signo % BITS_PER_LONG, 0);
156 for (int i = 0; i < ARRAY_SIZE(set.sig); i++) {
157 zassert_equal(set.sig[i], target.sig[i],
158 "set.sig[%d of %d] has content: %lx, expected %lx", i,
159 ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]);
160 }
161 }
162
ZTEST(posix_signals,test_sigismember_oor)163 ZTEST(posix_signals, test_sigismember_oor)
164 {
165 sigset_t set = {0};
166
167 zassert_equal(sigismember(&set, -1), -1, "rc should be -1");
168 zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL");
169
170 zassert_equal(sigismember(&set, 0), -1, "rc should be -1");
171 zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL");
172
173 zassert_equal(sigismember(&set, _NSIG), -1, "rc should be -1");
174 zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL");
175 }
176
ZTEST(posix_signals,test_sigismember)177 ZTEST(posix_signals, test_sigismember)
178 {
179 sigset_t set = (sigset_t){0};
180
181 #ifdef CONFIG_64BIT
182 set.sig[0] = BIT(SIGHUP) | BIT(SIGSYS) | BIT(SIGRTMIN);
183 #else /* 32BIT */
184 set.sig[0] = BIT(SIGHUP) | BIT(SIGSYS);
185 set.sig[1] = BIT((SIGRTMIN)-BITS_PER_LONG);
186 #endif
187 WRITE_BIT(set.sig[SIGRTMAX / BITS_PER_LONG], SIGRTMAX % BITS_PER_LONG, 1);
188
189 zassert_equal(sigismember(&set, SIGHUP), 1, "%s expected to be member", "SIGHUP");
190 zassert_equal(sigismember(&set, SIGSYS), 1, "%s expected to be member", "SIGSYS");
191 zassert_equal(sigismember(&set, SIGRTMIN), 1, "%s expected to be member", "SIGRTMIN");
192 zassert_equal(sigismember(&set, SIGRTMAX), 1, "%s expected to be member", "SIGRTMAX");
193
194 zassert_equal(sigismember(&set, SIGKILL), 0, "%s not expected to be member", "SIGKILL");
195 zassert_equal(sigismember(&set, SIGTERM), 0, "%s not expected to be member", "SIGTERM");
196 }
197
ZTEST(posix_signals,test_signal_strsignal)198 ZTEST(posix_signals, test_signal_strsignal)
199 {
200 /* Using -INT_MAX here because compiler resolves INT_MIN to (-2147483647 - 1) */
201 char buf[sizeof("RT signal -" STRINGIFY(INT_MAX))] = {0};
202
203 zassert_mem_equal(strsignal(-1), "Invalid signal", sizeof("Invalid signal"));
204 zassert_mem_equal(strsignal(0), "Invalid signal", sizeof("Invalid signal"));
205 zassert_mem_equal(strsignal(_NSIG), "Invalid signal", sizeof("Invalid signal"));
206
207 zassert_mem_equal(strsignal(30), "Signal 30", sizeof("Signal 30"));
208 snprintf(buf, sizeof(buf), "RT signal %d", SIGRTMIN - SIGRTMIN);
209 zassert_mem_equal(strsignal(SIGRTMIN), buf, strlen(buf));
210 snprintf(buf, sizeof(buf), "RT signal %d", SIGRTMAX - SIGRTMIN);
211 zassert_mem_equal(strsignal(SIGRTMAX), buf, strlen(buf));
212
213 #ifdef CONFIG_POSIX_SIGNAL_STRING_DESC
214 zassert_mem_equal(strsignal(SIGHUP), "Hangup", sizeof("Hangup"));
215 zassert_mem_equal(strsignal(SIGSYS), "Bad system call", sizeof("Bad system call"));
216 #else
217 zassert_mem_equal(strsignal(SIGHUP), "Signal 1", sizeof("Signal 1"));
218 zassert_mem_equal(strsignal(SIGSYS), "Signal 31", sizeof("Signal 31"));
219 #endif
220 }
221
222 typedef int (*sigmask_fn)(int how, const sigset_t *set, sigset_t *oset);
test_sigmask_entry(void * arg)223 static void *test_sigmask_entry(void *arg)
224 {
225 /* for clarity */
226 #define SIG_GETMASK SIG_SETMASK
227
228 enum {
229 NEW,
230 OLD,
231 };
232 static sigset_t set[2];
233 const int invalid_how = 0x9a2ba9e;
234 sigmask_fn sigmask = arg;
235
236 /* invalid how results in EINVAL */
237 zassert_equal(sigmask(invalid_how, NULL, NULL), EINVAL);
238 zassert_equal(sigmask(invalid_how, &set[NEW], &set[OLD]), EINVAL);
239
240 /* verify setting / getting masks */
241 zassert_ok(sigemptyset(&set[NEW]));
242 zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL));
243 zassert_ok(sigfillset(&set[OLD]));
244 zassert_ok(sigmask(SIG_GETMASK, NULL, &set[OLD]));
245 zassert_mem_equal(&set[OLD], &set[NEW], sizeof(set[OLD]));
246
247 zassert_ok(sigfillset(&set[NEW]));
248 zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL));
249 zassert_ok(sigemptyset(&set[OLD]));
250 zassert_ok(sigmask(SIG_GETMASK, NULL, &set[OLD]));
251 zassert_mem_equal(&set[OLD], &set[NEW], sizeof(set[OLD]));
252
253 /* start with an empty mask */
254 zassert_ok(sigemptyset(&set[NEW]));
255 zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL));
256
257 /* verify SIG_BLOCK: expect (SIGUSR1 | SIGUSR2 | SIGHUP) */
258 zassert_ok(sigemptyset(&set[NEW]));
259 zassert_ok(sigaddset(&set[NEW], SIGUSR1));
260 zassert_ok(sigmask(SIG_BLOCK, &set[NEW], NULL));
261
262 zassert_ok(sigemptyset(&set[NEW]));
263 zassert_ok(sigaddset(&set[NEW], SIGUSR2));
264 zassert_ok(sigaddset(&set[NEW], SIGHUP));
265 zassert_ok(sigmask(SIG_BLOCK, &set[NEW], NULL));
266
267 zassert_ok(sigemptyset(&set[OLD]));
268 zassert_ok(sigaddset(&set[OLD], SIGUSR1));
269 zassert_ok(sigaddset(&set[OLD], SIGUSR2));
270 zassert_ok(sigaddset(&set[OLD], SIGHUP));
271
272 zassert_ok(sigmask(SIG_GETMASK, NULL, &set[NEW]));
273 zassert_mem_equal(&set[NEW], &set[OLD], sizeof(set[NEW]));
274
275 /* start with full mask */
276 zassert_ok(sigfillset(&set[NEW]));
277 zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL));
278
279 /* verify SIG_UNBLOCK: expect ~(SIGUSR1 | SIGUSR2 | SIGHUP) */
280 zassert_ok(sigemptyset(&set[NEW]));
281 zassert_ok(sigaddset(&set[NEW], SIGUSR1));
282 zassert_ok(sigmask(SIG_UNBLOCK, &set[NEW], NULL));
283
284 zassert_ok(sigemptyset(&set[NEW]));
285 zassert_ok(sigaddset(&set[NEW], SIGUSR2));
286 zassert_ok(sigaddset(&set[NEW], SIGHUP));
287 zassert_ok(sigmask(SIG_UNBLOCK, &set[NEW], NULL));
288
289 zassert_ok(sigfillset(&set[OLD]));
290 zassert_ok(sigdelset(&set[OLD], SIGUSR1));
291 zassert_ok(sigdelset(&set[OLD], SIGUSR2));
292 zassert_ok(sigdelset(&set[OLD], SIGHUP));
293
294 zassert_ok(sigmask(SIG_GETMASK, NULL, &set[NEW]));
295 zassert_mem_equal(&set[NEW], &set[OLD], sizeof(set[NEW]));
296
297 return NULL;
298 }
299
ZTEST(posix_signals,test_pthread_sigmask)300 ZTEST(posix_signals, test_pthread_sigmask)
301 {
302 pthread_t th;
303
304 zassert_ok(pthread_create(&th, NULL, test_sigmask_entry, pthread_sigmask));
305 zassert_ok(pthread_join(th, NULL));
306 }
307
ZTEST(posix_signals,test_sigprocmask)308 ZTEST(posix_signals, test_sigprocmask)
309 {
310 if (IS_ENABLED(CONFIG_MULTITHREADING)) {
311 if (!IS_ENABLED(CONFIG_ASSERT)) {
312 zassert_not_ok(sigprocmask(SIG_SETMASK, NULL, NULL));
313 zassert_equal(errno, ENOSYS);
314 }
315 } else {
316 pthread_t th;
317
318 zassert_ok(pthread_create(&th, NULL, test_sigmask_entry, sigprocmask));
319 zassert_ok(pthread_join(th, NULL));
320 }
321 }
322
before(void * arg)323 static void before(void *arg)
324 {
325 ARG_UNUSED(arg);
326
327 if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) {
328 /* skip redundant testing if there is no thread pool / heap allocation */
329 ztest_test_skip();
330 }
331 }
332
333 ZTEST_SUITE(posix_signals, NULL, NULL, before, NULL, NULL);
334