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