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