configure: add '-Wredundant-decls' to warning flags
[lttng-tools.git] / tests / regression / kernel / select_poll_epoll.cpp
CommitLineData
9d16b343
MJ
1/*
2 * Copyright (C) 2016 Julien Desfossez <jdesfossez@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
a0b1f42c
JD
8#include <stdio.h>
9#include <poll.h>
10#include <signal.h>
11#include <unistd.h>
12#include <sys/syscall.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <stdlib.h>
17#include <string.h>
18#include <stddef.h>
19#include <sys/select.h>
20#include <sys/epoll.h>
21#include <popt.h>
22#include <sys/time.h>
23#include <sys/resource.h>
24#include <limits.h>
25#include <pthread.h>
26#include <sys/mman.h>
389fbf04 27#include <common/compat/time.h>
d40c2620 28#include <common/error.h>
a0b1f42c
JD
29
30#define BUF_SIZE 256
31#define NB_FD 1
32#define MAX_FDS 2047
33#define NR_ITER 1000 /* for stress-tests */
34
35#define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */
36#define BIG_SELECT_FD 1022
37
38#define MSEC_PER_USEC 1000
39#define MSEC_PER_NSEC (MSEC_PER_USEC * 1000)
40
41static int timeout; /* seconds, -1 to disable */
44a411a6 42static volatile int stop_thread;
a0b1f42c
JD
43static int wait_fd;
44
d40c2620
JG
45/* Used by logging utils. */
46int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi;
47
48static void run_working_cases(FILE *validation_output_file);
49static void pselect_invalid_fd(FILE *validation_output_file);
50static void test_ppoll_big(FILE *validation_output_file);
51static void ppoll_fds_buffer_overflow(FILE *validation_output_file);
52static void pselect_invalid_pointer(FILE *validation_output_file);
53static void ppoll_fds_ulong_max(FILE *validation_output_file);
54static void epoll_pwait_invalid_pointer(FILE *validation_output_file);
55static void epoll_pwait_int_max(FILE *validation_output_file);
56static void ppoll_concurrent_write(FILE *validation_output_file);
57static void epoll_pwait_concurrent_munmap(FILE *validation_output_file);
58
59typedef void (*test_case_cb)(FILE *output_file);
60
61static const struct test_case {
62 test_case_cb run;
63 bool produces_validation_info;
64 int timeout;
65} test_cases [] =
66{
67 { .run = run_working_cases, .produces_validation_info = true, .timeout = -1 },
68 { .run = run_working_cases, .produces_validation_info = true, .timeout = 1 },
69 { .run = pselect_invalid_fd, .produces_validation_info = false },
70 { .run = test_ppoll_big, .produces_validation_info = false },
71 { .run = ppoll_fds_buffer_overflow, .produces_validation_info = false },
72 { .run = pselect_invalid_pointer, .produces_validation_info = false },
73 { .run = ppoll_fds_ulong_max, .produces_validation_info = false },
74 { .run = epoll_pwait_invalid_pointer, .produces_validation_info = true },
75 { .run = epoll_pwait_int_max, .produces_validation_info = true },
76 { .run = ppoll_concurrent_write, .produces_validation_info = false },
77 { .run = epoll_pwait_concurrent_munmap, .produces_validation_info = true },
78};
79
a0b1f42c
JD
80struct ppoll_thread_data {
81 struct pollfd *ufds;
82 int value;
83};
84
f12eb9c1 85static
a0b1f42c
JD
86void test_select_big(void)
87{
88 fd_set rfds, wfds, exfds;
89 struct timeval tv;
90 int ret;
91 int fd2;
92 char buf[BUF_SIZE];
93
94 FD_ZERO(&rfds);
95 FD_ZERO(&wfds);
96 FD_ZERO(&exfds);
97
98 fd2 = dup2(wait_fd, BIG_SELECT_FD);
99 if (fd2 < 0) {
d40c2620 100 PERROR("dup2");
a0b1f42c
JD
101 goto end;
102 }
103 FD_SET(fd2, &rfds);
104
105 tv.tv_sec = 0;
106 tv.tv_usec = timeout * MSEC_PER_USEC;
107
108 if (timeout > 0) {
109 ret = select(fd2 + 1, &rfds, &wfds, &exfds, &tv);
110 } else {
111 ret = select(fd2 + 1, &rfds, &wfds, &exfds, NULL);
112 }
113
114 if (ret == -1) {
d40c2620 115 PERROR("select()");
a0b1f42c 116 } else if (ret) {
a0b1f42c
JD
117 ret = read(wait_fd, buf, BUF_SIZE);
118 if (ret < 0) {
d40c2620 119 PERROR("[select] read");
a0b1f42c 120 }
a0b1f42c
JD
121 }
122
123 ret = close(BIG_SELECT_FD);
124 if (ret) {
d40c2620 125 PERROR("close");
a0b1f42c
JD
126 }
127
128end:
129 return;
130}
131
f12eb9c1 132static
a0b1f42c
JD
133void test_pselect(void)
134{
135 fd_set rfds;
136 struct timespec tv;
137 int ret;
138 char buf[BUF_SIZE];
139
140 FD_ZERO(&rfds);
141 FD_SET(wait_fd, &rfds);
142
143 tv.tv_sec = 0;
144 tv.tv_nsec = timeout * MSEC_PER_NSEC;
145
146 if (timeout > 0) {
147 ret = pselect(1, &rfds, NULL, NULL, &tv, NULL);
148 } else {
149 ret = pselect(1, &rfds, NULL, NULL, NULL, NULL);
150 }
151
152 if (ret == -1) {
d40c2620 153 PERROR("pselect()");
a0b1f42c 154 } else if (ret) {
a0b1f42c
JD
155 ret = read(wait_fd, buf, BUF_SIZE);
156 if (ret < 0) {
d40c2620 157 PERROR("[pselect] read");
a0b1f42c 158 }
a0b1f42c 159 }
a0b1f42c
JD
160}
161
f12eb9c1 162static
a0b1f42c
JD
163void test_select(void)
164{
165 fd_set rfds;
166 struct timeval tv;
167 int ret;
168 char buf[BUF_SIZE];
169
170 FD_ZERO(&rfds);
171 FD_SET(wait_fd, &rfds);
172
173 tv.tv_sec = 0;
174 tv.tv_usec = timeout * MSEC_PER_USEC;
175
176 if (timeout > 0) {
177 ret = select(1, &rfds, NULL, NULL, &tv);
178 } else {
179 ret = select(1, &rfds, NULL, NULL, NULL);
180 }
181
182 if (ret == -1) {
d40c2620 183 PERROR("select()");
a0b1f42c 184 } else if (ret) {
a0b1f42c
JD
185 ret = read(wait_fd, buf, BUF_SIZE);
186 if (ret < 0) {
d40c2620 187 PERROR("[select] read");
a0b1f42c 188 }
a0b1f42c 189 }
a0b1f42c
JD
190}
191
f12eb9c1 192static
a0b1f42c
JD
193void test_poll(void)
194{
195 struct pollfd ufds[NB_FD];
196 char buf[BUF_SIZE];
197 int ret;
198
199 ufds[0].fd = wait_fd;
200 ufds[0].events = POLLIN|POLLPRI;
201
202 ret = poll(ufds, 1, timeout);
203
204 if (ret < 0) {
d40c2620 205 PERROR("poll");
a0b1f42c 206 } else if (ret > 0) {
a0b1f42c
JD
207 ret = read(wait_fd, buf, BUF_SIZE);
208 if (ret < 0) {
d40c2620 209 PERROR("[poll] read");
a0b1f42c 210 }
a0b1f42c
JD
211 }
212}
213
f12eb9c1 214static
a0b1f42c
JD
215void test_ppoll(void)
216{
217 struct pollfd ufds[NB_FD];
218 char buf[BUF_SIZE];
219 int ret;
220 struct timespec ts;
221
222 ufds[0].fd = wait_fd;
223 ufds[0].events = POLLIN|POLLPRI;
224
225 if (timeout > 0) {
226 ts.tv_sec = 0;
227 ts.tv_nsec = timeout * MSEC_PER_NSEC;
228 ret = ppoll(ufds, 1, &ts, NULL);
229 } else {
230 ret = ppoll(ufds, 1, NULL, NULL);
231 }
232
233
234 if (ret < 0) {
d40c2620 235 PERROR("ppoll");
a0b1f42c 236 } else if (ret > 0) {
a0b1f42c
JD
237 ret = read(wait_fd, buf, BUF_SIZE);
238 if (ret < 0) {
d40c2620 239 PERROR("[ppoll] read");
a0b1f42c 240 }
a0b1f42c
JD
241 }
242}
243
f12eb9c1 244static
d40c2620 245void test_ppoll_big(FILE *validation_output_file)
a0b1f42c
JD
246{
247 struct pollfd ufds[MAX_FDS];
248 char buf[BUF_SIZE];
249 int ret, i, fds[MAX_FDS];
250
251 for (i = 0; i < MAX_FDS; i++) {
252 fds[i] = dup(wait_fd);
253 if (fds[i] < 0) {
d40c2620 254 PERROR("dup");
a0b1f42c
JD
255 }
256 ufds[i].fd = fds[i];
257 ufds[i].events = POLLIN|POLLPRI;
258 }
259
260 ret = ppoll(ufds, MAX_FDS, NULL, NULL);
261
262 if (ret < 0) {
d40c2620 263 PERROR("ppoll");
a0b1f42c 264 } else if (ret > 0) {
a0b1f42c
JD
265 ret = read(wait_fd, buf, BUF_SIZE);
266 if (ret < 0) {
d40c2620 267 PERROR("[ppoll] read");
a0b1f42c 268 }
a0b1f42c
JD
269 }
270
271 for (i = 0; i < MAX_FDS; i++) {
272 ret = close(fds[i]);
273 if (ret != 0) {
d40c2620 274 PERROR("close");
a0b1f42c
JD
275 }
276 }
277
278 return;
279}
280
f12eb9c1 281static
d40c2620 282void test_epoll(FILE *validation_output_file)
a0b1f42c
JD
283{
284 int ret, epollfd;
285 char buf[BUF_SIZE];
286 struct epoll_event epoll_event;
287
288 epollfd = epoll_create(NB_FD);
289 if (epollfd < 0) {
d40c2620 290 PERROR("[epoll] create");
a0b1f42c
JD
291 goto end;
292 }
293
d40c2620
JG
294 ret = fprintf(validation_output_file,
295 ", \"epoll_wait_fd\": %i", epollfd);
296 if (ret < 0) {
297 PERROR("[epoll] Failed to write test validation output");
298 goto error;
299 }
300
a0b1f42c
JD
301 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
302 epoll_event.data.fd = wait_fd;
303 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
304 if (ret < 0) {
d40c2620 305 PERROR("[epoll] add");
5305e823 306 goto error;
a0b1f42c
JD
307 }
308
309 if (timeout > 0) {
310 ret = epoll_wait(epollfd, &epoll_event, 1, timeout);
311 } else {
312 ret = epoll_wait(epollfd, &epoll_event, 1, -1);
313 }
314
315 if (ret == 1) {
a0b1f42c
JD
316 ret = read(wait_fd, buf, BUF_SIZE);
317 if (ret < 0) {
d40c2620 318 PERROR("[epoll] read");
a0b1f42c 319 }
d40c2620
JG
320 } else if (ret != 0) {
321 PERROR("epoll_wait");
a0b1f42c
JD
322 }
323
5305e823 324error:
6d52f14d
FD
325 ret = close(epollfd);
326 if (ret) {
d40c2620 327 PERROR("close");
6d52f14d 328 }
a0b1f42c
JD
329end:
330 return;
331}
332
f12eb9c1 333static
d40c2620 334void test_epoll_pwait(FILE *validation_output_file)
a0b1f42c
JD
335{
336 int ret, epollfd;
337 char buf[BUF_SIZE];
338 struct epoll_event epoll_event;
339
340 epollfd = epoll_create(NB_FD);
341 if (epollfd < 0) {
d40c2620 342 PERROR("[epoll_pwait] create");
a0b1f42c
JD
343 goto end;
344 }
345
d40c2620
JG
346 ret = fprintf(validation_output_file,
347 ", \"epoll_pwait_fd\": %i", epollfd);
348 if (ret < 0) {
349 PERROR("[epoll_pwait] Failed to write test validation output");
350 goto error;
351 }
352
a0b1f42c
JD
353 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
354 epoll_event.data.fd = wait_fd;
355 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
356 if (ret < 0) {
d40c2620 357 PERROR("[epoll_pwait] add");
5305e823 358 goto error;
a0b1f42c
JD
359 }
360
361 if (timeout > 0) {
362 ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, NULL);
363 } else {
364 ret = epoll_pwait(epollfd, &epoll_event, 1, -1, NULL);
365 }
366
367 if (ret == 1) {
a0b1f42c
JD
368 ret = read(wait_fd, buf, BUF_SIZE);
369 if (ret < 0) {
d40c2620 370 PERROR("[epoll_pwait] read");
a0b1f42c 371 }
d40c2620
JG
372 } else if (ret != 0) {
373 PERROR("epoll_pwait");
a0b1f42c
JD
374 }
375
5305e823 376error:
6d52f14d
FD
377 ret = close(epollfd);
378 if (ret) {
d40c2620 379 PERROR("close");
6d52f14d 380 }
a0b1f42c
JD
381end:
382 return;
383}
384
f12eb9c1 385static
d40c2620 386void run_working_cases(FILE *validation_output_file)
a0b1f42c
JD
387{
388 int ret;
389 int pipe_fds[2];
390
391 if (timeout > 0) {
392 /*
393 * We need an input pipe for some cases and stdin might
394 * have random data, so we create a dummy pipe for this
395 * test to make sure we are running under clean conditions.
396 */
397 ret = pipe(pipe_fds);
398 if (ret != 0) {
d40c2620 399 PERROR("pipe");
a0b1f42c
JD
400 goto end;
401 }
402 wait_fd = pipe_fds[0];
403 }
404 test_select();
405 test_pselect();
406 test_select_big();
407 test_poll();
408 test_ppoll();
d40c2620
JG
409
410 ret = fprintf(validation_output_file, "{ \"pid\": %i", getpid());
411 if (ret < 0) {
412 PERROR("Failed to write pid to test validation file");
413 goto end;
414 }
415
416 test_epoll(validation_output_file);
417 test_epoll_pwait(validation_output_file);
a0b1f42c
JD
418
419 if (timeout > 0) {
420 ret = close(pipe_fds[0]);
421 if (ret) {
d40c2620 422 PERROR("close");
a0b1f42c
JD
423 }
424 ret = close(pipe_fds[1]);
425 if (ret) {
d40c2620 426 PERROR("close");
a0b1f42c
JD
427 }
428 }
429
d40c2620
JG
430 ret = fputs(" }", validation_output_file);
431 if (ret < 0) {
432 PERROR("Failed to close JSON dictionary in test validation file");
433 goto end;
434 }
435
a0b1f42c
JD
436end:
437 return;
438}
439
440/*
441 * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
442 * segfault (eventually with a "*** stack smashing detected ***" message).
443 * The event should contain an array of 100 FDs filled with garbage.
444 */
f12eb9c1 445static
d40c2620 446void ppoll_fds_buffer_overflow(FILE *validation_output_file)
a0b1f42c
JD
447{
448 struct pollfd ufds[NB_FD];
449 char buf[BUF_SIZE];
450 int ret;
451
452 ufds[0].fd = wait_fd;
453 ufds[0].events = POLLIN|POLLPRI;
454
455 ret = syscall(SYS_ppoll, ufds, 100, NULL, NULL);
456
457 if (ret < 0) {
d40c2620 458 PERROR("ppoll");
a0b1f42c 459 } else if (ret > 0) {
a0b1f42c
JD
460 ret = read(wait_fd, buf, BUF_SIZE);
461 if (ret < 0) {
d40c2620 462 PERROR("[ppoll] read");
a0b1f42c 463 }
a0b1f42c 464 }
a0b1f42c
JD
465}
466
467/*
468 * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
469 * cleanly fail with a "Invalid argument".
470 * The event should contain an empty array of FDs and overflow = 1.
471 */
f12eb9c1 472static
d40c2620 473void ppoll_fds_ulong_max(FILE *validation_output_file)
a0b1f42c
JD
474{
475 struct pollfd ufds[NB_FD];
476 char buf[BUF_SIZE];
477 int ret;
478
479 ufds[0].fd = wait_fd;
480 ufds[0].events = POLLIN|POLLPRI;
481
482 ret = syscall(SYS_ppoll, ufds, ULONG_MAX, NULL, NULL);
a0b1f42c 483 if (ret < 0) {
d40c2620 484 /* Expected error. */
a0b1f42c 485 } else if (ret > 0) {
a0b1f42c
JD
486 ret = read(wait_fd, buf, BUF_SIZE);
487 if (ret < 0) {
d40c2620 488 PERROR("[ppoll] read");
a0b1f42c 489 }
a0b1f42c 490 }
a0b1f42c
JD
491}
492
493/*
8b3b99e2
FD
494 * Pass an invalid file descriptor to pselect6(). The syscall should return
495 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
a0b1f42c 496 */
f12eb9c1 497static
d40c2620 498void pselect_invalid_fd(FILE *validation_output_file)
a0b1f42c 499{
8b3b99e2 500 fd_set rfds;
a0b1f42c 501 int ret;
8b3b99e2 502 int fd;
a0b1f42c
JD
503 char buf[BUF_SIZE];
504
505 /*
8b3b99e2 506 * Open a file, close it and use the closed FD in the pselect6 call.
a0b1f42c 507 */
8b3b99e2
FD
508 fd = open("/dev/null", O_RDONLY);
509 if (fd == -1) {
d40c2620 510 PERROR("open");
8b3b99e2
FD
511 goto error;
512 }
513
514 ret = close(fd);
515 if (ret == -1) {
d40c2620 516 PERROR("close");
8b3b99e2 517 goto error;
a0b1f42c 518 }
e593ee02 519
8b3b99e2
FD
520 FD_ZERO(&rfds);
521 FD_SET(fd, &rfds);
a0b1f42c 522
8b3b99e2 523 ret = syscall(SYS_pselect6, fd + 1, &rfds, NULL, NULL, NULL, NULL);
a0b1f42c 524 if (ret == -1) {
d40c2620 525 /* Expected error. */
a0b1f42c 526 } else if (ret) {
a0b1f42c
JD
527 ret = read(wait_fd, buf, BUF_SIZE);
528 if (ret < 0) {
d40c2620 529 PERROR("[pselect] read");
a0b1f42c 530 }
a0b1f42c 531 }
8b3b99e2
FD
532error:
533 return;
a0b1f42c
JD
534}
535
536/*
537 * Invalid pointer as writefds, should output a ppoll event
538 * with 0 FDs.
539 */
f12eb9c1 540static
d40c2620 541void pselect_invalid_pointer(FILE *validation_output_file)
a0b1f42c
JD
542{
543 fd_set rfds;
544 int ret;
545 char buf[BUF_SIZE];
546 void *invalid = (void *) 0x42;
547
548 FD_ZERO(&rfds);
549 FD_SET(wait_fd, &rfds);
550
551 ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL,
552 NULL);
a0b1f42c 553 if (ret == -1) {
d40c2620 554 /* Expected error. */
a0b1f42c 555 } else if (ret) {
a0b1f42c
JD
556 ret = read(wait_fd, buf, BUF_SIZE);
557 if (ret < 0) {
d40c2620 558 PERROR("[pselect] read");
a0b1f42c 559 }
a0b1f42c 560 }
a0b1f42c
JD
561}
562
563/*
564 * Pass an invalid pointer to epoll_pwait, should fail with
565 * "Bad address", the event returns 0 FDs.
566 */
f12eb9c1 567static
d40c2620 568void epoll_pwait_invalid_pointer(FILE *validation_output_file)
a0b1f42c
JD
569{
570 int ret, epollfd;
571 char buf[BUF_SIZE];
572 struct epoll_event epoll_event;
573 void *invalid = (void *) 0x42;
574
575 epollfd = epoll_create(NB_FD);
576 if (epollfd < 0) {
d40c2620 577 PERROR("[epoll_pwait] create");
a0b1f42c
JD
578 goto end;
579 }
580
d40c2620
JG
581 ret = fprintf(validation_output_file,
582 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
583 getpid());
584 if (ret < 0) {
585 PERROR("[epoll_pwait] Failed to write test validation output");
586 goto error;
587 }
588
a0b1f42c
JD
589 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
590 epoll_event.data.fd = wait_fd;
591 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
592 if (ret < 0) {
d40c2620 593 PERROR("[epoll_pwait] add");
5305e823 594 goto error;
a0b1f42c
JD
595 }
596
597 ret = syscall(SYS_epoll_pwait, epollfd,
598 (struct epoll_event *) invalid, 1, -1, NULL);
599
600 if (ret == 1) {
a0b1f42c
JD
601 ret = read(wait_fd, buf, BUF_SIZE);
602 if (ret < 0) {
d40c2620 603 PERROR("[epoll_pwait] read");
a0b1f42c 604 }
d40c2620
JG
605 } else if (ret != 0) {
606 /* Expected error. */
a0b1f42c
JD
607 }
608
5305e823 609error:
6d52f14d
FD
610 ret = close(epollfd);
611 if (ret) {
d40c2620 612 PERROR("close");
6d52f14d 613 }
a0b1f42c
JD
614end:
615 return;
616}
617
618/*
619 * Set maxevents to INT_MAX, should output "Invalid argument"
620 * The event should return an empty array.
621 */
f12eb9c1 622static
d40c2620 623void epoll_pwait_int_max(FILE *validation_output_file)
a0b1f42c
JD
624{
625 int ret, epollfd;
626 char buf[BUF_SIZE];
627 struct epoll_event epoll_event;
628
629 epollfd = epoll_create(NB_FD);
630 if (epollfd < 0) {
d40c2620 631 PERROR("[epoll_pwait] create");
a0b1f42c
JD
632 goto end;
633 }
634
d40c2620
JG
635 ret = fprintf(validation_output_file,
636 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
637 getpid());
638 if (ret < 0) {
639 PERROR("[epoll_pwait] Failed to write test validation output");
640 goto error;
641 }
642
a0b1f42c
JD
643 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
644 epoll_event.data.fd = wait_fd;
645 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
646 if (ret < 0) {
d40c2620 647 PERROR("[epoll_pwait] add");
5305e823 648 goto error;
a0b1f42c
JD
649 }
650
651 ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1,
652 NULL);
653
654 if (ret == 1) {
a0b1f42c
JD
655 ret = read(wait_fd, buf, BUF_SIZE);
656 if (ret < 0) {
d40c2620 657 PERROR("[epoll_pwait] read");
a0b1f42c 658 }
d40c2620
JG
659 } else if (ret != 0) {
660 /* Expected error. */
a0b1f42c
JD
661 }
662
5305e823 663error:
6d52f14d
FD
664 ret = close(epollfd);
665 if (ret) {
d40c2620 666 PERROR("close");
6d52f14d 667 }
a0b1f42c
JD
668end:
669 return;
670}
671
f12eb9c1 672static
a0b1f42c
JD
673void *ppoll_writer(void *arg)
674{
675 struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg;
676
677 while (!stop_thread) {
678 memset(data->ufds, data->value,
679 MAX_FDS * sizeof(struct pollfd));
680 usleep(100);
681 }
682
683 return NULL;
684}
685
f12eb9c1 686static
a0b1f42c
JD
687void do_ppoll(int *fds, struct pollfd *ufds)
688{
689 int i, ret;
690 struct timespec ts;
691 char buf[BUF_SIZE];
692
693 ts.tv_sec = 0;
694 ts.tv_nsec = 1 * MSEC_PER_NSEC;
695
696 for (i = 0; i < MAX_FDS; i++) {
697 ufds[i].fd = fds[i];
698 ufds[i].events = POLLIN|POLLPRI;
699 }
700
701 ret = ppoll(ufds, MAX_FDS, &ts, NULL);
702
703 if (ret < 0) {
d40c2620 704 PERROR("ppoll");
a0b1f42c 705 } else if (ret > 0) {
a0b1f42c
JD
706 ret = read(wait_fd, buf, BUF_SIZE);
707 if (ret < 0) {
d40c2620 708 PERROR("[ppoll] read");
a0b1f42c 709 }
a0b1f42c
JD
710 }
711}
712
f12eb9c1 713static
a0b1f42c
JD
714void stress_ppoll(int *fds, int value)
715{
716 pthread_t writer;
717 int iter, ret;
718 struct ppoll_thread_data thread_data;
719 struct pollfd ufds[MAX_FDS];
720
721 thread_data.ufds = ufds;
722 thread_data.value = value;
723
724 stop_thread = 0;
725 ret = pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data);
726 if (ret != 0) {
727 fprintf(stderr, "[error] pthread_create\n");
728 goto end;
729 }
730 for (iter = 0; iter < NR_ITER; iter++) {
731 do_ppoll(fds, ufds);
732 }
733 stop_thread = 1;
9d558571
JG
734 ret = pthread_join(writer, NULL);
735 if (ret) {
736 fprintf(stderr, "[error] pthread_join\n");
737 goto end;
738 }
a0b1f42c
JD
739end:
740 return;
741}
742
743/*
744 * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
745 * structure:
746 * - memset to 0
747 * - memset to 1
748 * - memset to INT_MAX
749 * Waits for input, but also set a timeout in case the input FD is overwritten
750 * before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the
751 * resulting trace is big (20MB).
752 *
753 * ppoll should work as expected and the trace should be readable at the end.
754 */
f12eb9c1 755static
d40c2620 756void ppoll_concurrent_write(FILE *validation_output_file)
a0b1f42c
JD
757{
758 int i, ret, fds[MAX_FDS];
759
760 for (i = 0; i < MAX_FDS; i++) {
761 fds[i] = dup(wait_fd);
762 if (fds[i] < 0) {
d40c2620 763 PERROR("dup");
a0b1f42c
JD
764 }
765 }
766
767 stress_ppoll(fds, 0);
768 stress_ppoll(fds, 1);
769 stress_ppoll(fds, INT_MAX);
770
771 for (i = 0; i < MAX_FDS; i++) {
772 ret = close(fds[i]);
773 if (ret != 0) {
d40c2620 774 PERROR("close");
a0b1f42c
JD
775 }
776 }
777
778 return;
779}
780
f12eb9c1 781static
a0b1f42c
JD
782void *epoll_pwait_writer(void *addr)
783{
784 srand(time(NULL));
785
786 while (!stop_thread) {
787 usleep(rand() % 30);
788 munmap(addr, MAX_FDS * sizeof(struct epoll_event));
789 }
790
791 return NULL;
792}
793
794/*
795 * epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the
796 * buffer allocated for the returned data. This should randomly segfault.
797 * The trace should be readable and no kernel OOPS should occur.
798 */
f12eb9c1 799static
d40c2620 800void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
a0b1f42c
JD
801{
802 int ret, epollfd, i, fds[MAX_FDS];
803 char buf[BUF_SIZE];
804 struct epoll_event *epoll_event;
a0b1f42c
JD
805 pthread_t writer;
806
7f6288c8
JG
807 for (i = 0; i < MAX_FDS; i++) {
808 fds[i] = -1;
809 }
a0b1f42c
JD
810 epollfd = epoll_create(MAX_FDS);
811 if (epollfd < 0) {
d40c2620 812 PERROR("[epoll_pwait] create");
a0b1f42c
JD
813 goto end;
814 }
815
d40c2620
JG
816 ret = fprintf(validation_output_file,
817 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
818 getpid());
819 if (ret < 0) {
820 PERROR("[epoll_pwait] Failed to write test validation output");
821 goto error;
822 }
823
824 epoll_event = (struct epoll_event *) mmap(NULL,
825 MAX_FDS * sizeof(struct epoll_event),
826 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1,
827 0);
a0b1f42c 828 if (epoll_event == MAP_FAILED) {
d40c2620 829 PERROR("mmap");
5305e823 830 goto error;
a0b1f42c
JD
831 }
832
833 for (i = 0; i < MAX_FDS; i++) {
834 fds[i] = dup(wait_fd);
835 if (fds[i] < 0) {
d40c2620 836 PERROR("dup");
a0b1f42c
JD
837 }
838 epoll_event[i].events = EPOLLIN | EPOLLPRI | EPOLLET;
839 epoll_event[i].data.fd = fds[i];
840 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], epoll_event);
841 if (ret < 0) {
d40c2620 842 PERROR("[epoll_pwait] add");
5305e823 843 goto error_unmap;
a0b1f42c
JD
844 }
845 }
846 stop_thread = 0;
d542c0ae
JG
847 ret = pthread_create(&writer, NULL, &epoll_pwait_writer,
848 (void *) epoll_event);
849 if (ret != 0) {
850 fprintf(stderr, "[error] pthread_create\n");
5305e823 851 goto error_unmap;
d542c0ae 852 }
a0b1f42c
JD
853
854 ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL);
855
856 if (ret == 1) {
a0b1f42c
JD
857 ret = read(wait_fd, buf, BUF_SIZE);
858 if (ret < 0) {
d40c2620 859 PERROR("[epoll_pwait] read");
a0b1f42c 860 }
d40c2620
JG
861 } else if (ret != 0) {
862 /* Expected error. */
a0b1f42c
JD
863 }
864
865 stop_thread = 1;
9d558571
JG
866 ret = pthread_join(writer, NULL);
867 if (ret) {
868 fprintf(stderr, "[error] pthread_join\n");
5305e823 869 goto error_unmap;
9d558571 870 }
5305e823 871error_unmap:
a0b1f42c
JD
872 for (i = 0; i < MAX_FDS; i++) {
873 ret = close(fds[i]);
874 if (ret != 0) {
d40c2620 875 PERROR("close");
a0b1f42c
JD
876 }
877 }
878
36bc42d9 879 ret = munmap(epoll_event, MAX_FDS * sizeof(struct epoll_event));
a0b1f42c 880 if (ret != 0) {
d40c2620 881 PERROR("munmap");
a0b1f42c
JD
882 }
883
5305e823 884error:
6d52f14d
FD
885 ret = close(epollfd);
886 if (ret) {
d40c2620 887 PERROR("close");
6d52f14d 888 }
a0b1f42c
JD
889end:
890 return;
891}
892
f12eb9c1 893static
a0b1f42c
JD
894void print_list(void)
895{
896 fprintf(stderr, "Test list (-t X):\n");
897 fprintf(stderr, "\t1: Working cases for select, pselect6, poll, ppoll "
898 "and epoll, waiting for input\n");
899 fprintf(stderr, "\t2: Timeout cases (1ms) for select, pselect6, poll, "
900 "ppoll and epoll\n");
8b3b99e2 901 fprintf(stderr, "\t3: pselect with an invalid fd\n");
a0b1f42c
JD
902 fprintf(stderr, "\t4: ppoll with %d FDs\n", MAX_FDS);
903 fprintf(stderr, "\t5: ppoll buffer overflow, should segfault, waits "
904 "for input\n");
8b3b99e2 905 fprintf(stderr, "\t6: pselect with an invalid pointer, waits for "
a0b1f42c
JD
906 "input\n");
907 fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n");
8b3b99e2 908 fprintf(stderr, "\t8: epoll_pwait with an invalid pointer, waits for "
a0b1f42c
JD
909 "input\n");
910 fprintf(stderr, "\t9: epoll_pwait with maxevents set to INT_MAX, "
911 "waits for input\n");
912 fprintf(stderr, "\t10: ppoll with concurrent updates of the structure "
913 "from user-space, stress test (3000 iterations), "
914 "waits for input + timeout 1ms\n");
915 fprintf(stderr, "\t11: epoll_pwait with concurrent munmap of the buffer "
916 "from user-space, should randomly segfault, run "
917 "multiple times, waits for input + timeout 1ms\n");
918}
919
920int main(int argc, const char **argv)
921{
922 int c, ret, test = -1;
923 poptContext optCon;
924 struct rlimit open_lim;
d40c2620
JG
925 FILE *test_validation_output_file = NULL;
926 const char *test_validation_output_file_path = NULL;
a0b1f42c
JD
927 struct poptOption optionsTable[] = {
928 { "test", 't', POPT_ARG_INT, &test, 0,
929 "Test to run", NULL },
930 { "list", 'l', 0, 0, 'l',
931 "List of tests (-t X)", NULL },
d40c2620
JG
932 { "validation-file", 'o', POPT_ARG_STRING, &test_validation_output_file_path, 0,
933 "Test case output", NULL },
a0b1f42c
JD
934 POPT_AUTOHELP
935 { NULL, 0, 0, NULL, 0 }
936 };
d40c2620 937 const struct test_case *test_case;
a0b1f42c
JD
938
939 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
940
941 if (argc < 2) {
942 poptPrintUsage(optCon, stderr, 0);
943 ret = -1;
944 goto end;
945 }
946
947 ret = 0;
948
949 while ((c = poptGetNextOpt(optCon)) >= 0) {
d40c2620 950 switch (c) {
a0b1f42c
JD
951 case 'l':
952 print_list();
953 goto end;
954 }
955 }
956
d40c2620
JG
957 if (!test_validation_output_file_path) {
958 fprintf(stderr, "A test validation file path is required (--validation-file/-o)\n");
959 ret = -1;
960 goto end;
961 }
962
963 test_validation_output_file = fopen(test_validation_output_file_path, "w+");
964 if (!test_validation_output_file) {
965 PERROR("Failed to create test validation output file at '%s'",
966 test_validation_output_file_path);
967 ret = -1;
968 goto end;
969 }
970
a0b1f42c
JD
971 open_lim.rlim_cur = MAX_FDS + MIN_NR_FDS;
972 open_lim.rlim_max = MAX_FDS + MIN_NR_FDS;
973
974 ret = setrlimit(RLIMIT_NOFILE, &open_lim);
975 if (ret < 0) {
d40c2620 976 PERROR("setrlimit");
a0b1f42c
JD
977 goto end;
978 }
979
980 /*
981 * Some tests might segfault, but we need the getpid() to be output
d40c2620
JG
982 * for the validation, disabling the buffering on the validation file
983 * works.
a0b1f42c 984 */
d40c2620 985 setbuf(test_validation_output_file, NULL);
a0b1f42c
JD
986 wait_fd = STDIN_FILENO;
987
d40c2620
JG
988 /* Test case id is 1-based. */
989 if (test < 1 || test > ARRAY_SIZE(test_cases)) {
a0b1f42c
JD
990 poptPrintUsage(optCon, stderr, 0);
991 ret = -1;
a0b1f42c
JD
992 }
993
d40c2620
JG
994 test_case = &test_cases[test - 1];
995
996 timeout = test_case->timeout;
997 if (!test_case->produces_validation_info) {
998 /*
999 * All test cases need to provide, at minimum, the pid of the
1000 * test application.
1001 */
1002 ret = fprintf(test_validation_output_file, "{ \"pid\": %i }", getpid());
1003 if (ret < 0) {
1004 PERROR("Failed to write application pid to test validation file");
1005 goto end;
1006 }
1007 }
1008
1009 test_case->run(test_validation_output_file);
1010
a0b1f42c 1011end:
d40c2620
JG
1012 if (test_validation_output_file) {
1013 const int close_ret = fclose(test_validation_output_file);
1014
1015 if (close_ret) {
1016 PERROR("Failed to close test output file");
1017 }
1018 }
a0b1f42c
JD
1019 poptFreeContext(optCon);
1020 return ret;
1021}
This page took 0.082484 seconds and 4 git commands to generate.