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
main(int ac,char ** av)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
setup(void)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
verify_sigmask(void)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
verify_nonsigmask(void)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
sighandler(int sig LTP_ATTRIBUTE_UNUSED)148 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
149 {
150
151 }
152
do_test(sigset_t * sigmask)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
do_child(void)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
cleanup(void)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