1/*
2 * Copyright (c) 2016 Fujitsu Ltd.
3 * Author: Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.
17 */
18
19/*
20 * Description:
21 *  Basic test for epoll_pwait(2).
22 *  1) epoll_pwait(2) with sigmask argument allows the caller to
23 *     safely wait until either a file descriptor becomes ready
24 *     or the timeout expires.
25 *  2) epoll_pwait(2) with NULL sigmask argument fails if
26 *     interrupted by a signal handler, epoll_pwait(2) should
27 *     return -1 and set errno to EINTR.
28 */
29
30#include <sys/epoll.h>
31#include <sys/types.h>
32#include <unistd.h>
33#include <string.h>
34#include <errno.h>
35
36#include "test.h"
37#include "epoll_pwait.h"
38#include "safe_macros.h"
39
40char *TCID = "epoll_pwait01";
41int TST_TOTAL = 2;
42
43static int epfd, fds[2];
44static sigset_t signalset;
45static struct epoll_event epevs;
46static struct sigaction sa;
47
48static void setup(void);
49static void verify_sigmask(void);
50static void verify_nonsigmask(void);
51static void sighandler(int sig LTP_ATTRIBUTE_UNUSED);
52static void do_test(sigset_t *);
53static void do_child(void);
54static void cleanup(void);
55
56int main(int ac, char **av)
57{
58	int lc;
59
60	tst_parse_opts(ac, av, NULL, NULL);
61
62	setup();
63
64	for (lc = 0; TEST_LOOPING(lc); lc++) {
65		tst_count = 0;
66
67		do_test(&signalset);
68		do_test(NULL);
69	}
70
71	cleanup();
72	tst_exit();
73}
74
75static void setup(void)
76{
77	if ((tst_kvercmp(2, 6, 19)) < 0) {
78		tst_brkm(TCONF, NULL, "This test can only run on kernels "
79			 "that are 2.6.19 or higher");
80	}
81
82	tst_sig(FORK, DEF_HANDLER, cleanup);
83
84	TEST_PAUSE;
85
86	if (sigemptyset(&signalset) == -1)
87		tst_brkm(TFAIL | TERRNO, NULL, "sigemptyset() failed");
88
89	if (sigaddset(&signalset, SIGUSR1) == -1)
90		tst_brkm(TFAIL | TERRNO, NULL, "sigaddset() failed");
91
92	sa.sa_flags = 0;
93	sa.sa_handler = sighandler;
94	if (sigemptyset(&sa.sa_mask) == -1)
95		tst_brkm(TFAIL | TERRNO, NULL, "sigemptyset() failed");
96
97	if (sigaction(SIGUSR1, &sa, NULL) == -1)
98		tst_brkm(TFAIL | TERRNO, NULL, "sigaction() failed");
99
100	SAFE_PIPE(NULL, fds);
101
102	epfd = epoll_create(1);
103	if (epfd == -1) {
104		tst_brkm(TBROK | TERRNO, cleanup,
105			 "failed to create epoll instance");
106	}
107
108	epevs.events = EPOLLIN;
109	epevs.data.fd = fds[0];
110
111	if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs) == -1) {
112		tst_brkm(TBROK | TERRNO, cleanup,
113			 "failed to register epoll target");
114	}
115}
116
117static void verify_sigmask(void)
118{
119	if (TEST_RETURN == -1) {
120		tst_resm(TFAIL | TTERRNO, "epoll_pwait() failed");
121		return;
122	}
123
124	if (TEST_RETURN != 0) {
125		tst_resm(TFAIL, "epoll_pwait() returned %li, expected 0",
126			 TEST_RETURN);
127		return;
128	}
129
130	tst_resm(TPASS, "epoll_pwait(sigmask) blocked signal");
131}
132
133static void verify_nonsigmask(void)
134{
135	if (TEST_RETURN != -1) {
136		tst_resm(TFAIL, "epoll_wait() succeeded unexpectedly");
137		return;
138	}
139
140	if (TEST_ERRNO == EINTR) {
141		tst_resm(TPASS | TTERRNO, "epoll_wait() failed as expected");
142	} else {
143		tst_resm(TFAIL | TTERRNO, "epoll_wait() failed unexpectedly, "
144				 "expected EINTR");
145	}
146}
147
148static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
149{
150
151}
152
153static void do_test(sigset_t *sigmask)
154{
155	pid_t cpid;
156
157	cpid = tst_fork();
158	if (cpid < 0)
159		tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
160
161	if (cpid == 0)
162		do_child();
163
164	TEST(epoll_pwait(epfd, &epevs, 1, 100, sigmask));
165
166	if (sigmask != NULL)
167		verify_sigmask();
168	else
169		verify_nonsigmask();
170
171	tst_record_childstatus(cleanup, cpid);
172}
173
174static void do_child(void)
175{
176	if (tst_process_state_wait2(getppid(), 'S') != 0) {
177		tst_brkm(TBROK | TERRNO, cleanup,
178			 "failed to wait for parent process's state");
179	}
180
181	SAFE_KILL(cleanup, getppid(), SIGUSR1);
182
183	cleanup();
184	tst_exit();
185}
186
187static void cleanup(void)
188{
189	if (epfd > 0 && close(epfd))
190		tst_resm(TWARN | TERRNO, "failed to close epfd");
191
192	if (close(fds[0]))
193		tst_resm(TWARN | TERRNO, "close(fds[0]) failed");
194
195	if (close(fds[1]))
196		tst_resm(TWARN | TERRNO, "close(fds[1]) failed");
197}
198