xref: /freebsd/tests/sys/kern/sigwait.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 /*-
2  * Copyright (c) 2022 Dmitry Chagin <dchagin@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 #include <sys/cdefs.h>
7 __FBSDID("$FreeBSD$");
8 
9 #include <sys/limits.h>
10 #include <sys/time.h>
11 #include <sys/sysctl.h>
12 #include <sys/user.h>
13 #include <sys/wait.h>
14 
15 #include <err.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <signal.h>
21 #include <stdbool.h>
22 #include <unistd.h>
23 
24 #include <atf-c.h>
25 
26 
27 static inline struct timespec
28 make_timespec(time_t s, long int ns)
29 {
30 	struct timespec rts;
31 
32 	rts.tv_sec = s;
33 	rts.tv_nsec = ns;
34 	return (rts);
35 }
36 
37 static void
38 dummy_sig_handler(int sig)
39 {
40 
41 }
42 
43 static void
44 dummy_sigchld(int signo, siginfo_t *info, void *ctx)
45 {
46 
47 }
48 
49 static void
50 support_signal(int sig, sig_t handler)
51 {
52 
53 	ATF_REQUIRE(signal(sig, handler) != SIG_ERR);
54 }
55 
56 static void
57 support_sysctlset(const char *name, int32_t val)
58 {
59 
60 	ATF_REQUIRE(sysctlbyname(name, NULL, NULL, &val, sizeof(val)) == 0);
61 }
62 
63 static timer_t
64 support_create_timer(uint64_t sec, long int nsec, bool repeat,
65     bool callback)
66 {
67 	struct sigevent ev = {
68 		.sigev_notify = SIGEV_SIGNAL,
69 		.sigev_signo = SIGALRM
70 	};
71 	struct itimerspec its =
72 	{
73 		{ .tv_sec = repeat ? sec : 0, .tv_nsec = repeat ? nsec : 0 },
74 		{ .tv_sec = sec, .tv_nsec = nsec }
75 	};
76 	struct sigaction sa;
77 	timer_t timerid;
78 
79 	if (callback) {
80 		sa.sa_handler = dummy_sig_handler;
81 		sigemptyset (&sa.sa_mask);
82 		sa.sa_flags = 0;
83 		ATF_REQUIRE(sigaction(SIGALRM, &sa, NULL) == 0);
84 	}
85 	ATF_REQUIRE(timer_create(CLOCK_REALTIME, &ev, &timerid) == 0);
86 	ATF_REQUIRE(timer_settime(timerid, 0, &its, NULL) == 0);
87 	return (timerid);
88 }
89 
90 static void
91 support_delete_timer(timer_t timer)
92 {
93 
94 	ATF_REQUIRE(timer_delete(timer) == 0);
95 	support_signal(SIGALRM, SIG_DFL);
96 }
97 
98 static pid_t
99 support_create_sig_proc(int sig, int count, unsigned int usec)
100 {
101 	pid_t pid, cpid;
102 
103 	pid = getpid();
104 	ATF_REQUIRE(pid > 0);
105 	cpid = fork();
106 	ATF_REQUIRE(cpid >= 0);
107 
108 	if (cpid == 0) {
109 		while (count-- > 0) {
110 			usleep(usec);
111 			if (kill(pid, sig) == -1)
112 				break;
113 		}
114 		exit(0);
115 	}
116 	return (cpid);
117 }
118 
119 #define TIMESPEC_HZ     1000000000
120 
121 static void
122 test_sigtimedwait_timeout_eagain(time_t sec, bool zero_tmo)
123 {
124 	struct timespec ts, timeout, now;
125 	sigset_t ss;
126 	int rv;
127 
128 	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts) == 0);
129 
130 	timeout = make_timespec(sec, zero_tmo ? 0 : TIMESPEC_HZ/2);
131 	timespecadd(&ts, &timeout, &ts);
132 
133 	sigemptyset(&ss);
134 	sigaddset(&ss, SIGUSR1);
135 	rv = sigtimedwait(&ss, NULL, &timeout);
136 	ATF_REQUIRE_EQ_MSG(-1, rv,
137 	    "sigtimedwait () should fail: rv %d, errno %d", rv, errno);
138 	ATF_REQUIRE_EQ_MSG(EAGAIN, errno,
139 	    "sigtimedwait() should fail with EAGAIN: rv %d, errno %d",
140 	    rv, errno);
141 	/* now >= ts */
142 	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &now) == 0);
143 	ATF_REQUIRE_MSG(timespeccmp(&now, &ts, >=) == true,
144 	    "timespeccmp: now { %jd.%ld } < ts { %jd.%ld }",
145 	    (intmax_t)now.tv_sec, now.tv_nsec,
146 	    (intmax_t)ts.tv_sec, ts.tv_nsec);
147 }
148 
149 ATF_TC(test_sigtimedwait_timeout_eagain0);
150 ATF_TC_HEAD(test_sigtimedwait_timeout_eagain0, tc)
151 {
152 
153 	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits immediately");
154 }
155 
156 ATF_TC_BODY(test_sigtimedwait_timeout_eagain0, tc)
157 {
158 
159 	test_sigtimedwait_timeout_eagain(0, true);
160 }
161 
162 ATF_TC(test_sigtimedwait_timeout_eagain1);
163 ATF_TC_HEAD(test_sigtimedwait_timeout_eagain1, tc)
164 {
165 
166 	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits immediately");
167 }
168 
169 ATF_TC_BODY(test_sigtimedwait_timeout_eagain1, tc)
170 {
171 
172 	test_sigtimedwait_timeout_eagain(-1, true);
173 }
174 
175 ATF_TC(test_sigtimedwait_timeout_eagain2);
176 ATF_TC_HEAD(test_sigtimedwait_timeout_eagain2, tc)
177 {
178 
179 	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits immediately");
180 }
181 
182 ATF_TC_BODY(test_sigtimedwait_timeout_eagain2, tc)
183 {
184 
185 	test_sigtimedwait_timeout_eagain(-1, false);
186 }
187 
188 ATF_TC(test_sigtimedwait_timeout_eagain3);
189 ATF_TC_HEAD(test_sigtimedwait_timeout_eagain3, tc)
190 {
191 
192 	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits after specified timeout");
193 }
194 
195 ATF_TC_BODY(test_sigtimedwait_timeout_eagain3, tc)
196 {
197 
198 	test_sigtimedwait_timeout_eagain(0, false);
199 }
200 
201 ATF_TC(test_sigtimedwait_large_timeout_eintr);
202 ATF_TC_HEAD(test_sigtimedwait_large_timeout_eintr, tc)
203 {
204 
205 	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits with EINTR");
206 }
207 
208 ATF_TC_BODY(test_sigtimedwait_large_timeout_eintr, tc)
209 {
210 	struct timespec ts;
211 	timer_t timerid;
212 	sigset_t ss;
213 	int rv;
214 
215 	ts = make_timespec(LONG_MAX, 0);
216 	timerid = support_create_timer(0, 100000000, false, true);
217 
218 	sigemptyset(&ss);
219 	sigaddset(&ss, SIGUSR1);
220 	rv = sigtimedwait(&ss, NULL, &ts);
221 	ATF_REQUIRE_EQ_MSG(-1, rv,
222 	    "sigtimedwait () should fail: rv %d, errno %d", rv, errno);
223 	ATF_REQUIRE_EQ_MSG(EINTR, errno,
224 	    "sigtimedwait() should fail with EINTR: rv %d, errno %d",
225 	    rv, errno);
226 	support_delete_timer(timerid);
227 }
228 
229 ATF_TC(test_sigtimedwait_infinity);
230 ATF_TC_HEAD(test_sigtimedwait_infinity, tc)
231 {
232 
233 	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits with EINTR");
234 }
235 
236 ATF_TC_BODY(test_sigtimedwait_infinity, tc)
237 {
238 	timer_t timerid;
239 	sigset_t ss;
240 	int rv;
241 
242 	timerid = support_create_timer(0, 100000000, false, true);
243 
244 	sigemptyset(&ss);
245 	sigaddset(&ss, SIGUSR1);
246 	rv = sigtimedwait(&ss, NULL, NULL);
247 	ATF_REQUIRE_EQ_MSG(-1, rv,
248 	    "sigtimedwait () should fail: rv %d, errno %d", rv, errno);
249 	ATF_REQUIRE_EQ_MSG(EINTR, errno,
250 	    "sigtimedwait() should fail with EINTR: rv %d, errno %d",
251 	    rv, errno);
252 	support_delete_timer(timerid);
253 }
254 
255 ATF_TC(test_sigtimedwait_einval);
256 ATF_TC_HEAD(test_sigtimedwait_einval, tc)
257 {
258 
259 	atf_tc_set_md_var(tc, "descr", "Check if sigtimedwait exits with EINVAL");
260 }
261 
262 ATF_TC_BODY(test_sigtimedwait_einval, tc)
263 {
264 	struct timespec ts;
265 	timer_t timerid;
266 	sigset_t ss;
267 	int rv;
268 
269 	ts = make_timespec(0, -1);
270 	timerid = support_create_timer(0, 100000000, false, true);
271 
272 	sigemptyset(&ss);
273 	sigaddset(&ss, SIGUSR1);
274 	rv = sigtimedwait(&ss, NULL, &ts);
275 	ATF_REQUIRE_EQ_MSG(-1, rv,
276 	    "sigtimedwait () should fail: rv %d, errno %d", rv, errno);
277 	ATF_REQUIRE_EQ_MSG(EINVAL, errno,
278 	    "sigtimedwait() should fail with EINVAL: rv %d, errno %d",
279 	    rv, errno);
280 	support_delete_timer(timerid);
281 }
282 
283 ATF_TC(test_sigwait_eintr);
284 ATF_TC_HEAD(test_sigwait_eintr, tc)
285 {
286 
287 	atf_tc_set_md_var(tc, "descr", "Check if sigwait exits with EINTR");
288 }
289 
290 ATF_TC_BODY(test_sigwait_eintr, tc)
291 {
292 	timer_t timerid;
293 	sigset_t ss;
294 	int rv, sig, pid;
295 
296 	support_signal(SIGUSR1, dummy_sig_handler);
297 
298 	pid = support_create_sig_proc(SIGUSR1, 1, 400000);
299 	timerid = support_create_timer(0, 200000, false, true);
300 
301 	sigemptyset(&ss);
302 	sigaddset(&ss, SIGUSR1);
303 	rv = sigwait(&ss, &sig);
304 	ATF_REQUIRE_EQ_MSG(0, rv,
305 	    "sigwait() should not fail: rv %d, errno %d", rv, errno);
306 	ATF_REQUIRE_EQ_MSG(SIGUSR1, sig,
307 	    "sigwait() should return SIGUSR1: rv %d, sig %d", rv, sig);
308 	ATF_REQUIRE(waitid(P_PID, pid, NULL, WEXITED) == 0);
309 	support_delete_timer(timerid);
310 }
311 
312 ATF_TC(test_sigwaitinfo_eintr);
313 ATF_TC_HEAD(test_sigwaitinfo_eintr, tc)
314 {
315 
316 	atf_tc_set_md_var(tc, "descr", "Check if sigwaitinfo exits with EINTR");
317 }
318 
319 ATF_TC_BODY(test_sigwaitinfo_eintr, tc)
320 {
321 	timer_t timerid;
322 	sigset_t ss;
323 	int rv;
324 
325 	timerid = support_create_timer(0, 100000000, false, true);
326 
327 	sigemptyset(&ss);
328 	sigaddset(&ss, SIGUSR1);
329 	rv = sigwaitinfo(&ss, NULL);
330 	ATF_REQUIRE_EQ_MSG(-1, rv,
331 	    "sigwaitinfo() should fail, rv %d != -1", rv);
332 	ATF_REQUIRE_EQ_MSG(EINTR, errno,
333 	    "sigwaitinfo() should fail errno %d != EINTR", errno);
334 	support_delete_timer(timerid);
335 }
336 
337 /*
338  * Test kern.sig_discard_ign knob (default true).
339  * See commit bc387624
340  */
341 static void
342 test_sig_discard_ign(bool ignore)
343 {
344 	struct timespec ts;
345 	sigset_t mask;
346 	pid_t pid;
347 	int rv;
348 
349 	support_signal(SIGUSR2, SIG_IGN);
350 
351 	if (ignore)
352 		support_sysctlset("kern.sig_discard_ign", 1);
353 	else
354 		support_sysctlset("kern.sig_discard_ign", 0);
355 
356 	sigemptyset(&mask);
357 	sigaddset(&mask, SIGUSR2);
358 	ATF_REQUIRE(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
359 
360 	pid = support_create_sig_proc(SIGUSR2, 1, 100000);
361 
362 	ts = make_timespec(1, 0);
363 	rv = sigtimedwait(&mask, NULL, &ts);
364 	if (ignore == true) {
365 		ATF_REQUIRE_EQ_MSG(-1, rv,
366 		    "sigtimedwait() ign=on should fail, rv %d != -1", rv);
367 		ATF_REQUIRE_EQ_MSG(EAGAIN, errno,
368 		    "sigtimedwait() ign=on should fail with EAGAIN errno %d",
369 		    errno);
370 	} else
371 		ATF_REQUIRE_EQ_MSG(SIGUSR2, rv,
372 		    "sigtimedwait() ign=off should return SIGUSR2, rv %d errno %d",
373 		    rv, errno);
374 	ATF_REQUIRE(waitid(P_PID, pid, NULL, WEXITED) == 0);
375 }
376 
377 static void
378 support_check_siginfo(int code, int status, pid_t pid,
379     siginfo_t *si, int sig)
380 {
381 
382 	ATF_REQUIRE_EQ_MSG(sig, si->si_signo,
383 	    "check_siginfo: si_signo %d != sig %d", si->si_signo, sig);
384 	ATF_REQUIRE_EQ_MSG(code, si->si_code,
385 	    "check_siginfo: si_code %d != code %d", si->si_code, code);
386 	ATF_REQUIRE_EQ_MSG(status, si->si_status,
387 	    "check_siginfo: si_status %d != status %d", si->si_status, status);
388 	ATF_REQUIRE_EQ_MSG(pid, si->si_pid,
389 	    "check_siginfo: si_pid %d != pid %d", si->si_pid, pid);
390 }
391 
392 static void
393 support_check_sigchld(sigset_t *set, int code, int status, pid_t pid,
394     bool dequeue)
395 {
396 	siginfo_t si;
397 	int sig, kpid;
398 
399 	if (dequeue == true)
400 		kpid = support_create_sig_proc(SIGUSR2, 1, 1000000);
401 
402 	sig = sigwaitinfo(set, &si);
403 	if (dequeue == true) {
404 		ATF_REQUIRE_EQ_MSG(-1, sig,
405 		    "sigwaitinfo() should fail, sig %d != -1", sig);
406 		ATF_REQUIRE_EQ_MSG(EINTR, errno,
407 		    "sigwaitinfo() should fail errno %d != EINTR", errno);
408 	} else
409 		ATF_REQUIRE_EQ_MSG(SIGCHLD, sig,
410 		    "sigwaitinfo() %d != SIGCHLD", sig);
411 	if (dequeue == false)
412 		support_check_siginfo(code, status, pid, &si, SIGCHLD);
413 	if (dequeue == true)
414 		ATF_REQUIRE(waitid(P_PID, kpid, &si, WEXITED) == 0);
415 }
416 
417 static void
418 test_child(void)
419 {
420 
421 	raise(SIGSTOP);
422 	while (1)
423 		pause();
424 }
425 
426 /*
427  * Test kern.wait_dequeue_sigchld knob.
428  */
429 static void
430 test_wait_dequeue_sigchld(bool dequeue)
431 {
432 	struct sigaction sa;
433 	siginfo_t si;
434 	sigset_t set;
435 	pid_t pid;
436 
437 	sa.sa_flags = SA_SIGINFO | SA_RESTART;
438 	sa.sa_sigaction = dummy_sigchld;
439 	sigemptyset(&sa.sa_mask);
440 	ATF_REQUIRE(sigaction(SIGCHLD, &sa, NULL) == 0);
441 
442 	support_signal(SIGUSR2, dummy_sig_handler);
443 
444 	sigemptyset(&set);
445 	sigaddset(&set, SIGCHLD);
446 	ATF_REQUIRE(sigprocmask(SIG_BLOCK, &set, NULL) == 0);
447 
448 	if (dequeue)
449 		support_sysctlset("kern.wait_dequeue_sigchld", 1);
450 	else
451 		support_sysctlset("kern.wait_dequeue_sigchld", 0);
452 
453 	pid = fork();
454 	ATF_REQUIRE(pid >= 0);
455 	if (pid == 0) {
456 		test_child();
457 		exit(0);
458 	}
459 
460 	bzero(&si, sizeof(si));
461 	ATF_REQUIRE(waitid(P_PID, pid, &si, WSTOPPED) == 0);
462 
463 	support_check_siginfo(CLD_STOPPED, SIGSTOP, pid, &si, SIGCHLD);
464 	support_check_sigchld(&set, CLD_STOPPED, SIGSTOP, pid, dequeue);
465 
466 	ATF_REQUIRE(kill(pid, SIGCONT) == 0);
467 
468 	bzero(&si, sizeof(si));
469 	ATF_REQUIRE(waitid(P_PID, pid, &si, WCONTINUED) == 0);
470 
471 	support_check_siginfo(CLD_CONTINUED, SIGCONT, pid, &si, SIGCHLD);
472 	support_check_sigchld(&set, CLD_CONTINUED, SIGCONT, pid, dequeue);
473 
474 	ATF_REQUIRE(kill(pid, SIGKILL) == 0);
475 
476 	bzero(&si, sizeof(si));
477 	ATF_REQUIRE(waitid(P_PID, pid, &si, WEXITED) == 0);
478 
479 	support_check_siginfo(CLD_KILLED, SIGKILL, pid, &si, SIGCHLD);
480 }
481 
482 ATF_TC_WITH_CLEANUP(test_sig_discard_ign_true);
483 ATF_TC_HEAD(test_sig_discard_ign_true, tc)
484 {
485 
486 	atf_tc_set_md_var(tc, "require.user", "root");
487 	atf_tc_set_md_var(tc, "descr", "Test kern.sig_discard_ign on");
488 }
489 
490 ATF_TC_BODY(test_sig_discard_ign_true, tc)
491 {
492 
493 	test_sig_discard_ign(true);
494 }
495 
496 ATF_TC_CLEANUP(test_sig_discard_ign_true, tc)
497 {
498 
499 	support_sysctlset("kern.sig_discard_ign", 1);
500 }
501 
502 ATF_TC_WITH_CLEANUP(test_sig_discard_ign_false);
503 ATF_TC_HEAD(test_sig_discard_ign_false, tc)
504 {
505 
506 	atf_tc_set_md_var(tc, "require.user", "root");
507 	atf_tc_set_md_var(tc, "descr", "Test kern.sig_discard_ign off");
508 }
509 
510 ATF_TC_BODY(test_sig_discard_ign_false, tc)
511 {
512 
513 	test_sig_discard_ign(false);
514 }
515 
516 ATF_TC_CLEANUP(test_sig_discard_ign_false, tc)
517 {
518 
519 	support_sysctlset("kern.sig_discard_ign", 1);
520 }
521 
522 ATF_TC_WITH_CLEANUP(test_wait_dequeue_sigchld_true);
523 ATF_TC_HEAD(test_wait_dequeue_sigchld_true, tc)
524 {
525 
526 	atf_tc_set_md_var(tc, "require.user", "root");
527 	atf_tc_set_md_var(tc, "descr", "Test kern.wait_dequeue_sigchld on");
528 }
529 
530 ATF_TC_BODY(test_wait_dequeue_sigchld_true, tc)
531 {
532 
533 	test_wait_dequeue_sigchld(true);
534 }
535 
536 ATF_TC_CLEANUP(test_wait_dequeue_sigchld_true, tc)
537 {
538 
539 	support_sysctlset("kern.wait_dequeue_sigchld", 1);
540 }
541 
542 ATF_TC_WITH_CLEANUP(test_wait_dequeue_sigchld_false);
543 ATF_TC_HEAD(test_wait_dequeue_sigchld_false, tc)
544 {
545 
546 	atf_tc_set_md_var(tc, "require.user", "root");
547 	atf_tc_set_md_var(tc, "descr", "Test kern.wait_dequeue_sigchld off");
548 }
549 
550 ATF_TC_BODY(test_wait_dequeue_sigchld_false, tc)
551 {
552 
553 	test_wait_dequeue_sigchld(false);
554 }
555 
556 ATF_TC_CLEANUP(test_wait_dequeue_sigchld_false, tc)
557 {
558 
559 	support_sysctlset("kern.wait_dequeue_sigchld", 1);
560 }
561 
562 ATF_TP_ADD_TCS(tp)
563 {
564 
565 	ATF_TP_ADD_TC(tp, test_sigtimedwait_timeout_eagain0);
566 	ATF_TP_ADD_TC(tp, test_sigtimedwait_timeout_eagain1);
567 	ATF_TP_ADD_TC(tp, test_sigtimedwait_timeout_eagain2);
568 	ATF_TP_ADD_TC(tp, test_sigtimedwait_timeout_eagain3);
569 
570 	ATF_TP_ADD_TC(tp, test_sigtimedwait_large_timeout_eintr);
571 	ATF_TP_ADD_TC(tp, test_sigtimedwait_infinity);
572 
573 	ATF_TP_ADD_TC(tp, test_sigtimedwait_einval);
574 
575 	ATF_TP_ADD_TC(tp, test_sigwait_eintr);
576 	ATF_TP_ADD_TC(tp, test_sigwaitinfo_eintr);
577 
578 	ATF_TP_ADD_TC(tp, test_sig_discard_ign_true);
579 	ATF_TP_ADD_TC(tp, test_sig_discard_ign_false);
580 
581 	ATF_TP_ADD_TC(tp, test_wait_dequeue_sigchld_true);
582 	ATF_TP_ADD_TC(tp, test_wait_dequeue_sigchld_false);
583 
584 	return (atf_no_error());
585 }
586