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