abedc0aa929557c7aa859e76788d71d53e0f0cb4
[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 #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>
27 #include <common/compat/time.h>
28 #include <common/error.h>
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
41 static int timeout; /* seconds, -1 to disable */
42 static volatile int stop_thread;
43 static int wait_fd;
44
45 /* Used by logging utils. */
46 int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi;
47
48 static void run_working_cases(FILE *validation_output_file);
49 static void pselect_invalid_fd(FILE *validation_output_file);
50 static void test_ppoll_big(FILE *validation_output_file);
51 static void ppoll_fds_buffer_overflow(FILE *validation_output_file);
52 static void pselect_invalid_pointer(FILE *validation_output_file);
53 static void ppoll_fds_ulong_max(FILE *validation_output_file);
54 static void epoll_pwait_invalid_pointer(FILE *validation_output_file);
55 static void epoll_pwait_int_max(FILE *validation_output_file);
56 static void ppoll_concurrent_write(FILE *validation_output_file);
57 static void epoll_pwait_concurrent_munmap(FILE *validation_output_file);
58
59 typedef void (*test_case_cb)(FILE *output_file);
60
61 static const struct test_case {
62 test_case_cb run;
63 bool produces_validation_info;
64 int timeout;
65 } test_cases [] =
66 {
67 { .run = run_working_cases, .produces_validation_info = true, .timeout = -1 },
68 { .run = run_working_cases, .produces_validation_info = true, .timeout = 1 },
69 { .run = pselect_invalid_fd, .produces_validation_info = false },
70 { .run = test_ppoll_big, .produces_validation_info = false },
71 { .run = ppoll_fds_buffer_overflow, .produces_validation_info = false },
72 { .run = pselect_invalid_pointer, .produces_validation_info = false },
73 { .run = ppoll_fds_ulong_max, .produces_validation_info = false },
74 { .run = epoll_pwait_invalid_pointer, .produces_validation_info = true },
75 { .run = epoll_pwait_int_max, .produces_validation_info = true },
76 { .run = ppoll_concurrent_write, .produces_validation_info = false },
77 { .run = epoll_pwait_concurrent_munmap, .produces_validation_info = true },
78 };
79
80 struct ppoll_thread_data {
81 struct pollfd *ufds;
82 int value;
83 };
84
85 static
86 void 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) {
100 PERROR("dup2");
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) {
115 PERROR("select()");
116 } else if (ret) {
117 ret = read(wait_fd, buf, BUF_SIZE);
118 if (ret < 0) {
119 PERROR("[select] read");
120 }
121 }
122
123 ret = close(BIG_SELECT_FD);
124 if (ret) {
125 PERROR("close");
126 }
127
128 end:
129 return;
130 }
131
132 static
133 void 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) {
153 PERROR("pselect()");
154 } else if (ret) {
155 ret = read(wait_fd, buf, BUF_SIZE);
156 if (ret < 0) {
157 PERROR("[pselect] read");
158 }
159 }
160 }
161
162 static
163 void 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) {
183 PERROR("select()");
184 } else if (ret) {
185 ret = read(wait_fd, buf, BUF_SIZE);
186 if (ret < 0) {
187 PERROR("[select] read");
188 }
189 }
190 }
191
192 static
193 void 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) {
205 PERROR("poll");
206 } else if (ret > 0) {
207 ret = read(wait_fd, buf, BUF_SIZE);
208 if (ret < 0) {
209 PERROR("[poll] read");
210 }
211 }
212 }
213
214 static
215 void 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) {
235 PERROR("ppoll");
236 } else if (ret > 0) {
237 ret = read(wait_fd, buf, BUF_SIZE);
238 if (ret < 0) {
239 PERROR("[ppoll] read");
240 }
241 }
242 }
243
244 static
245 void test_ppoll_big(FILE *validation_output_file)
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) {
254 PERROR("dup");
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) {
263 PERROR("ppoll");
264 } else if (ret > 0) {
265 ret = read(wait_fd, buf, BUF_SIZE);
266 if (ret < 0) {
267 PERROR("[ppoll] read");
268 }
269 }
270
271 for (i = 0; i < MAX_FDS; i++) {
272 ret = close(fds[i]);
273 if (ret != 0) {
274 PERROR("close");
275 }
276 }
277
278 return;
279 }
280
281 static
282 void test_epoll(FILE *validation_output_file)
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) {
290 PERROR("[epoll] create");
291 goto end;
292 }
293
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
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) {
305 PERROR("[epoll] add");
306 goto error;
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) {
316 ret = read(wait_fd, buf, BUF_SIZE);
317 if (ret < 0) {
318 PERROR("[epoll] read");
319 }
320 } else if (ret != 0) {
321 PERROR("epoll_wait");
322 }
323
324 error:
325 ret = close(epollfd);
326 if (ret) {
327 PERROR("close");
328 }
329 end:
330 return;
331 }
332
333 static
334 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,
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
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) {
357 PERROR("[epoll_pwait] add");
358 goto error;
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) {
368 ret = read(wait_fd, buf, BUF_SIZE);
369 if (ret < 0) {
370 PERROR("[epoll_pwait] read");
371 }
372 } else if (ret != 0) {
373 PERROR("epoll_pwait");
374 }
375
376 error:
377 ret = close(epollfd);
378 if (ret) {
379 PERROR("close");
380 }
381 end:
382 return;
383 }
384
385 static
386 void run_working_cases(FILE *validation_output_file)
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) {
399 PERROR("pipe");
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();
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);
418
419 if (timeout > 0) {
420 ret = close(pipe_fds[0]);
421 if (ret) {
422 PERROR("close");
423 }
424 ret = close(pipe_fds[1]);
425 if (ret) {
426 PERROR("close");
427 }
428 }
429
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
436 end:
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 */
445 static
446 void ppoll_fds_buffer_overflow(FILE *validation_output_file)
447 {
448 struct pollfd ufds[NB_FD];
449 char buf[BUF_SIZE];
450 int ret;
451
452 ufds[0].fd = wait_fd;
453 ufds[0].events = POLLIN|POLLPRI;
454
455 ret = syscall(SYS_ppoll, ufds, 100, NULL, NULL);
456
457 if (ret < 0) {
458 PERROR("ppoll");
459 } else if (ret > 0) {
460 ret = read(wait_fd, buf, BUF_SIZE);
461 if (ret < 0) {
462 PERROR("[ppoll] read");
463 }
464 }
465 }
466
467 /*
468 * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
469 * cleanly fail with a "Invalid argument".
470 * The event should contain an empty array of FDs and overflow = 1.
471 */
472 static
473 void ppoll_fds_ulong_max(FILE *validation_output_file)
474 {
475 struct pollfd ufds[NB_FD];
476 char buf[BUF_SIZE];
477 int ret;
478
479 ufds[0].fd = wait_fd;
480 ufds[0].events = POLLIN|POLLPRI;
481
482 ret = syscall(SYS_ppoll, ufds, ULONG_MAX, NULL, NULL);
483 if (ret < 0) {
484 /* Expected error. */
485 } else if (ret > 0) {
486 ret = read(wait_fd, buf, BUF_SIZE);
487 if (ret < 0) {
488 PERROR("[ppoll] read");
489 }
490 }
491 }
492
493 /*
494 * Pass an invalid file descriptor to pselect6(). The syscall should return
495 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
496 */
497 static
498 void pselect_invalid_fd(FILE *validation_output_file)
499 {
500 fd_set rfds;
501 int ret;
502 int fd;
503 char buf[BUF_SIZE];
504
505 /*
506 * Open a file, close it and use the closed FD in the pselect6 call.
507 */
508 fd = open("/dev/null", O_RDONLY);
509 if (fd == -1) {
510 PERROR("open");
511 goto error;
512 }
513
514 ret = close(fd);
515 if (ret == -1) {
516 PERROR("close");
517 goto error;
518 }
519
520 FD_ZERO(&rfds);
521 FD_SET(fd, &rfds);
522
523 ret = syscall(SYS_pselect6, fd + 1, &rfds, NULL, NULL, NULL, NULL);
524 if (ret == -1) {
525 /* Expected error. */
526 } else if (ret) {
527 ret = read(wait_fd, buf, BUF_SIZE);
528 if (ret < 0) {
529 PERROR("[pselect] read");
530 }
531 }
532 error:
533 return;
534 }
535
536 /*
537 * Invalid pointer as writefds, should output a ppoll event
538 * with 0 FDs.
539 */
540 static
541 void pselect_invalid_pointer(FILE *validation_output_file)
542 {
543 fd_set rfds;
544 int ret;
545 char buf[BUF_SIZE];
546 void *invalid = (void *) 0x42;
547
548 FD_ZERO(&rfds);
549 FD_SET(wait_fd, &rfds);
550
551 ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL,
552 NULL);
553 if (ret == -1) {
554 /* Expected error. */
555 } else if (ret) {
556 ret = read(wait_fd, buf, BUF_SIZE);
557 if (ret < 0) {
558 PERROR("[pselect] read");
559 }
560 }
561 }
562
563 /*
564 * Pass an invalid pointer to epoll_pwait, should fail with
565 * "Bad address", the event returns 0 FDs.
566 */
567 static
568 void epoll_pwait_invalid_pointer(FILE *validation_output_file)
569 {
570 int ret, epollfd;
571 char buf[BUF_SIZE];
572 struct epoll_event epoll_event;
573 void *invalid = (void *) 0x42;
574
575 epollfd = epoll_create(NB_FD);
576 if (epollfd < 0) {
577 PERROR("[epoll_pwait] create");
578 goto end;
579 }
580
581 ret = fprintf(validation_output_file,
582 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
583 getpid());
584 if (ret < 0) {
585 PERROR("[epoll_pwait] Failed to write test validation output");
586 goto error;
587 }
588
589 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
590 epoll_event.data.fd = wait_fd;
591 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
592 if (ret < 0) {
593 PERROR("[epoll_pwait] add");
594 goto error;
595 }
596
597 ret = syscall(SYS_epoll_pwait, epollfd,
598 (struct epoll_event *) invalid, 1, -1, NULL);
599
600 if (ret == 1) {
601 ret = read(wait_fd, buf, BUF_SIZE);
602 if (ret < 0) {
603 PERROR("[epoll_pwait] read");
604 }
605 } else if (ret != 0) {
606 /* Expected error. */
607 }
608
609 error:
610 ret = close(epollfd);
611 if (ret) {
612 PERROR("close");
613 }
614 end:
615 return;
616 }
617
618 /*
619 * Set maxevents to INT_MAX, should output "Invalid argument"
620 * The event should return an empty array.
621 */
622 static
623 void epoll_pwait_int_max(FILE *validation_output_file)
624 {
625 int ret, epollfd;
626 char buf[BUF_SIZE];
627 struct epoll_event epoll_event;
628
629 epollfd = epoll_create(NB_FD);
630 if (epollfd < 0) {
631 PERROR("[epoll_pwait] create");
632 goto end;
633 }
634
635 ret = fprintf(validation_output_file,
636 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
637 getpid());
638 if (ret < 0) {
639 PERROR("[epoll_pwait] Failed to write test validation output");
640 goto error;
641 }
642
643 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
644 epoll_event.data.fd = wait_fd;
645 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
646 if (ret < 0) {
647 PERROR("[epoll_pwait] add");
648 goto error;
649 }
650
651 ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1,
652 NULL);
653
654 if (ret == 1) {
655 ret = read(wait_fd, buf, BUF_SIZE);
656 if (ret < 0) {
657 PERROR("[epoll_pwait] read");
658 }
659 } else if (ret != 0) {
660 /* Expected error. */
661 }
662
663 error:
664 ret = close(epollfd);
665 if (ret) {
666 PERROR("close");
667 }
668 end:
669 return;
670 }
671
672 static
673 void *ppoll_writer(void *arg)
674 {
675 struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg;
676
677 while (!stop_thread) {
678 memset(data->ufds, data->value,
679 MAX_FDS * sizeof(struct pollfd));
680 usleep(100);
681 }
682
683 return NULL;
684 }
685
686 static
687 void do_ppoll(int *fds, struct pollfd *ufds)
688 {
689 int i, ret;
690 struct timespec ts;
691 char buf[BUF_SIZE];
692
693 ts.tv_sec = 0;
694 ts.tv_nsec = 1 * MSEC_PER_NSEC;
695
696 for (i = 0; i < MAX_FDS; i++) {
697 ufds[i].fd = fds[i];
698 ufds[i].events = POLLIN|POLLPRI;
699 }
700
701 ret = ppoll(ufds, MAX_FDS, &ts, NULL);
702
703 if (ret < 0) {
704 PERROR("ppoll");
705 } else if (ret > 0) {
706 ret = read(wait_fd, buf, BUF_SIZE);
707 if (ret < 0) {
708 PERROR("[ppoll] read");
709 }
710 }
711 }
712
713 static
714 void stress_ppoll(int *fds, int value)
715 {
716 pthread_t writer;
717 int iter, ret;
718 struct ppoll_thread_data thread_data;
719 struct pollfd ufds[MAX_FDS];
720
721 thread_data.ufds = ufds;
722 thread_data.value = value;
723
724 stop_thread = 0;
725 ret = pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data);
726 if (ret != 0) {
727 fprintf(stderr, "[error] pthread_create\n");
728 goto end;
729 }
730 for (iter = 0; iter < NR_ITER; iter++) {
731 do_ppoll(fds, ufds);
732 }
733 stop_thread = 1;
734 ret = pthread_join(writer, NULL);
735 if (ret) {
736 fprintf(stderr, "[error] pthread_join\n");
737 goto end;
738 }
739 end:
740 return;
741 }
742
743 /*
744 * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
745 * structure:
746 * - memset to 0
747 * - memset to 1
748 * - memset to INT_MAX
749 * Waits for input, but also set a timeout in case the input FD is overwritten
750 * before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the
751 * resulting trace is big (20MB).
752 *
753 * ppoll should work as expected and the trace should be readable at the end.
754 */
755 static
756 void ppoll_concurrent_write(FILE *validation_output_file)
757 {
758 int i, ret, fds[MAX_FDS];
759
760 for (i = 0; i < MAX_FDS; i++) {
761 fds[i] = dup(wait_fd);
762 if (fds[i] < 0) {
763 PERROR("dup");
764 }
765 }
766
767 stress_ppoll(fds, 0);
768 stress_ppoll(fds, 1);
769 stress_ppoll(fds, INT_MAX);
770
771 for (i = 0; i < MAX_FDS; i++) {
772 ret = close(fds[i]);
773 if (ret != 0) {
774 PERROR("close");
775 }
776 }
777
778 return;
779 }
780
781 static
782 void *epoll_pwait_writer(void *addr)
783 {
784 srand(time(NULL));
785
786 while (!stop_thread) {
787 usleep(rand() % 30);
788 munmap(addr, MAX_FDS * sizeof(struct epoll_event));
789 }
790
791 return NULL;
792 }
793
794 /*
795 * epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the
796 * buffer allocated for the returned data. This should randomly segfault.
797 * The trace should be readable and no kernel OOPS should occur.
798 */
799 static
800 void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
801 {
802 int ret, epollfd, i, fds[MAX_FDS];
803 char buf[BUF_SIZE];
804 struct epoll_event *epoll_event;
805 pthread_t writer;
806
807 for (i = 0; i < MAX_FDS; i++) {
808 fds[i] = -1;
809 }
810 epollfd = epoll_create(MAX_FDS);
811 if (epollfd < 0) {
812 PERROR("[epoll_pwait] create");
813 goto end;
814 }
815
816 ret = fprintf(validation_output_file,
817 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
818 getpid());
819 if (ret < 0) {
820 PERROR("[epoll_pwait] Failed to write test validation output");
821 goto error;
822 }
823
824 epoll_event = (struct epoll_event *) mmap(NULL,
825 MAX_FDS * sizeof(struct epoll_event),
826 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1,
827 0);
828 if (epoll_event == MAP_FAILED) {
829 PERROR("mmap");
830 goto error;
831 }
832
833 for (i = 0; i < MAX_FDS; i++) {
834 fds[i] = dup(wait_fd);
835 if (fds[i] < 0) {
836 PERROR("dup");
837 }
838 epoll_event[i].events = EPOLLIN | EPOLLPRI | EPOLLET;
839 epoll_event[i].data.fd = fds[i];
840 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], epoll_event);
841 if (ret < 0) {
842 PERROR("[epoll_pwait] add");
843 goto error_unmap;
844 }
845 }
846 stop_thread = 0;
847 ret = pthread_create(&writer, NULL, &epoll_pwait_writer,
848 (void *) epoll_event);
849 if (ret != 0) {
850 fprintf(stderr, "[error] pthread_create\n");
851 goto error_unmap;
852 }
853
854 ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL);
855
856 if (ret == 1) {
857 ret = read(wait_fd, buf, BUF_SIZE);
858 if (ret < 0) {
859 PERROR("[epoll_pwait] read");
860 }
861 } else if (ret != 0) {
862 /* Expected error. */
863 }
864
865 stop_thread = 1;
866 ret = pthread_join(writer, NULL);
867 if (ret) {
868 fprintf(stderr, "[error] pthread_join\n");
869 goto error_unmap;
870 }
871 error_unmap:
872 for (i = 0; i < MAX_FDS; i++) {
873 ret = close(fds[i]);
874 if (ret != 0) {
875 PERROR("close");
876 }
877 }
878
879 ret = munmap(epoll_event, MAX_FDS * sizeof(struct epoll_event));
880 if (ret != 0) {
881 PERROR("munmap");
882 }
883
884 error:
885 ret = close(epollfd);
886 if (ret) {
887 PERROR("close");
888 }
889 end:
890 return;
891 }
892
893 static
894 void print_list(void)
895 {
896 fprintf(stderr, "Test list (-t X):\n");
897 fprintf(stderr, "\t1: Working cases for select, pselect6, poll, ppoll "
898 "and epoll, waiting for input\n");
899 fprintf(stderr, "\t2: Timeout cases (1ms) for select, pselect6, poll, "
900 "ppoll and epoll\n");
901 fprintf(stderr, "\t3: pselect with an invalid fd\n");
902 fprintf(stderr, "\t4: ppoll with %d FDs\n", MAX_FDS);
903 fprintf(stderr, "\t5: ppoll buffer overflow, should segfault, waits "
904 "for input\n");
905 fprintf(stderr, "\t6: pselect with an invalid pointer, waits for "
906 "input\n");
907 fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n");
908 fprintf(stderr, "\t8: epoll_pwait with an invalid pointer, waits for "
909 "input\n");
910 fprintf(stderr, "\t9: epoll_pwait with maxevents set to INT_MAX, "
911 "waits for input\n");
912 fprintf(stderr, "\t10: ppoll with concurrent updates of the structure "
913 "from user-space, stress test (3000 iterations), "
914 "waits for input + timeout 1ms\n");
915 fprintf(stderr, "\t11: epoll_pwait with concurrent munmap of the buffer "
916 "from user-space, should randomly segfault, run "
917 "multiple times, waits for input + timeout 1ms\n");
918 }
919
920 int main(int argc, const char **argv)
921 {
922 int c, ret, test = -1;
923 poptContext optCon;
924 struct rlimit open_lim;
925 FILE *test_validation_output_file = NULL;
926 const char *test_validation_output_file_path = NULL;
927 struct poptOption optionsTable[] = {
928 { "test", 't', POPT_ARG_INT, &test, 0,
929 "Test to run", NULL },
930 { "list", 'l', 0, 0, 'l',
931 "List of tests (-t X)", NULL },
932 { "validation-file", 'o', POPT_ARG_STRING, &test_validation_output_file_path, 0,
933 "Test case output", NULL },
934 POPT_AUTOHELP
935 { NULL, 0, 0, NULL, 0 }
936 };
937 const struct test_case *test_case;
938
939 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
940
941 if (argc < 2) {
942 poptPrintUsage(optCon, stderr, 0);
943 ret = -1;
944 goto end;
945 }
946
947 ret = 0;
948
949 while ((c = poptGetNextOpt(optCon)) >= 0) {
950 switch (c) {
951 case 'l':
952 print_list();
953 goto end;
954 }
955 }
956
957 if (!test_validation_output_file_path) {
958 fprintf(stderr, "A test validation file path is required (--validation-file/-o)\n");
959 ret = -1;
960 goto end;
961 }
962
963 test_validation_output_file = fopen(test_validation_output_file_path, "w+");
964 if (!test_validation_output_file) {
965 PERROR("Failed to create test validation output file at '%s'",
966 test_validation_output_file_path);
967 ret = -1;
968 goto end;
969 }
970
971 open_lim.rlim_cur = MAX_FDS + MIN_NR_FDS;
972 open_lim.rlim_max = MAX_FDS + MIN_NR_FDS;
973
974 ret = setrlimit(RLIMIT_NOFILE, &open_lim);
975 if (ret < 0) {
976 PERROR("setrlimit");
977 goto end;
978 }
979
980 /*
981 * Some tests might segfault, but we need the getpid() to be output
982 * for the validation, disabling the buffering on the validation file
983 * works.
984 */
985 setbuf(test_validation_output_file, NULL);
986 wait_fd = STDIN_FILENO;
987
988 /* Test case id is 1-based. */
989 if (test < 1 || test > ARRAY_SIZE(test_cases)) {
990 poptPrintUsage(optCon, stderr, 0);
991 ret = -1;
992 }
993
994 test_case = &test_cases[test - 1];
995
996 timeout = test_case->timeout;
997 if (!test_case->produces_validation_info) {
998 /*
999 * All test cases need to provide, at minimum, the pid of the
1000 * test application.
1001 */
1002 ret = fprintf(test_validation_output_file, "{ \"pid\": %i }", getpid());
1003 if (ret < 0) {
1004 PERROR("Failed to write application pid to test validation file");
1005 goto end;
1006 }
1007 }
1008
1009 test_case->run(test_validation_output_file);
1010
1011 end:
1012 if (test_validation_output_file) {
1013 const int close_ret = fclose(test_validation_output_file);
1014
1015 if (close_ret) {
1016 PERROR("Failed to close test output file");
1017 }
1018 }
1019 poptFreeContext(optCon);
1020 return ret;
1021 }
This page took 0.100104 seconds and 4 git commands to generate.