Prepare for '-Wmissing-field-initializers'
[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 },
1c9a0b0e
MJ
69 { .run = pselect_invalid_fd, .produces_validation_info = false, .timeout = 0 },
70 { .run = test_ppoll_big, .produces_validation_info = false, .timeout = 0 },
71 { .run = ppoll_fds_buffer_overflow, .produces_validation_info = false, .timeout = 0 },
72 { .run = pselect_invalid_pointer, .produces_validation_info = false, .timeout = 0 },
73 { .run = ppoll_fds_ulong_max, .produces_validation_info = false, .timeout = 0 },
74 { .run = epoll_pwait_invalid_pointer, .produces_validation_info = true, .timeout = 0 },
75 { .run = epoll_pwait_int_max, .produces_validation_info = true, .timeout = 0 },
76 { .run = ppoll_concurrent_write, .produces_validation_info = false, .timeout = 0 },
77 { .run = epoll_pwait_concurrent_munmap, .produces_validation_info = true, .timeout = 0 },
d40c2620
JG
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
f46376a1 245void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
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
f46376a1
MJ
446void ppoll_fds_buffer_overflow(
447 FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
448{
449 struct pollfd ufds[NB_FD];
450 char buf[BUF_SIZE];
451 int ret;
452
453 ufds[0].fd = wait_fd;
454 ufds[0].events = POLLIN|POLLPRI;
455
456 ret = syscall(SYS_ppoll, ufds, 100, NULL, NULL);
457
458 if (ret < 0) {
d40c2620 459 PERROR("ppoll");
a0b1f42c 460 } else if (ret > 0) {
a0b1f42c
JD
461 ret = read(wait_fd, buf, BUF_SIZE);
462 if (ret < 0) {
d40c2620 463 PERROR("[ppoll] read");
a0b1f42c 464 }
a0b1f42c 465 }
a0b1f42c
JD
466}
467
468/*
469 * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
470 * cleanly fail with a "Invalid argument".
471 * The event should contain an empty array of FDs and overflow = 1.
472 */
f12eb9c1 473static
f46376a1 474void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
475{
476 struct pollfd ufds[NB_FD];
477 char buf[BUF_SIZE];
478 int ret;
479
480 ufds[0].fd = wait_fd;
481 ufds[0].events = POLLIN|POLLPRI;
482
483 ret = syscall(SYS_ppoll, ufds, ULONG_MAX, NULL, NULL);
a0b1f42c 484 if (ret < 0) {
d40c2620 485 /* Expected error. */
a0b1f42c 486 } else if (ret > 0) {
a0b1f42c
JD
487 ret = read(wait_fd, buf, BUF_SIZE);
488 if (ret < 0) {
d40c2620 489 PERROR("[ppoll] read");
a0b1f42c 490 }
a0b1f42c 491 }
a0b1f42c
JD
492}
493
494/*
8b3b99e2
FD
495 * Pass an invalid file descriptor to pselect6(). The syscall should return
496 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
a0b1f42c 497 */
f12eb9c1 498static
f46376a1 499void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
a0b1f42c 500{
8b3b99e2 501 fd_set rfds;
a0b1f42c 502 int ret;
8b3b99e2 503 int fd;
a0b1f42c
JD
504 char buf[BUF_SIZE];
505
506 /*
8b3b99e2 507 * Open a file, close it and use the closed FD in the pselect6 call.
a0b1f42c 508 */
8b3b99e2
FD
509 fd = open("/dev/null", O_RDONLY);
510 if (fd == -1) {
d40c2620 511 PERROR("open");
8b3b99e2
FD
512 goto error;
513 }
514
515 ret = close(fd);
516 if (ret == -1) {
d40c2620 517 PERROR("close");
8b3b99e2 518 goto error;
a0b1f42c 519 }
e593ee02 520
8b3b99e2
FD
521 FD_ZERO(&rfds);
522 FD_SET(fd, &rfds);
a0b1f42c 523
8b3b99e2 524 ret = syscall(SYS_pselect6, fd + 1, &rfds, NULL, NULL, NULL, NULL);
a0b1f42c 525 if (ret == -1) {
d40c2620 526 /* Expected error. */
a0b1f42c 527 } else if (ret) {
a0b1f42c
JD
528 ret = read(wait_fd, buf, BUF_SIZE);
529 if (ret < 0) {
d40c2620 530 PERROR("[pselect] read");
a0b1f42c 531 }
a0b1f42c 532 }
8b3b99e2
FD
533error:
534 return;
a0b1f42c
JD
535}
536
537/*
538 * Invalid pointer as writefds, should output a ppoll event
539 * with 0 FDs.
540 */
f12eb9c1 541static
f46376a1
MJ
542void pselect_invalid_pointer(
543 FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
544{
545 fd_set rfds;
546 int ret;
547 char buf[BUF_SIZE];
548 void *invalid = (void *) 0x42;
549
550 FD_ZERO(&rfds);
551 FD_SET(wait_fd, &rfds);
552
553 ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL,
554 NULL);
a0b1f42c 555 if (ret == -1) {
d40c2620 556 /* Expected error. */
a0b1f42c 557 } else if (ret) {
a0b1f42c
JD
558 ret = read(wait_fd, buf, BUF_SIZE);
559 if (ret < 0) {
d40c2620 560 PERROR("[pselect] read");
a0b1f42c 561 }
a0b1f42c 562 }
a0b1f42c
JD
563}
564
565/*
566 * Pass an invalid pointer to epoll_pwait, should fail with
567 * "Bad address", the event returns 0 FDs.
568 */
f12eb9c1 569static
d40c2620 570void epoll_pwait_invalid_pointer(FILE *validation_output_file)
a0b1f42c
JD
571{
572 int ret, epollfd;
573 char buf[BUF_SIZE];
574 struct epoll_event epoll_event;
575 void *invalid = (void *) 0x42;
576
577 epollfd = epoll_create(NB_FD);
578 if (epollfd < 0) {
d40c2620 579 PERROR("[epoll_pwait] create");
a0b1f42c
JD
580 goto end;
581 }
582
d40c2620
JG
583 ret = fprintf(validation_output_file,
584 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
585 getpid());
586 if (ret < 0) {
587 PERROR("[epoll_pwait] Failed to write test validation output");
588 goto error;
589 }
590
a0b1f42c
JD
591 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
592 epoll_event.data.fd = wait_fd;
593 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
594 if (ret < 0) {
d40c2620 595 PERROR("[epoll_pwait] add");
5305e823 596 goto error;
a0b1f42c
JD
597 }
598
599 ret = syscall(SYS_epoll_pwait, epollfd,
600 (struct epoll_event *) invalid, 1, -1, NULL);
601
602 if (ret == 1) {
a0b1f42c
JD
603 ret = read(wait_fd, buf, BUF_SIZE);
604 if (ret < 0) {
d40c2620 605 PERROR("[epoll_pwait] read");
a0b1f42c 606 }
d40c2620
JG
607 } else if (ret != 0) {
608 /* Expected error. */
a0b1f42c
JD
609 }
610
5305e823 611error:
6d52f14d
FD
612 ret = close(epollfd);
613 if (ret) {
d40c2620 614 PERROR("close");
6d52f14d 615 }
a0b1f42c
JD
616end:
617 return;
618}
619
620/*
621 * Set maxevents to INT_MAX, should output "Invalid argument"
622 * The event should return an empty array.
623 */
f12eb9c1 624static
d40c2620 625void epoll_pwait_int_max(FILE *validation_output_file)
a0b1f42c
JD
626{
627 int ret, epollfd;
628 char buf[BUF_SIZE];
629 struct epoll_event epoll_event;
630
631 epollfd = epoll_create(NB_FD);
632 if (epollfd < 0) {
d40c2620 633 PERROR("[epoll_pwait] create");
a0b1f42c
JD
634 goto end;
635 }
636
d40c2620
JG
637 ret = fprintf(validation_output_file,
638 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
639 getpid());
640 if (ret < 0) {
641 PERROR("[epoll_pwait] Failed to write test validation output");
642 goto error;
643 }
644
a0b1f42c
JD
645 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
646 epoll_event.data.fd = wait_fd;
647 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
648 if (ret < 0) {
d40c2620 649 PERROR("[epoll_pwait] add");
5305e823 650 goto error;
a0b1f42c
JD
651 }
652
653 ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1,
654 NULL);
655
656 if (ret == 1) {
a0b1f42c
JD
657 ret = read(wait_fd, buf, BUF_SIZE);
658 if (ret < 0) {
d40c2620 659 PERROR("[epoll_pwait] read");
a0b1f42c 660 }
d40c2620
JG
661 } else if (ret != 0) {
662 /* Expected error. */
a0b1f42c
JD
663 }
664
5305e823 665error:
6d52f14d
FD
666 ret = close(epollfd);
667 if (ret) {
d40c2620 668 PERROR("close");
6d52f14d 669 }
a0b1f42c
JD
670end:
671 return;
672}
673
f12eb9c1 674static
a0b1f42c
JD
675void *ppoll_writer(void *arg)
676{
677 struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg;
678
679 while (!stop_thread) {
680 memset(data->ufds, data->value,
681 MAX_FDS * sizeof(struct pollfd));
682 usleep(100);
683 }
684
685 return NULL;
686}
687
f12eb9c1 688static
a0b1f42c
JD
689void do_ppoll(int *fds, struct pollfd *ufds)
690{
691 int i, ret;
692 struct timespec ts;
693 char buf[BUF_SIZE];
694
695 ts.tv_sec = 0;
696 ts.tv_nsec = 1 * MSEC_PER_NSEC;
697
698 for (i = 0; i < MAX_FDS; i++) {
699 ufds[i].fd = fds[i];
700 ufds[i].events = POLLIN|POLLPRI;
701 }
702
703 ret = ppoll(ufds, MAX_FDS, &ts, NULL);
704
705 if (ret < 0) {
d40c2620 706 PERROR("ppoll");
a0b1f42c 707 } else if (ret > 0) {
a0b1f42c
JD
708 ret = read(wait_fd, buf, BUF_SIZE);
709 if (ret < 0) {
d40c2620 710 PERROR("[ppoll] read");
a0b1f42c 711 }
a0b1f42c
JD
712 }
713}
714
f12eb9c1 715static
a0b1f42c
JD
716void stress_ppoll(int *fds, int value)
717{
718 pthread_t writer;
719 int iter, ret;
720 struct ppoll_thread_data thread_data;
721 struct pollfd ufds[MAX_FDS];
722
723 thread_data.ufds = ufds;
724 thread_data.value = value;
725
726 stop_thread = 0;
727 ret = pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data);
728 if (ret != 0) {
729 fprintf(stderr, "[error] pthread_create\n");
730 goto end;
731 }
732 for (iter = 0; iter < NR_ITER; iter++) {
733 do_ppoll(fds, ufds);
734 }
735 stop_thread = 1;
9d558571
JG
736 ret = pthread_join(writer, NULL);
737 if (ret) {
738 fprintf(stderr, "[error] pthread_join\n");
739 goto end;
740 }
a0b1f42c
JD
741end:
742 return;
743}
744
745/*
746 * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
747 * structure:
748 * - memset to 0
749 * - memset to 1
750 * - memset to INT_MAX
751 * Waits for input, but also set a timeout in case the input FD is overwritten
752 * before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the
753 * resulting trace is big (20MB).
754 *
755 * ppoll should work as expected and the trace should be readable at the end.
756 */
f12eb9c1 757static
f46376a1
MJ
758void ppoll_concurrent_write(
759 FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
760{
761 int i, ret, fds[MAX_FDS];
762
763 for (i = 0; i < MAX_FDS; i++) {
764 fds[i] = dup(wait_fd);
765 if (fds[i] < 0) {
d40c2620 766 PERROR("dup");
a0b1f42c
JD
767 }
768 }
769
770 stress_ppoll(fds, 0);
771 stress_ppoll(fds, 1);
772 stress_ppoll(fds, INT_MAX);
773
774 for (i = 0; i < MAX_FDS; i++) {
775 ret = close(fds[i]);
776 if (ret != 0) {
d40c2620 777 PERROR("close");
a0b1f42c
JD
778 }
779 }
780
781 return;
782}
783
f12eb9c1 784static
a0b1f42c
JD
785void *epoll_pwait_writer(void *addr)
786{
787 srand(time(NULL));
788
789 while (!stop_thread) {
790 usleep(rand() % 30);
791 munmap(addr, MAX_FDS * sizeof(struct epoll_event));
792 }
793
794 return NULL;
795}
796
797/*
798 * epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the
799 * buffer allocated for the returned data. This should randomly segfault.
800 * The trace should be readable and no kernel OOPS should occur.
801 */
f12eb9c1 802static
d40c2620 803void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
a0b1f42c
JD
804{
805 int ret, epollfd, i, fds[MAX_FDS];
806 char buf[BUF_SIZE];
807 struct epoll_event *epoll_event;
a0b1f42c
JD
808 pthread_t writer;
809
7f6288c8
JG
810 for (i = 0; i < MAX_FDS; i++) {
811 fds[i] = -1;
812 }
a0b1f42c
JD
813 epollfd = epoll_create(MAX_FDS);
814 if (epollfd < 0) {
d40c2620 815 PERROR("[epoll_pwait] create");
a0b1f42c
JD
816 goto end;
817 }
818
d40c2620
JG
819 ret = fprintf(validation_output_file,
820 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
821 getpid());
822 if (ret < 0) {
823 PERROR("[epoll_pwait] Failed to write test validation output");
824 goto error;
825 }
826
827 epoll_event = (struct epoll_event *) mmap(NULL,
828 MAX_FDS * sizeof(struct epoll_event),
829 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1,
830 0);
a0b1f42c 831 if (epoll_event == MAP_FAILED) {
d40c2620 832 PERROR("mmap");
5305e823 833 goto error;
a0b1f42c
JD
834 }
835
836 for (i = 0; i < MAX_FDS; i++) {
837 fds[i] = dup(wait_fd);
838 if (fds[i] < 0) {
d40c2620 839 PERROR("dup");
a0b1f42c
JD
840 }
841 epoll_event[i].events = EPOLLIN | EPOLLPRI | EPOLLET;
842 epoll_event[i].data.fd = fds[i];
843 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], epoll_event);
844 if (ret < 0) {
d40c2620 845 PERROR("[epoll_pwait] add");
5305e823 846 goto error_unmap;
a0b1f42c
JD
847 }
848 }
849 stop_thread = 0;
d542c0ae
JG
850 ret = pthread_create(&writer, NULL, &epoll_pwait_writer,
851 (void *) epoll_event);
852 if (ret != 0) {
853 fprintf(stderr, "[error] pthread_create\n");
5305e823 854 goto error_unmap;
d542c0ae 855 }
a0b1f42c
JD
856
857 ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL);
858
859 if (ret == 1) {
a0b1f42c
JD
860 ret = read(wait_fd, buf, BUF_SIZE);
861 if (ret < 0) {
d40c2620 862 PERROR("[epoll_pwait] read");
a0b1f42c 863 }
d40c2620
JG
864 } else if (ret != 0) {
865 /* Expected error. */
a0b1f42c
JD
866 }
867
868 stop_thread = 1;
9d558571
JG
869 ret = pthread_join(writer, NULL);
870 if (ret) {
871 fprintf(stderr, "[error] pthread_join\n");
5305e823 872 goto error_unmap;
9d558571 873 }
5305e823 874error_unmap:
a0b1f42c
JD
875 for (i = 0; i < MAX_FDS; i++) {
876 ret = close(fds[i]);
877 if (ret != 0) {
d40c2620 878 PERROR("close");
a0b1f42c
JD
879 }
880 }
881
36bc42d9 882 ret = munmap(epoll_event, MAX_FDS * sizeof(struct epoll_event));
a0b1f42c 883 if (ret != 0) {
d40c2620 884 PERROR("munmap");
a0b1f42c
JD
885 }
886
5305e823 887error:
6d52f14d
FD
888 ret = close(epollfd);
889 if (ret) {
d40c2620 890 PERROR("close");
6d52f14d 891 }
a0b1f42c
JD
892end:
893 return;
894}
895
f12eb9c1 896static
a0b1f42c
JD
897void print_list(void)
898{
899 fprintf(stderr, "Test list (-t X):\n");
900 fprintf(stderr, "\t1: Working cases for select, pselect6, poll, ppoll "
901 "and epoll, waiting for input\n");
902 fprintf(stderr, "\t2: Timeout cases (1ms) for select, pselect6, poll, "
903 "ppoll and epoll\n");
8b3b99e2 904 fprintf(stderr, "\t3: pselect with an invalid fd\n");
a0b1f42c
JD
905 fprintf(stderr, "\t4: ppoll with %d FDs\n", MAX_FDS);
906 fprintf(stderr, "\t5: ppoll buffer overflow, should segfault, waits "
907 "for input\n");
8b3b99e2 908 fprintf(stderr, "\t6: pselect with an invalid pointer, waits for "
a0b1f42c
JD
909 "input\n");
910 fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n");
8b3b99e2 911 fprintf(stderr, "\t8: epoll_pwait with an invalid pointer, waits for "
a0b1f42c
JD
912 "input\n");
913 fprintf(stderr, "\t9: epoll_pwait with maxevents set to INT_MAX, "
914 "waits for input\n");
915 fprintf(stderr, "\t10: ppoll with concurrent updates of the structure "
916 "from user-space, stress test (3000 iterations), "
917 "waits for input + timeout 1ms\n");
918 fprintf(stderr, "\t11: epoll_pwait with concurrent munmap of the buffer "
919 "from user-space, should randomly segfault, run "
920 "multiple times, waits for input + timeout 1ms\n");
921}
922
923int main(int argc, const char **argv)
924{
925 int c, ret, test = -1;
926 poptContext optCon;
927 struct rlimit open_lim;
d40c2620
JG
928 FILE *test_validation_output_file = NULL;
929 const char *test_validation_output_file_path = NULL;
a0b1f42c
JD
930 struct poptOption optionsTable[] = {
931 { "test", 't', POPT_ARG_INT, &test, 0,
932 "Test to run", NULL },
933 { "list", 'l', 0, 0, 'l',
934 "List of tests (-t X)", NULL },
d40c2620
JG
935 { "validation-file", 'o', POPT_ARG_STRING, &test_validation_output_file_path, 0,
936 "Test case output", NULL },
a0b1f42c 937 POPT_AUTOHELP
1c9a0b0e 938 { NULL, 0, 0, NULL, 0, NULL, NULL }
a0b1f42c 939 };
d40c2620 940 const struct test_case *test_case;
a0b1f42c
JD
941
942 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
943
944 if (argc < 2) {
945 poptPrintUsage(optCon, stderr, 0);
946 ret = -1;
947 goto end;
948 }
949
950 ret = 0;
951
952 while ((c = poptGetNextOpt(optCon)) >= 0) {
d40c2620 953 switch (c) {
a0b1f42c
JD
954 case 'l':
955 print_list();
956 goto end;
957 }
958 }
959
d40c2620
JG
960 if (!test_validation_output_file_path) {
961 fprintf(stderr, "A test validation file path is required (--validation-file/-o)\n");
962 ret = -1;
963 goto end;
964 }
965
966 test_validation_output_file = fopen(test_validation_output_file_path, "w+");
967 if (!test_validation_output_file) {
968 PERROR("Failed to create test validation output file at '%s'",
969 test_validation_output_file_path);
970 ret = -1;
971 goto end;
972 }
973
a0b1f42c
JD
974 open_lim.rlim_cur = MAX_FDS + MIN_NR_FDS;
975 open_lim.rlim_max = MAX_FDS + MIN_NR_FDS;
976
977 ret = setrlimit(RLIMIT_NOFILE, &open_lim);
978 if (ret < 0) {
d40c2620 979 PERROR("setrlimit");
a0b1f42c
JD
980 goto end;
981 }
982
983 /*
984 * Some tests might segfault, but we need the getpid() to be output
d40c2620
JG
985 * for the validation, disabling the buffering on the validation file
986 * works.
a0b1f42c 987 */
d40c2620 988 setbuf(test_validation_output_file, NULL);
a0b1f42c
JD
989 wait_fd = STDIN_FILENO;
990
d40c2620
JG
991 /* Test case id is 1-based. */
992 if (test < 1 || test > ARRAY_SIZE(test_cases)) {
a0b1f42c
JD
993 poptPrintUsage(optCon, stderr, 0);
994 ret = -1;
a0b1f42c
JD
995 }
996
d40c2620
JG
997 test_case = &test_cases[test - 1];
998
999 timeout = test_case->timeout;
1000 if (!test_case->produces_validation_info) {
1001 /*
1002 * All test cases need to provide, at minimum, the pid of the
1003 * test application.
1004 */
1005 ret = fprintf(test_validation_output_file, "{ \"pid\": %i }", getpid());
1006 if (ret < 0) {
1007 PERROR("Failed to write application pid to test validation file");
1008 goto end;
1009 }
1010 }
1011
1012 test_case->run(test_validation_output_file);
1013
a0b1f42c 1014end:
d40c2620
JG
1015 if (test_validation_output_file) {
1016 const int close_ret = fclose(test_validation_output_file);
1017
1018 if (close_ret) {
1019 PERROR("Failed to close test output file");
1020 }
1021 }
a0b1f42c
JD
1022 poptFreeContext(optCon);
1023 return ret;
1024}
This page took 0.083442 seconds and 4 git commands to generate.