1 /* 2 * Copyright (c) 2016 Fujitsu Ltd. 3 * Author: Guangwen Feng <fenggw-fnst (at) 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_wait(2). 22 * Check that epoll_wait(2) works for EPOLLOUT and EPOLLIN events 23 * on a epoll instance and that struct epoll_event is set correctly. 24 */ 25 26 #include <sys/epoll.h> 27 #include <poll.h> 28 #include <string.h> 29 #include <errno.h> 30 31 #include "test.h" 32 #include "safe_macros.h" 33 34 char *TCID = "epoll_wait01"; 35 int TST_TOTAL = 3; 36 37 static int write_size, epfd, fds[2], fds2[2]; 38 static struct epoll_event epevs[3] = { 39 {.events = EPOLLIN}, 40 {.events = EPOLLOUT}, 41 {.events = EPOLLIN} 42 }; 43 44 static void setup(void); 45 static int get_writesize(void); 46 static void verify_epollout(void); 47 static void verify_epollin(void); 48 static void verify_epollio(void); 49 static int has_event(struct epoll_event *, int, int, uint32_t); 50 static void dump_epevs(struct epoll_event *, int); 51 static void cleanup(void); 52 53 int main(int ac, char **av) 54 { 55 int lc; 56 57 tst_parse_opts(ac, av, NULL, NULL); 58 59 setup(); 60 61 for (lc = 0; TEST_LOOPING(lc); lc++) { 62 tst_count = 0; 63 64 verify_epollout(); 65 verify_epollin(); 66 verify_epollio(); 67 } 68 69 cleanup(); 70 tst_exit(); 71 } 72 73 static void setup(void) 74 { 75 tst_sig(NOFORK, DEF_HANDLER, cleanup); 76 77 TEST_PAUSE; 78 79 SAFE_PIPE(NULL, fds); 80 SAFE_PIPE(cleanup, fds2); 81 82 write_size = get_writesize(); 83 84 epfd = epoll_create(3); 85 if (epfd == -1) { 86 tst_brkm(TBROK | TERRNO, cleanup, 87 "failed to create epoll instance"); 88 } 89 90 epevs[0].data.fd = fds[0]; 91 epevs[1].data.fd = fds[1]; 92 epevs[2].data.fd = fds2[0]; 93 94 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0]) || 95 epoll_ctl(epfd, EPOLL_CTL_ADD, fds[1], &epevs[1]) || 96 epoll_ctl(epfd, EPOLL_CTL_ADD, fds2[0], &epevs[2])) { 97 tst_brkm(TBROK | TERRNO, cleanup, 98 "failed to register epoll target"); 99 } 100 } 101 102 static int get_writesize(void) 103 { 104 int nfd, write_size = 0; 105 char buf[4096]; 106 107 struct pollfd pfd[] = { 108 {.fd = fds[1], .events = POLLOUT}, 109 }; 110 111 memset(buf, 'a', sizeof(buf)); 112 113 do { 114 write_size += SAFE_WRITE(cleanup, 0, fds[1], buf, sizeof(buf)); 115 nfd = poll(pfd, 1, 1); 116 if (nfd == -1) 117 tst_brkm(TBROK | TERRNO, cleanup, "poll failed"); 118 } while (nfd > 0); 119 120 char read_buf[write_size]; 121 122 SAFE_READ(cleanup, 1, fds[0], read_buf, sizeof(read_buf)); 123 124 tst_resm(TINFO, "Pipe buffer size is %i bytes", write_size); 125 126 return write_size; 127 } 128 129 static void verify_epollout(void) 130 { 131 TEST(epoll_wait(epfd, epevs, 3, -1)); 132 133 if (TEST_RETURN == -1) { 134 tst_resm(TFAIL | TTERRNO, "epoll_wait() epollout failed"); 135 return; 136 } 137 138 if (TEST_RETURN != 1) { 139 tst_resm(TFAIL, "epoll_wait() returned %li, expected 1", 140 TEST_RETURN); 141 return; 142 } 143 144 if (epevs[0].data.fd != fds[1]) { 145 tst_resm(TFAIL, "epoll.data.fd %i, expected %i", 146 epevs[0].data.fd, fds[1]); 147 return; 148 } 149 150 if (epevs[0].events != EPOLLOUT) { 151 tst_resm(TFAIL, "epoll.events %x, expected EPOLLOUT %x", 152 epevs[0].events, EPOLLOUT); 153 return; 154 } 155 156 tst_resm(TPASS, "epoll_wait() epollout"); 157 } 158 159 static void verify_epollin(void) 160 { 161 char write_buf[write_size]; 162 char read_buf[sizeof(write_buf)]; 163 164 memset(write_buf, 'a', sizeof(write_buf)); 165 166 SAFE_WRITE(cleanup, 1, fds[1], write_buf, sizeof(write_buf)); 167 168 TEST(epoll_wait(epfd, epevs, 3, -1)); 169 170 if (TEST_RETURN == -1) { 171 tst_resm(TFAIL | TTERRNO, "epoll_wait() epollin failed"); 172 goto end; 173 } 174 175 if (TEST_RETURN != 1) { 176 tst_resm(TFAIL, "epoll_wait() returned %li, expected 1", 177 TEST_RETURN); 178 goto end; 179 } 180 181 if (epevs[0].data.fd != fds[0]) { 182 tst_resm(TFAIL, "epoll.data.fd %i, expected %i", 183 epevs[0].data.fd, fds[0]); 184 goto end; 185 } 186 187 if (epevs[0].events != EPOLLIN) { 188 tst_resm(TFAIL, "epoll.events %x, expected EPOLLIN %x", 189 epevs[0].events, EPOLLIN); 190 goto end; 191 } 192 193 tst_resm(TPASS, "epoll_wait() epollin"); 194 195 end: 196 SAFE_READ(cleanup, 1, fds[0], read_buf, sizeof(write_buf)); 197 } 198 199 static void verify_epollio(void) 200 { 201 char write_buf[] = "Testing"; 202 char read_buf[sizeof(write_buf)]; 203 204 SAFE_WRITE(cleanup, 1, fds[1], write_buf, sizeof(write_buf)); 205 206 TEST(epoll_wait(epfd, epevs, 3, -1)); 207 208 if (TEST_RETURN == -1) { 209 tst_resm(TFAIL | TTERRNO, "epoll_wait() epollio failed"); 210 goto end; 211 } 212 213 if (TEST_RETURN != 2) { 214 tst_resm(TFAIL, "epoll_wait() returned %li, expected 2", 215 TEST_RETURN); 216 goto end; 217 } 218 219 if (!has_event(epevs, 2, fds[0], EPOLLIN)) { 220 dump_epevs(epevs, 2); 221 tst_resm(TFAIL, "epoll_wait() expected %d and EPOLLIN %x", 222 fds[0], EPOLLIN); 223 goto end; 224 } 225 226 if (!has_event(epevs, 2, fds[1], EPOLLOUT)) { 227 dump_epevs(epevs, 2); 228 tst_resm(TFAIL, "epoll_wait() expected %d and EPOLLOUT %x", 229 fds[1], EPOLLOUT); 230 goto end; 231 } 232 233 tst_resm(TPASS, "epoll_wait() epollio"); 234 235 end: 236 SAFE_READ(cleanup, 1, fds[0], read_buf, sizeof(write_buf)); 237 } 238 239 static int has_event(struct epoll_event *epevs, int epevs_len, 240 int fd, uint32_t events) 241 { 242 int i; 243 244 for (i = 0; i < epevs_len; i++) { 245 if ((epevs[i].data.fd == fd) && (epevs[i].events == events)) 246 return 1; 247 } 248 249 return 0; 250 } 251 252 static void dump_epevs(struct epoll_event *epevs, int epevs_len) 253 { 254 int i; 255 256 for (i = 0; i < epevs_len; i++) { 257 tst_resm(TINFO, "epevs[%d]: epoll.data.fd %d, epoll.events %x", 258 i, epevs[i].data.fd, epevs[i].events); 259 } 260 } 261 262 static void cleanup(void) 263 { 264 if (epfd > 0 && close(epfd)) 265 tst_resm(TWARN | TERRNO, "failed to close epfd"); 266 267 if (close(fds[0])) 268 tst_resm(TWARN | TERRNO, "failed to close fds[0]"); 269 270 if (close(fds[1])) 271 tst_resm(TWARN | TERRNO, "failed to close fds[1]"); 272 273 if (fds2[0] > 0 && close(fds2[0])) 274 tst_resm(TWARN | TERRNO, "failed to close fds2[0]"); 275 276 if (fds2[1] > 0 && close(fds2[1])) 277 tst_resm(TWARN | TERRNO, "failed to close fds2[1]"); 278 } 279