2 * Copyright (C) 2016 Julien Desfossez <jdesfossez@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
12 #include <sys/syscall.h>
13 #include <sys/types.h>
19 #include <sys/select.h>
20 #include <sys/epoll.h>
23 #include <sys/resource.h>
27 #include <common/compat/time.h>
32 #define NR_ITER 1000 /* for stress-tests */
34 #define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */
35 #define BIG_SELECT_FD 1022
37 #define MSEC_PER_USEC 1000
38 #define MSEC_PER_NSEC (MSEC_PER_USEC * 1000)
40 static int timeout
; /* seconds, -1 to disable */
41 static volatile int stop_thread
;
44 struct ppoll_thread_data
{
49 void test_select_big(void)
51 fd_set rfds
, wfds
, exfds
;
61 fd2
= dup2(wait_fd
, BIG_SELECT_FD
);
69 tv
.tv_usec
= timeout
* MSEC_PER_USEC
;
72 ret
= select(fd2
+ 1, &rfds
, &wfds
, &exfds
, &tv
);
74 ret
= select(fd2
+ 1, &rfds
, &wfds
, &exfds
, NULL
);
80 printf("# [select] data available\n");
81 ret
= read(wait_fd
, buf
, BUF_SIZE
);
83 perror("[select] read");
86 printf("# [select] timeout\n");
89 ret
= close(BIG_SELECT_FD
);
98 void test_pselect(void)
106 FD_SET(wait_fd
, &rfds
);
109 tv
.tv_nsec
= timeout
* MSEC_PER_NSEC
;
112 ret
= pselect(1, &rfds
, NULL
, NULL
, &tv
, NULL
);
114 ret
= pselect(1, &rfds
, NULL
, NULL
, NULL
, NULL
);
120 printf("# [pselect] data available\n");
121 ret
= read(wait_fd
, buf
, BUF_SIZE
);
123 perror("[pselect] read");
126 printf("# [pselect] timeout\n");
131 void test_select(void)
139 FD_SET(wait_fd
, &rfds
);
142 tv
.tv_usec
= timeout
* MSEC_PER_USEC
;
145 ret
= select(1, &rfds
, NULL
, NULL
, &tv
);
147 ret
= select(1, &rfds
, NULL
, NULL
, NULL
);
153 printf("# [select] data available\n");
154 ret
= read(wait_fd
, buf
, BUF_SIZE
);
156 perror("[select] read");
159 printf("# [select] timeout\n");
166 struct pollfd ufds
[NB_FD
];
170 ufds
[0].fd
= wait_fd
;
171 ufds
[0].events
= POLLIN
|POLLPRI
;
173 ret
= poll(ufds
, 1, timeout
);
177 } else if (ret
> 0) {
178 printf("# [poll] data available\n");
179 ret
= read(wait_fd
, buf
, BUF_SIZE
);
181 perror("[poll] read");
184 printf("# [poll] timeout\n");
188 void test_ppoll(void)
190 struct pollfd ufds
[NB_FD
];
195 ufds
[0].fd
= wait_fd
;
196 ufds
[0].events
= POLLIN
|POLLPRI
;
200 ts
.tv_nsec
= timeout
* MSEC_PER_NSEC
;
201 ret
= ppoll(ufds
, 1, &ts
, NULL
);
203 ret
= ppoll(ufds
, 1, NULL
, NULL
);
209 } else if (ret
> 0) {
210 printf("# [ppoll] data available\n");
211 ret
= read(wait_fd
, buf
, BUF_SIZE
);
213 perror("[ppoll] read");
216 printf("# [ppoll] timeout\n");
220 void test_ppoll_big(void)
222 struct pollfd ufds
[MAX_FDS
];
224 int ret
, i
, fds
[MAX_FDS
];
226 for (i
= 0; i
< MAX_FDS
; i
++) {
227 fds
[i
] = dup(wait_fd
);
232 ufds
[i
].events
= POLLIN
|POLLPRI
;
235 ret
= ppoll(ufds
, MAX_FDS
, NULL
, NULL
);
239 } else if (ret
> 0) {
240 printf("# [ppoll] data available\n");
241 ret
= read(wait_fd
, buf
, BUF_SIZE
);
243 perror("[ppoll] read");
246 printf("# [ppoll] timeout\n");
249 for (i
= 0; i
< MAX_FDS
; i
++) {
259 void test_epoll(void)
263 struct epoll_event epoll_event
;
265 epollfd
= epoll_create(NB_FD
);
267 perror("[epoll] create");
271 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
272 epoll_event
.data
.fd
= wait_fd
;
273 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
275 perror("[epoll] add");
280 ret
= epoll_wait(epollfd
, &epoll_event
, 1, timeout
);
282 ret
= epoll_wait(epollfd
, &epoll_event
, 1, -1);
286 printf("# [epoll] data available\n");
287 ret
= read(wait_fd
, buf
, BUF_SIZE
);
289 perror("[epoll] read");
291 } else if (ret
== 0) {
292 printf("# [epoll] timeout\n");
294 perror("epoll_wait");
301 void test_pepoll(void)
305 struct epoll_event epoll_event
;
307 epollfd
= epoll_create(NB_FD
);
309 perror("[eppoll] create");
313 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
314 epoll_event
.data
.fd
= wait_fd
;
315 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
317 perror("[eppoll] add");
322 ret
= epoll_pwait(epollfd
, &epoll_event
, 1, timeout
, NULL
);
324 ret
= epoll_pwait(epollfd
, &epoll_event
, 1, -1, NULL
);
328 printf("# [eppoll] data available\n");
329 ret
= read(wait_fd
, buf
, BUF_SIZE
);
331 perror("[eppoll] read");
333 } else if (ret
== 0) {
334 printf("# [eppoll] timeout\n");
336 perror("epoll_pwait");
343 void run_working_cases(void)
350 * We need an input pipe for some cases and stdin might
351 * have random data, so we create a dummy pipe for this
352 * test to make sure we are running under clean conditions.
354 ret
= pipe(pipe_fds
);
359 wait_fd
= pipe_fds
[0];
370 ret
= close(pipe_fds
[0]);
374 ret
= close(pipe_fds
[1]);
385 * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
386 * segfault (eventually with a "*** stack smashing detected ***" message).
387 * The event should contain an array of 100 FDs filled with garbage.
389 void ppoll_fds_buffer_overflow(void)
391 struct pollfd ufds
[NB_FD
];
395 ufds
[0].fd
= wait_fd
;
396 ufds
[0].events
= POLLIN
|POLLPRI
;
398 ret
= syscall(SYS_ppoll
, ufds
, 100, NULL
, NULL
);
402 } else if (ret
> 0) {
403 printf("# [ppoll] data available\n");
404 ret
= read(wait_fd
, buf
, BUF_SIZE
);
406 perror("[ppoll] read");
409 printf("# [ppoll] timeout\n");
416 * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
417 * cleanly fail with a "Invalid argument".
418 * The event should contain an empty array of FDs and overflow = 1.
420 void ppoll_fds_ulong_max(void)
422 struct pollfd ufds
[NB_FD
];
426 ufds
[0].fd
= wait_fd
;
427 ufds
[0].events
= POLLIN
|POLLPRI
;
429 ret
= syscall(SYS_ppoll
, ufds
, ULONG_MAX
, NULL
, NULL
);
433 } else if (ret
> 0) {
434 printf("# [ppoll] data available\n");
435 ret
= read(wait_fd
, buf
, BUF_SIZE
);
437 perror("[ppoll] read");
440 printf("# [ppoll] timeout\n");
447 * Pass an invalid file descriptor to pselect6(). The syscall should return
448 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
450 void pselect_invalid_fd(void)
458 * Open a file, close it and use the closed FD in the pselect6 call.
461 fd
= open("/dev/null", O_RDONLY
);
476 ret
= syscall(SYS_pselect6
, fd
+ 1, &rfds
, NULL
, NULL
, NULL
, NULL
);
478 perror("# pselect()");
480 printf("# [pselect] data available\n");
481 ret
= read(wait_fd
, buf
, BUF_SIZE
);
483 perror("[pselect] read");
486 printf("# [pselect] timeout\n");
493 * Invalid pointer as writefds, should output a ppoll event
496 void pselect_invalid_pointer(void)
501 void *invalid
= (void *) 0x42;
504 FD_SET(wait_fd
, &rfds
);
506 ret
= syscall(SYS_pselect6
, 1, &rfds
, (fd_set
*) invalid
, NULL
, NULL
,
510 perror("# pselect()");
512 printf("# [pselect] data available\n");
513 ret
= read(wait_fd
, buf
, BUF_SIZE
);
515 perror("[pselect] read");
518 printf("# [pselect] timeout\n");
524 * Pass an invalid pointer to epoll_pwait, should fail with
525 * "Bad address", the event returns 0 FDs.
527 void epoll_pwait_invalid_pointer(void)
531 struct epoll_event epoll_event
;
532 void *invalid
= (void *) 0x42;
534 epollfd
= epoll_create(NB_FD
);
536 perror("[eppoll] create");
540 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
541 epoll_event
.data
.fd
= wait_fd
;
542 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
544 perror("[eppoll] add");
548 ret
= syscall(SYS_epoll_pwait
, epollfd
,
549 (struct epoll_event
*) invalid
, 1, -1, NULL
);
552 printf("# [eppoll] data available\n");
553 ret
= read(wait_fd
, buf
, BUF_SIZE
);
555 perror("[eppoll] read");
557 } else if (ret
== 0) {
558 printf("# [eppoll] timeout\n");
560 perror("# epoll_pwait");
568 * Set maxevents to INT_MAX, should output "Invalid argument"
569 * The event should return an empty array.
571 void epoll_pwait_int_max(void)
575 struct epoll_event epoll_event
;
577 epollfd
= epoll_create(NB_FD
);
579 perror("[eppoll] create");
583 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
584 epoll_event
.data
.fd
= wait_fd
;
585 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
587 perror("[eppoll] add");
591 ret
= syscall(SYS_epoll_pwait
, epollfd
, &epoll_event
, INT_MAX
, -1,
595 printf("# [eppoll] data available\n");
596 ret
= read(wait_fd
, buf
, BUF_SIZE
);
598 perror("[eppoll] read");
600 } else if (ret
== 0) {
601 printf("# [eppoll] timeout\n");
603 perror("# epoll_pwait");
610 void *ppoll_writer(void *arg
)
612 struct ppoll_thread_data
*data
= (struct ppoll_thread_data
*) arg
;
614 while (!stop_thread
) {
615 memset(data
->ufds
, data
->value
,
616 MAX_FDS
* sizeof(struct pollfd
));
623 void do_ppoll(int *fds
, struct pollfd
*ufds
)
630 ts
.tv_nsec
= 1 * MSEC_PER_NSEC
;
632 for (i
= 0; i
< MAX_FDS
; i
++) {
634 ufds
[i
].events
= POLLIN
|POLLPRI
;
637 ret
= ppoll(ufds
, MAX_FDS
, &ts
, NULL
);
641 } else if (ret
> 0) {
642 printf("# [ppoll] data available\n");
643 ret
= read(wait_fd
, buf
, BUF_SIZE
);
645 perror("[ppoll] read");
648 printf("# [ppoll] timeout\n");
652 void stress_ppoll(int *fds
, int value
)
656 struct ppoll_thread_data thread_data
;
657 struct pollfd ufds
[MAX_FDS
];
659 thread_data
.ufds
= ufds
;
660 thread_data
.value
= value
;
663 ret
= pthread_create(&writer
, NULL
, &ppoll_writer
, (void *) &thread_data
);
665 fprintf(stderr
, "[error] pthread_create\n");
668 for (iter
= 0; iter
< NR_ITER
; iter
++) {
672 ret
= pthread_join(writer
, NULL
);
674 fprintf(stderr
, "[error] pthread_join\n");
682 * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
686 * - memset to INT_MAX
687 * Waits for input, but also set a timeout in case the input FD is overwritten
688 * before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the
689 * resulting trace is big (20MB).
691 * ppoll should work as expected and the trace should be readable at the end.
693 void ppoll_concurrent_write(void)
695 int i
, ret
, fds
[MAX_FDS
];
697 for (i
= 0; i
< MAX_FDS
; i
++) {
698 fds
[i
] = dup(wait_fd
);
704 stress_ppoll(fds
, 0);
705 stress_ppoll(fds
, 1);
706 stress_ppoll(fds
, INT_MAX
);
708 for (i
= 0; i
< MAX_FDS
; i
++) {
718 void *epoll_pwait_writer(void *addr
)
722 while (!stop_thread
) {
724 munmap(addr
, MAX_FDS
* sizeof(struct epoll_event
));
731 * epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the
732 * buffer allocated for the returned data. This should randomly segfault.
733 * The trace should be readable and no kernel OOPS should occur.
735 void epoll_pwait_concurrent_munmap(void)
737 int ret
, epollfd
, i
, fds
[MAX_FDS
];
739 struct epoll_event
*epoll_event
;
742 for (i
= 0; i
< MAX_FDS
; i
++) {
745 epollfd
= epoll_create(MAX_FDS
);
747 perror("[eppoll] create");
751 epoll_event
= mmap(NULL
, MAX_FDS
* sizeof(struct epoll_event
),
752 PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_ANONYMOUS
,
754 if (epoll_event
== MAP_FAILED
) {
759 for (i
= 0; i
< MAX_FDS
; i
++) {
760 fds
[i
] = dup(wait_fd
);
764 epoll_event
[i
].events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
765 epoll_event
[i
].data
.fd
= fds
[i
];
766 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fds
[i
], epoll_event
);
768 perror("[eppoll] add");
773 ret
= pthread_create(&writer
, NULL
, &epoll_pwait_writer
,
774 (void *) epoll_event
);
776 fprintf(stderr
, "[error] pthread_create\n");
780 ret
= epoll_pwait(epollfd
, epoll_event
, 1, 1, NULL
);
783 printf("# [eppoll] data available\n");
784 ret
= read(wait_fd
, buf
, BUF_SIZE
);
786 perror("[eppoll] read");
788 } else if (ret
== 0) {
789 printf("# [eppoll] timeout\n");
791 perror("# epoll_pwait");
795 ret
= pthread_join(writer
, NULL
);
797 fprintf(stderr
, "[error] pthread_join\n");
801 for (i
= 0; i
< MAX_FDS
; i
++) {
808 ret
= munmap(epoll_event
, MAX_FDS
* sizeof(struct epoll_event
));
817 void usage(poptContext optCon
, int exitcode
, char *error
, char *addl
)
819 poptPrintUsage(optCon
, stderr
, 0);
821 fprintf(stderr
, "%s: %s\n", error
, addl
);
826 void print_list(void)
828 fprintf(stderr
, "Test list (-t X):\n");
829 fprintf(stderr
, "\t1: Working cases for select, pselect6, poll, ppoll "
830 "and epoll, waiting for input\n");
831 fprintf(stderr
, "\t2: Timeout cases (1ms) for select, pselect6, poll, "
832 "ppoll and epoll\n");
833 fprintf(stderr
, "\t3: pselect with an invalid fd\n");
834 fprintf(stderr
, "\t4: ppoll with %d FDs\n", MAX_FDS
);
835 fprintf(stderr
, "\t5: ppoll buffer overflow, should segfault, waits "
837 fprintf(stderr
, "\t6: pselect with an invalid pointer, waits for "
839 fprintf(stderr
, "\t7: ppoll with ulong_max fds, waits for input\n");
840 fprintf(stderr
, "\t8: epoll_pwait with an invalid pointer, waits for "
842 fprintf(stderr
, "\t9: epoll_pwait with maxevents set to INT_MAX, "
843 "waits for input\n");
844 fprintf(stderr
, "\t10: ppoll with concurrent updates of the structure "
845 "from user-space, stress test (3000 iterations), "
846 "waits for input + timeout 1ms\n");
847 fprintf(stderr
, "\t11: epoll_pwait with concurrent munmap of the buffer "
848 "from user-space, should randomly segfault, run "
849 "multiple times, waits for input + timeout 1ms\n");
852 int main(int argc
, const char **argv
)
854 int c
, ret
, test
= -1;
856 struct rlimit open_lim
;
858 struct poptOption optionsTable
[] = {
859 { "test", 't', POPT_ARG_INT
, &test
, 0,
860 "Test to run", NULL
},
861 { "list", 'l', 0, 0, 'l',
862 "List of tests (-t X)", NULL
},
864 { NULL
, 0, 0, NULL
, 0 }
867 optCon
= poptGetContext(NULL
, argc
, argv
, optionsTable
, 0);
870 poptPrintUsage(optCon
, stderr
, 0);
877 while ((c
= poptGetNextOpt(optCon
)) >= 0) {
885 open_lim
.rlim_cur
= MAX_FDS
+ MIN_NR_FDS
;
886 open_lim
.rlim_max
= MAX_FDS
+ MIN_NR_FDS
;
888 ret
= setrlimit(RLIMIT_NOFILE
, &open_lim
);
895 * Some tests might segfault, but we need the getpid() to be output
896 * for the validation, disabling the buffering on stdout works.
898 setbuf(stdout
, NULL
);
899 printf("%d\n", getpid());
901 wait_fd
= STDIN_FILENO
;
913 pselect_invalid_fd();
919 ppoll_fds_buffer_overflow();
922 pselect_invalid_pointer();
925 ppoll_fds_ulong_max();
928 epoll_pwait_invalid_pointer();
931 epoll_pwait_int_max();
934 ppoll_concurrent_write();
937 epoll_pwait_concurrent_munmap();
940 poptPrintUsage(optCon
, stderr
, 0);
946 poptFreeContext(optCon
);