1/*
2 * Copyright (c) Jiri Palecek<jpalecek@web.de>, 2009
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like.  Any license provided herein, whether implied or
15 * otherwise, applies only to this software file.  Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23#include "test.h"
24#include <errno.h>
25#include <signal.h>
26#include "../utils/include_j_h.h"
27#include "../utils/common_j_h.c"
28#include <limits.h>
29#include "linux_syscall_numbers.h"
30
31#define SUCCEED_OR_DIE(syscall, message, ...)				 \
32	(errno = 0,							 \
33		({int ret=syscall(__VA_ARGS__);				 \
34			if (ret==-1)					 \
35				tst_brkm(TBROK|TERRNO, cleanup, message);\
36			ret;}))
37
38/* Report success iff TEST_RETURN and TEST_ERRNO are equal to
39	 exp_return and exp_errno, resp., and cond is true. If cond is not
40	 true, report condition_errmsg
41*/
42static void report_success_cond(const char *func, const char *file, int line,
43				long exp_return, int exp_errno, int condition,
44				char *condition_errmsg)
45{
46	if (exp_return == TEST_RETURN
47	    && (exp_return != -1 || exp_errno == TEST_ERRNO))
48		if (condition)
49			tst_resm(TPASS, "Test passed");
50		else
51			tst_resm(TFAIL, "%s (%s: %d): %s", func, file, line,
52				 condition_errmsg);
53	else if (TEST_RETURN != -1)
54		tst_resm(TFAIL,
55			 "%s (%s: %d): Unexpected return value; expected %ld, got %ld",
56			 func, file, line, exp_return, TEST_RETURN);
57	else
58		tst_resm(TFAIL | TTERRNO, "%s (%s: %d): Unexpected failure",
59			 func, file, line);
60}
61
62#define REPORT_SUCCESS_COND(exp_return, exp_errno, condition, condition_errmsg)	\
63	report_success_cond(__FUNCTION__, __FILE__, __LINE__, exp_return, exp_errno, condition, condition_errmsg);
64
65/* Report success iff TEST_RETURN and TEST_ERRNO are equal to
66	 exp_return and exp_errno, resp.
67*/
68#define REPORT_SUCCESS(exp_return, exp_errno)					\
69	REPORT_SUCCESS_COND(exp_return, exp_errno, 1, "");
70
71static void cleanup(void);
72
73static void empty_handler(int sig)
74{
75}
76
77static void setup(void)
78{
79	tst_sig(FORK, DEF_HANDLER, cleanup);
80	signal(SIGUSR1, empty_handler);
81	signal(SIGALRM, empty_handler);
82	signal(SIGUSR2, SIG_IGN);
83
84	TEST_PAUSE;
85}
86
87static void cleanup(void)
88{
89}
90
91typedef int (*swi_func) (const sigset_t * set, siginfo_t * info,
92			 struct timespec * timeout);
93typedef void (*test_func) (swi_func, int);
94
95#ifdef TEST_SIGWAIT
96static int my_sigwait(const sigset_t * set, siginfo_t * info,
97		      struct timespec *timeout)
98{
99	int ret;
100	int err = sigwait(set, &ret);
101
102	if (err == 0)
103		return ret;
104	errno = err;
105	return -1;
106}
107#endif
108
109#ifdef TEST_SIGWAITINFO
110static int my_sigwaitinfo(const sigset_t * set, siginfo_t * info,
111			  struct timespec *timeout)
112{
113
114	return sigwaitinfo(set, info);
115}
116#endif
117
118#ifdef TEST_SIGTIMEDWAIT
119static int my_sigtimedwait(const sigset_t * set, siginfo_t * info,
120			   struct timespec *timeout)
121{
122
123	return sigtimedwait(set, info, timeout);
124}
125#endif
126
127#ifdef TEST_RT_SIGTIMEDWAIT
128static int my_rt_sigtimedwait(const sigset_t * set, siginfo_t * info,
129			      struct timespec *timeout)
130{
131
132	/* The last argument is (number_of_signals)/(bits_per_byte), which are 64 and 8, resp. */
133	return ltp_syscall(__NR_rt_sigtimedwait, set, info, timeout, 8);
134}
135#endif
136
137void test_empty_set(swi_func sigwaitinfo, int signo)
138{
139	sigset_t sigs;
140	siginfo_t si;
141	pid_t child;
142
143	SUCCEED_OR_DIE(sigemptyset, "sigemptyset failed", &sigs);
144	/* Run a child that will wake us up */
145	child = create_sig_proc(100000, signo, UINT_MAX);
146
147	TEST(sigwaitinfo(&sigs, &si, NULL));
148	REPORT_SUCCESS(-1, EINTR);
149
150	kill(child, SIGTERM);
151}
152
153void test_timeout(swi_func sigwaitinfo, int signo)
154{
155	sigset_t sigs;
156	siginfo_t si;
157	pid_t child;
158	struct timespec ts = {.tv_sec = 1 };
159
160	SUCCEED_OR_DIE(sigemptyset, "sigemptyset failed", &sigs);
161
162	/* Run a child that will wake us up */
163	child = create_sig_proc(100000, signo, UINT_MAX);
164
165	TEST(sigwaitinfo(&sigs, &si, &ts));
166	REPORT_SUCCESS(-1, EAGAIN);
167
168	kill(child, SIGTERM);
169}
170
171/* Note: sigwait-ing for a signal that is not blocked is unspecified
172 * by POSIX; but works for non-ignored signals under Linux
173 */
174void test_unmasked_matching(swi_func sigwaitinfo, int signo)
175{
176	sigset_t sigs;
177	siginfo_t si;
178	pid_t child;
179
180	SUCCEED_OR_DIE(sigemptyset, "sigemptyset failed", &sigs);
181	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, signo);
182
183	/* Run a child that will wake us up */
184	child = create_sig_proc(100000, signo, UINT_MAX);
185
186	TEST(sigwaitinfo(&sigs, &si, NULL));
187	REPORT_SUCCESS_COND(signo, 0, si.si_pid == child
188			    && si.si_code == SI_USER
189			    && si.si_signo == signo, "Struct siginfo mismatch");
190
191	kill(child, SIGTERM);
192}
193
194void test_unmasked_matching_noinfo(swi_func sigwaitinfo, int signo)
195{
196	sigset_t sigs;
197	pid_t child;
198
199	SUCCEED_OR_DIE(sigemptyset, "sigemptyset failed", &sigs);
200	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, signo);
201	/* Run a child that will wake us up */
202	child = create_sig_proc(100000, signo, UINT_MAX);
203
204	TEST(sigwaitinfo(&sigs, NULL, NULL));
205	REPORT_SUCCESS(signo, 0);
206
207	kill(child, SIGTERM);
208}
209
210void test_masked_matching(swi_func sigwaitinfo, int signo)
211{
212	sigset_t sigs, oldmask;
213	siginfo_t si;
214	pid_t child;
215
216	SUCCEED_OR_DIE(sigemptyset, "sigemptyset failed", &sigs);
217	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, signo);
218	/* let's not get interrupted by our dying child */
219	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, SIGCHLD);
220
221	SUCCEED_OR_DIE(sigprocmask, "sigprocmask failed", SIG_SETMASK, &sigs,
222		       &oldmask);
223
224	/* don't wait on a SIGCHLD */
225	SUCCEED_OR_DIE(sigdelset, "sigaddset failed", &sigs, SIGCHLD);
226
227	/* Run a child that will wake us up */
228	child = create_sig_proc(0, signo, 1);
229
230	TEST(sigwaitinfo(&sigs, &si, NULL));
231	REPORT_SUCCESS_COND(signo, 0, si.si_pid == child
232			    && si.si_code == SI_USER
233			    && si.si_signo == signo, "Struct siginfo mismatch");
234
235	SUCCEED_OR_DIE(sigprocmask, "restoring original signal mask failed",
236		       SIG_SETMASK, &oldmask, &oldmask);
237
238	tst_count--;
239
240	if (sigismember(&oldmask, signo))
241		tst_resm(TPASS, "sigwaitinfo restored the original mask");
242	else
243		tst_resm(TFAIL,
244			 "sigwaitinfo failed to restore the original mask");
245}
246
247void test_masked_matching_rt(swi_func sigwaitinfo, int signo)
248{
249	sigset_t sigs, oldmask;
250	siginfo_t si;
251	pid_t child[2];
252
253	signo = SIGRTMIN + 1;
254
255	SUCCEED_OR_DIE(sigemptyset, "sigemptyset failed", &sigs);
256	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, signo);
257	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, signo + 1);
258	/* let's not get interrupted by our dying child */
259	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, SIGCHLD);
260
261	SUCCEED_OR_DIE(sigprocmask, "sigprocmask failed", SIG_SETMASK, &sigs,
262		       &oldmask);
263
264	/* don't wait on a SIGCHLD */
265	SUCCEED_OR_DIE(sigdelset, "sigdelset failed", &sigs, SIGCHLD);
266
267	/* Run a child that will wake us up */
268	child[0] = create_sig_proc(0, signo, 1);
269	child[1] = create_sig_proc(0, signo + 1, 1);
270
271	TEST(sigwaitinfo(&sigs, &si, NULL));
272	REPORT_SUCCESS_COND(signo, 0, si.si_pid == child[0]
273			    && si.si_code == SI_USER
274			    && si.si_signo == signo, "Struct siginfo mismatch");
275
276	/* eat the other signal */
277	tst_count--;
278	TEST(sigwaitinfo(&sigs, &si, NULL));
279	REPORT_SUCCESS_COND(signo + 1, 0, si.si_pid == child[1]
280			    && si.si_code == SI_USER
281			    && si.si_signo == signo + 1,
282			    "Struct siginfo mismatch");
283
284	SUCCEED_OR_DIE(sigprocmask, "restoring original signal mask failed",
285		       SIG_SETMASK, &oldmask, &oldmask);
286
287	tst_count--;
288
289	if (sigismember(&oldmask, signo))
290		tst_resm(TPASS, "sigwaitinfo restored the original mask");
291	else
292		tst_resm(TFAIL,
293			 "sigwaitinfo failed to restore the original mask");
294}
295
296void test_masked_matching_noinfo(swi_func sigwaitinfo, int signo)
297{
298	sigset_t sigs, oldmask;
299	pid_t child;
300
301	SUCCEED_OR_DIE(sigemptyset, "sigemptyset failed", &sigs);
302	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, signo);
303	/* let's not get interrupted by our dying child */
304	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, SIGCHLD);
305
306	SUCCEED_OR_DIE(sigprocmask, "sigprocmask failed", SIG_SETMASK, &sigs,
307		       &oldmask);
308
309	/* don't wait on a SIGCHLD */
310	SUCCEED_OR_DIE(sigdelset, "sigaddset failed", &sigs, SIGCHLD);
311
312	/* Run a child that will wake us up */
313	child = create_sig_proc(0, signo, 1);
314
315	TEST(sigwaitinfo(&sigs, NULL, NULL));
316	REPORT_SUCCESS(signo, 0);
317
318	SUCCEED_OR_DIE(sigprocmask, "restoring original signal mask failed",
319		       SIG_SETMASK, &oldmask, &oldmask);
320
321	tst_count--;
322
323	if (sigismember(&oldmask, signo))
324		tst_resm(TPASS, "sigwaitinfo restored the original mask");
325	else
326		tst_resm(TFAIL,
327			 "sigwaitinfo failed to restore the original mask");
328
329}
330
331void test_bad_address(swi_func sigwaitinfo, int signo)
332{
333	sigset_t sigs, oldmask;
334	pid_t child;
335
336	SUCCEED_OR_DIE(sigemptyset, "sigemptyset failed", &sigs);
337	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, signo);
338	/* let's not get interrupted by our dying child */
339	SUCCEED_OR_DIE(sigaddset, "sigaddset failed", &sigs, SIGCHLD);
340
341	SUCCEED_OR_DIE(sigprocmask, "sigprocmask failed", SIG_SETMASK, &sigs,
342		       &oldmask);
343
344	/* don't wait on a SIGCHLD */
345	SUCCEED_OR_DIE(sigdelset, "sigaddset failed", &sigs, SIGCHLD);
346
347	/* Run a child that will wake us up */
348	child = create_sig_proc(0, signo, 1);
349
350	TEST(sigwaitinfo(&sigs, (void *)1, NULL));
351	REPORT_SUCCESS(-1, EFAULT);
352
353	SUCCEED_OR_DIE(sigprocmask, "sigprocmask failed", SIG_SETMASK, &oldmask,
354		       &oldmask);
355
356	kill(child, SIGTERM);
357}
358
359void test_bad_address2(swi_func sigwaitinfo, int signo)
360{
361	TEST(sigwaitinfo((void *)1, NULL, NULL));
362	REPORT_SUCCESS(-1, EFAULT);
363}
364
365void test_bad_address3(swi_func sigwaitinfo, int signo)
366{
367	sigset_t sigs;
368	SUCCEED_OR_DIE(sigemptyset, "sigemptyset failed", &sigs);
369
370	TEST(sigwaitinfo(&sigs, NULL, (void *)1));
371	REPORT_SUCCESS(-1, EFAULT);
372}
373
374struct test_desc {
375	test_func tf;
376	swi_func swi;
377	int signo;
378} tests[] = {
379#ifdef TEST_RT_SIGTIMEDWAIT
380	{
381	test_empty_set, my_rt_sigtimedwait, SIGUSR1}, {
382	test_unmasked_matching, my_rt_sigtimedwait, SIGUSR1}, {
383	test_masked_matching, my_rt_sigtimedwait, SIGUSR1}, {
384	test_unmasked_matching_noinfo, my_rt_sigtimedwait, SIGUSR1}, {
385	test_masked_matching_noinfo, my_rt_sigtimedwait, SIGUSR1}, {
386	test_bad_address, my_rt_sigtimedwait, SIGUSR1}, {
387	test_bad_address2, my_rt_sigtimedwait, SIGUSR1}, {
388	test_bad_address3, my_rt_sigtimedwait, SIGUSR1}, {
389	test_timeout, my_rt_sigtimedwait, 0},
390	    /* Special cases */
391	    /* 1: sigwaitinfo does respond to ignored signal */
392	{
393	test_masked_matching, my_rt_sigtimedwait, SIGUSR2},
394	    /* 2: An ignored signal doesn't cause sigwaitinfo to return EINTR */
395	{
396	test_timeout, my_rt_sigtimedwait, SIGUSR2},
397	    /* 3: The handler is not called when the signal is waited for by sigwaitinfo */
398	{
399	test_masked_matching, my_rt_sigtimedwait, SIGTERM},
400	    /* 4: Simultaneous realtime signals are delivered in the order of increasing signal number */
401	{
402	test_masked_matching_rt, my_rt_sigtimedwait, -1},
403#endif
404#if defined TEST_SIGWAIT
405	{
406	test_unmasked_matching_noinfo, my_sigwait, SIGUSR1}, {
407	test_masked_matching_noinfo, my_sigwait, SIGUSR1},
408#endif
409#if defined TEST_SIGWAITINFO
410	{
411	test_empty_set, my_sigwaitinfo, SIGUSR1}, {
412	test_unmasked_matching, my_sigwaitinfo, SIGUSR1}, {
413	test_masked_matching, my_sigwaitinfo, SIGUSR1}, {
414	test_unmasked_matching_noinfo, my_sigwaitinfo, SIGUSR1}, {
415	test_masked_matching_noinfo, my_sigwaitinfo, SIGUSR1}, {
416	test_bad_address, my_sigwaitinfo, SIGUSR1}, {
417	test_bad_address2, my_sigwaitinfo, SIGUSR1},
418#endif
419#if defined TEST_SIGTIMEDWAIT
420	{
421	test_empty_set, my_sigtimedwait, SIGUSR1}, {
422	test_unmasked_matching, my_sigtimedwait, SIGUSR1}, {
423	test_masked_matching, my_sigtimedwait, SIGUSR1}, {
424	test_unmasked_matching_noinfo, my_sigtimedwait, SIGUSR1}, {
425	test_masked_matching_noinfo, my_sigtimedwait, SIGUSR1}, {
426	test_bad_address, my_sigtimedwait, SIGUSR1}, {
427	test_bad_address2, my_sigtimedwait, SIGUSR1}, {
428	test_bad_address3, my_sigtimedwait, SIGUSR1}, {
429	test_timeout, my_sigtimedwait, 0},
430#endif
431};
432
433#if defined TEST_SIGWAITINFO
434const char *TCID = "sigwaitinfo01";
435#elif defined TEST_RT_SIGTIMEDWAIT
436const char *TCID = "rt_sigtimedwait01";
437#elif defined TEST_SIGTIMEDWAIT
438const char *TCID = "sigtimedwait01";
439#elif defined TEST_SIGWAIT
440const char *TCID = "sigwait01";
441#endif
442
443int TST_TOTAL = ARRAY_SIZE(tests);
444
445int main(int argc, char **argv)
446{
447	unsigned i;
448	int lc;
449
450	tst_parse_opts(argc, argv, NULL, NULL);
451
452	setup();
453
454	for (lc = 0; TEST_LOOPING(lc); ++lc) {
455		tst_count = 0;
456
457		for (i = 0; i < ARRAY_SIZE(tests); i++) {
458			alarm(10);	/* arrange a 10 second timeout */
459			tst_resm(TINFO, "%p, %d", tests[i].swi, tests[i].signo);
460			tests[i].tf(tests[i].swi, tests[i].signo);
461		}
462		alarm(0);
463	}
464
465	cleanup();
466	tst_exit();
467}
468