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 
40 char *TCID = "epoll_pwait01";
41 int TST_TOTAL = 2;
42 
43 static int epfd, fds[2];
44 static sigset_t signalset;
45 static struct epoll_event epevs;
46 static struct sigaction sa;
47 
48 static void setup(void);
49 static void verify_sigmask(void);
50 static void verify_nonsigmask(void);
51 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED);
52 static void do_test(sigset_t *);
53 static void do_child(void);
54 static void cleanup(void);
55 
56 int 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 
75 static 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 
117 static 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 
133 static 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 
148 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
149 {
150 
151 }
152 
153 static 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 
174 static 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 
187 static 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