d3a21e2fcc392fe5bedb4f5b06dc56b9b393bf1d
[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, .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 },
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 __attribute__((unused)))
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(
447 FILE *validation_output_file __attribute__((unused)))
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) {
459 PERROR("ppoll");
460 } else if (ret > 0) {
461 ret = read(wait_fd, buf, BUF_SIZE);
462 if (ret < 0) {
463 PERROR("[ppoll] read");
464 }
465 }
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 */
473 static
474 void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused)))
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);
484 if (ret < 0) {
485 /* Expected error. */
486 } else if (ret > 0) {
487 ret = read(wait_fd, buf, BUF_SIZE);
488 if (ret < 0) {
489 PERROR("[ppoll] read");
490 }
491 }
492 }
493
494 /*
495 * Pass an invalid file descriptor to pselect6(). The syscall should return
496 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
497 */
498 static
499 void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
500 {
501 fd_set rfds;
502 int ret;
503 int fd;
504 char buf[BUF_SIZE];
505
506 /*
507 * Open a file, close it and use the closed FD in the pselect6 call.
508 */
509 fd = open("/dev/null", O_RDONLY);
510 if (fd == -1) {
511 PERROR("open");
512 goto error;
513 }
514
515 ret = close(fd);
516 if (ret == -1) {
517 PERROR("close");
518 goto error;
519 }
520
521 FD_ZERO(&rfds);
522 FD_SET(fd, &rfds);
523
524 ret = syscall(SYS_pselect6, fd + 1, &rfds, NULL, NULL, NULL, NULL);
525 if (ret == -1) {
526 /* Expected error. */
527 } else if (ret) {
528 ret = read(wait_fd, buf, BUF_SIZE);
529 if (ret < 0) {
530 PERROR("[pselect] read");
531 }
532 }
533 error:
534 return;
535 }
536
537 /*
538 * Invalid pointer as writefds, should output a ppoll event
539 * with 0 FDs.
540 */
541 static
542 void pselect_invalid_pointer(
543 FILE *validation_output_file __attribute__((unused)))
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);
555 if (ret == -1) {
556 /* Expected error. */
557 } else if (ret) {
558 ret = read(wait_fd, buf, BUF_SIZE);
559 if (ret < 0) {
560 PERROR("[pselect] read");
561 }
562 }
563 }
564
565 /*
566 * Pass an invalid pointer to epoll_pwait, should fail with
567 * "Bad address", the event returns 0 FDs.
568 */
569 static
570 void epoll_pwait_invalid_pointer(FILE *validation_output_file)
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) {
579 PERROR("[epoll_pwait] create");
580 goto end;
581 }
582
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
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) {
595 PERROR("[epoll_pwait] add");
596 goto error;
597 }
598
599 ret = syscall(SYS_epoll_pwait, epollfd,
600 (struct epoll_event *) invalid, 1, -1, NULL);
601
602 if (ret == 1) {
603 ret = read(wait_fd, buf, BUF_SIZE);
604 if (ret < 0) {
605 PERROR("[epoll_pwait] read");
606 }
607 } else if (ret != 0) {
608 /* Expected error. */
609 }
610
611 error:
612 ret = close(epollfd);
613 if (ret) {
614 PERROR("close");
615 }
616 end:
617 return;
618 }
619
620 /*
621 * Set maxevents to INT_MAX, should output "Invalid argument"
622 * The event should return an empty array.
623 */
624 static
625 void epoll_pwait_int_max(FILE *validation_output_file)
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) {
633 PERROR("[epoll_pwait] create");
634 goto end;
635 }
636
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
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) {
649 PERROR("[epoll_pwait] add");
650 goto error;
651 }
652
653 ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1,
654 NULL);
655
656 if (ret == 1) {
657 ret = read(wait_fd, buf, BUF_SIZE);
658 if (ret < 0) {
659 PERROR("[epoll_pwait] read");
660 }
661 } else if (ret != 0) {
662 /* Expected error. */
663 }
664
665 error:
666 ret = close(epollfd);
667 if (ret) {
668 PERROR("close");
669 }
670 end:
671 return;
672 }
673
674 static
675 void *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
688 static
689 void 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) {
706 PERROR("ppoll");
707 } else if (ret > 0) {
708 ret = read(wait_fd, buf, BUF_SIZE);
709 if (ret < 0) {
710 PERROR("[ppoll] read");
711 }
712 }
713 }
714
715 static
716 void 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;
736 ret = pthread_join(writer, NULL);
737 if (ret) {
738 fprintf(stderr, "[error] pthread_join\n");
739 goto end;
740 }
741 end:
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 */
757 static
758 void ppoll_concurrent_write(
759 FILE *validation_output_file __attribute__((unused)))
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) {
766 PERROR("dup");
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) {
777 PERROR("close");
778 }
779 }
780
781 return;
782 }
783
784 static
785 void *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 */
802 static
803 void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
804 {
805 int ret, epollfd, i, fds[MAX_FDS];
806 char buf[BUF_SIZE];
807 struct epoll_event *epoll_event;
808 pthread_t writer;
809
810 for (i = 0; i < MAX_FDS; i++) {
811 fds[i] = -1;
812 }
813 epollfd = epoll_create(MAX_FDS);
814 if (epollfd < 0) {
815 PERROR("[epoll_pwait] create");
816 goto end;
817 }
818
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);
831 if (epoll_event == MAP_FAILED) {
832 PERROR("mmap");
833 goto error;
834 }
835
836 for (i = 0; i < MAX_FDS; i++) {
837 fds[i] = dup(wait_fd);
838 if (fds[i] < 0) {
839 PERROR("dup");
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) {
845 PERROR("[epoll_pwait] add");
846 goto error_unmap;
847 }
848 }
849 stop_thread = 0;
850 ret = pthread_create(&writer, NULL, &epoll_pwait_writer,
851 (void *) epoll_event);
852 if (ret != 0) {
853 fprintf(stderr, "[error] pthread_create\n");
854 goto error_unmap;
855 }
856
857 ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL);
858
859 if (ret == 1) {
860 ret = read(wait_fd, buf, BUF_SIZE);
861 if (ret < 0) {
862 PERROR("[epoll_pwait] read");
863 }
864 } else if (ret != 0) {
865 /* Expected error. */
866 }
867
868 stop_thread = 1;
869 ret = pthread_join(writer, NULL);
870 if (ret) {
871 fprintf(stderr, "[error] pthread_join\n");
872 goto error_unmap;
873 }
874 error_unmap:
875 for (i = 0; i < MAX_FDS; i++) {
876 ret = close(fds[i]);
877 if (ret != 0) {
878 PERROR("close");
879 }
880 }
881
882 ret = munmap(epoll_event, MAX_FDS * sizeof(struct epoll_event));
883 if (ret != 0) {
884 PERROR("munmap");
885 }
886
887 error:
888 ret = close(epollfd);
889 if (ret) {
890 PERROR("close");
891 }
892 end:
893 return;
894 }
895
896 static
897 void 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");
904 fprintf(stderr, "\t3: pselect with an invalid fd\n");
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");
908 fprintf(stderr, "\t6: pselect with an invalid pointer, waits for "
909 "input\n");
910 fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n");
911 fprintf(stderr, "\t8: epoll_pwait with an invalid pointer, waits for "
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
923 int main(int argc, const char **argv)
924 {
925 int c, ret, test = -1;
926 poptContext optCon;
927 struct rlimit open_lim;
928 FILE *test_validation_output_file = NULL;
929 const char *test_validation_output_file_path = NULL;
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 },
935 { "validation-file", 'o', POPT_ARG_STRING, &test_validation_output_file_path, 0,
936 "Test case output", NULL },
937 POPT_AUTOHELP
938 { NULL, 0, 0, NULL, 0, NULL, NULL }
939 };
940 const struct test_case *test_case;
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) {
953 switch (c) {
954 case 'l':
955 print_list();
956 goto end;
957 }
958 }
959
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
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) {
979 PERROR("setrlimit");
980 goto end;
981 }
982
983 /*
984 * Some tests might segfault, but we need the getpid() to be output
985 * for the validation, disabling the buffering on the validation file
986 * works.
987 */
988 setbuf(test_validation_output_file, NULL);
989 wait_fd = STDIN_FILENO;
990
991 /* Test case id is 1-based. */
992 if (test < 1 || test > ARRAY_SIZE(test_cases)) {
993 poptPrintUsage(optCon, stderr, 0);
994 ret = -1;
995 }
996
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
1014 end:
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 }
1022 poptFreeContext(optCon);
1023 return ret;
1024 }
This page took 0.093434 seconds and 4 git commands to generate.