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