X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=tests%2Fregression%2Fkernel%2Fselect_poll_epoll.c;h=abedc0aa929557c7aa859e76788d71d53e0f0cb4;hb=2af9cd67cd3e2f8021559d01dd21c44a4844a27e;hp=08e7fce0d898df547da42e371dc694f90bea4141;hpb=8b3b99e2870d53c97f9ec9a976ed91f43da5f02b;p=lttng-tools.git diff --git a/tests/regression/kernel/select_poll_epoll.c b/tests/regression/kernel/select_poll_epoll.c index 08e7fce0d..abedc0aa9 100644 --- a/tests/regression/kernel/select_poll_epoll.c +++ b/tests/regression/kernel/select_poll_epoll.c @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2016 Julien Desfossez + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + #include #include #include @@ -18,6 +25,7 @@ #include #include #include +#include #define BUF_SIZE 256 #define NB_FD 1 @@ -31,14 +39,50 @@ #define MSEC_PER_NSEC (MSEC_PER_USEC * 1000) static int timeout; /* seconds, -1 to disable */ -volatile static int stop_thread; +static volatile int stop_thread; static int wait_fd; +/* Used by logging utils. */ +int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi; + +static void run_working_cases(FILE *validation_output_file); +static void pselect_invalid_fd(FILE *validation_output_file); +static void test_ppoll_big(FILE *validation_output_file); +static void ppoll_fds_buffer_overflow(FILE *validation_output_file); +static void pselect_invalid_pointer(FILE *validation_output_file); +static void ppoll_fds_ulong_max(FILE *validation_output_file); +static void epoll_pwait_invalid_pointer(FILE *validation_output_file); +static void epoll_pwait_int_max(FILE *validation_output_file); +static void ppoll_concurrent_write(FILE *validation_output_file); +static void epoll_pwait_concurrent_munmap(FILE *validation_output_file); + +typedef void (*test_case_cb)(FILE *output_file); + +static const struct test_case { + test_case_cb run; + bool produces_validation_info; + int timeout; +} test_cases [] = +{ + { .run = run_working_cases, .produces_validation_info = true, .timeout = -1 }, + { .run = run_working_cases, .produces_validation_info = true, .timeout = 1 }, + { .run = pselect_invalid_fd, .produces_validation_info = false }, + { .run = test_ppoll_big, .produces_validation_info = false }, + { .run = ppoll_fds_buffer_overflow, .produces_validation_info = false }, + { .run = pselect_invalid_pointer, .produces_validation_info = false }, + { .run = ppoll_fds_ulong_max, .produces_validation_info = false }, + { .run = epoll_pwait_invalid_pointer, .produces_validation_info = true }, + { .run = epoll_pwait_int_max, .produces_validation_info = true }, + { .run = ppoll_concurrent_write, .produces_validation_info = false }, + { .run = epoll_pwait_concurrent_munmap, .produces_validation_info = true }, +}; + struct ppoll_thread_data { struct pollfd *ufds; int value; }; +static void test_select_big(void) { fd_set rfds, wfds, exfds; @@ -53,7 +97,7 @@ void test_select_big(void) fd2 = dup2(wait_fd, BIG_SELECT_FD); if (fd2 < 0) { - perror("dup2"); + PERROR("dup2"); goto end; } FD_SET(fd2, &rfds); @@ -68,26 +112,24 @@ void test_select_big(void) } if (ret == -1) { - perror("select()"); + PERROR("select()"); } else if (ret) { - printf("# [select] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[select] read"); + PERROR("[select] read"); } - } else { - printf("# [select] timeout\n"); } ret = close(BIG_SELECT_FD); if (ret) { - perror("close"); + PERROR("close"); } end: return; } +static void test_pselect(void) { fd_set rfds; @@ -108,19 +150,16 @@ void test_pselect(void) } if (ret == -1) { - perror("pselect()"); + PERROR("pselect()"); } else if (ret) { - printf("# [pselect] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[pselect] read"); + PERROR("[pselect] read"); } - } else { - printf("# [pselect] timeout\n"); } - } +static void test_select(void) { fd_set rfds; @@ -141,19 +180,16 @@ void test_select(void) } if (ret == -1) { - perror("select()"); + PERROR("select()"); } else if (ret) { - printf("# [select] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[select] read"); + PERROR("[select] read"); } - } else { - printf("# [select] timeout\n"); } - } +static void test_poll(void) { struct pollfd ufds[NB_FD]; @@ -166,18 +202,16 @@ void test_poll(void) ret = poll(ufds, 1, timeout); if (ret < 0) { - perror("poll"); + PERROR("poll"); } else if (ret > 0) { - printf("# [poll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[poll] read"); + PERROR("[poll] read"); } - } else { - printf("# [poll] timeout\n"); } } +static void test_ppoll(void) { struct pollfd ufds[NB_FD]; @@ -198,19 +232,17 @@ void test_ppoll(void) if (ret < 0) { - perror("ppoll"); + PERROR("ppoll"); } else if (ret > 0) { - printf("# [ppoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[ppoll] read"); + PERROR("[ppoll] read"); } - } else { - printf("# [ppoll] timeout\n"); } } -void test_ppoll_big(void) +static +void test_ppoll_big(FILE *validation_output_file) { struct pollfd ufds[MAX_FDS]; char buf[BUF_SIZE]; @@ -219,7 +251,7 @@ void test_ppoll_big(void) for (i = 0; i < MAX_FDS; i++) { fds[i] = dup(wait_fd); if (fds[i] < 0) { - perror("dup"); + PERROR("dup"); } ufds[i].fd = fds[i]; ufds[i].events = POLLIN|POLLPRI; @@ -228,28 +260,26 @@ void test_ppoll_big(void) ret = ppoll(ufds, MAX_FDS, NULL, NULL); if (ret < 0) { - perror("ppoll"); + PERROR("ppoll"); } else if (ret > 0) { - printf("# [ppoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[ppoll] read"); + PERROR("[ppoll] read"); } - } else { - printf("# [ppoll] timeout\n"); } for (i = 0; i < MAX_FDS; i++) { ret = close(fds[i]); if (ret != 0) { - perror("close"); + PERROR("close"); } } return; } -void test_epoll(void) +static +void test_epoll(FILE *validation_output_file) { int ret, epollfd; char buf[BUF_SIZE]; @@ -257,16 +287,23 @@ void test_epoll(void) epollfd = epoll_create(NB_FD); if (epollfd < 0) { - perror("[epoll] create"); + PERROR("[epoll] create"); goto end; } + ret = fprintf(validation_output_file, + ", \"epoll_wait_fd\": %i", epollfd); + if (ret < 0) { + PERROR("[epoll] Failed to write test validation output"); + goto error; + } + epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET; epoll_event.data.fd = wait_fd; ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event); if (ret < 0) { - perror("[epoll] add"); - goto end; + PERROR("[epoll] add"); + goto error; } if (timeout > 0) { @@ -276,22 +313,25 @@ void test_epoll(void) } if (ret == 1) { - printf("# [epoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[epoll] read"); + PERROR("[epoll] read"); } - } else if (ret == 0) { - printf("# [epoll] timeout\n"); - } else { - perror("epoll_wait"); + } else if (ret != 0) { + PERROR("epoll_wait"); } +error: + ret = close(epollfd); + if (ret) { + PERROR("close"); + } end: return; } -void test_pepoll(void) +static +void test_epoll_pwait(FILE *validation_output_file) { int ret, epollfd; char buf[BUF_SIZE]; @@ -299,16 +339,23 @@ void test_pepoll(void) epollfd = epoll_create(NB_FD); if (epollfd < 0) { - perror("[eppoll] create"); + PERROR("[epoll_pwait] create"); goto end; } + ret = fprintf(validation_output_file, + ", \"epoll_pwait_fd\": %i", epollfd); + if (ret < 0) { + PERROR("[epoll_pwait] Failed to write test validation output"); + goto error; + } + epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET; epoll_event.data.fd = wait_fd; ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event); if (ret < 0) { - perror("[eppoll] add"); - goto end; + PERROR("[epoll_pwait] add"); + goto error; } if (timeout > 0) { @@ -318,22 +365,25 @@ void test_pepoll(void) } if (ret == 1) { - printf("# [eppoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[eppoll] read"); + PERROR("[epoll_pwait] read"); } - } else if (ret == 0) { - printf("# [eppoll] timeout\n"); - } else { - perror("epoll_pwait"); + } else if (ret != 0) { + PERROR("epoll_pwait"); } +error: + ret = close(epollfd); + if (ret) { + PERROR("close"); + } end: return; } -void run_working_cases(void) +static +void run_working_cases(FILE *validation_output_file) { int ret; int pipe_fds[2]; @@ -346,7 +396,7 @@ void run_working_cases(void) */ ret = pipe(pipe_fds); if (ret != 0) { - perror("pipe"); + PERROR("pipe"); goto end; } wait_fd = pipe_fds[0]; @@ -356,20 +406,33 @@ void run_working_cases(void) test_select_big(); test_poll(); test_ppoll(); - test_epoll(); - test_pepoll(); + + ret = fprintf(validation_output_file, "{ \"pid\": %i", getpid()); + if (ret < 0) { + PERROR("Failed to write pid to test validation file"); + goto end; + } + + test_epoll(validation_output_file); + test_epoll_pwait(validation_output_file); if (timeout > 0) { ret = close(pipe_fds[0]); if (ret) { - perror("close"); + PERROR("close"); } ret = close(pipe_fds[1]); if (ret) { - perror("close"); + PERROR("close"); } } + ret = fputs(" }", validation_output_file); + if (ret < 0) { + PERROR("Failed to close JSON dictionary in test validation file"); + goto end; + } + end: return; } @@ -379,7 +442,8 @@ end: * segfault (eventually with a "*** stack smashing detected ***" message). * The event should contain an array of 100 FDs filled with garbage. */ -void ppoll_fds_buffer_overflow(void) +static +void ppoll_fds_buffer_overflow(FILE *validation_output_file) { struct pollfd ufds[NB_FD]; char buf[BUF_SIZE]; @@ -391,18 +455,13 @@ void ppoll_fds_buffer_overflow(void) ret = syscall(SYS_ppoll, ufds, 100, NULL, NULL); if (ret < 0) { - perror("ppoll"); + PERROR("ppoll"); } else if (ret > 0) { - printf("# [ppoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[ppoll] read"); + PERROR("[ppoll] read"); } - } else { - printf("# [ppoll] timeout\n"); } - - return; } /* @@ -410,7 +469,8 @@ void ppoll_fds_buffer_overflow(void) * cleanly fail with a "Invalid argument". * The event should contain an empty array of FDs and overflow = 1. */ -void ppoll_fds_ulong_max(void) +static +void ppoll_fds_ulong_max(FILE *validation_output_file) { struct pollfd ufds[NB_FD]; char buf[BUF_SIZE]; @@ -420,27 +480,22 @@ void ppoll_fds_ulong_max(void) ufds[0].events = POLLIN|POLLPRI; ret = syscall(SYS_ppoll, ufds, ULONG_MAX, NULL, NULL); - if (ret < 0) { - perror("# ppoll"); + /* Expected error. */ } else if (ret > 0) { - printf("# [ppoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[ppoll] read"); + PERROR("[ppoll] read"); } - } else { - printf("# [ppoll] timeout\n"); } - - return; } /* * Pass an invalid file descriptor to pselect6(). The syscall should return * -EBADF. The recorded event should contain a "ret = -EBADF (-9)". */ -void pselect_invalid_fd(void) +static +void pselect_invalid_fd(FILE *validation_output_file) { fd_set rfds; int ret; @@ -450,16 +505,15 @@ void pselect_invalid_fd(void) /* * Open a file, close it and use the closed FD in the pselect6 call. */ - fd = open("/dev/null", O_RDONLY); if (fd == -1) { - perror("open"); + PERROR("open"); goto error; } ret = close(fd); if (ret == -1) { - perror("close"); + PERROR("close"); goto error; } @@ -468,15 +522,12 @@ void pselect_invalid_fd(void) ret = syscall(SYS_pselect6, fd + 1, &rfds, NULL, NULL, NULL, NULL); if (ret == -1) { - perror("# pselect()"); + /* Expected error. */ } else if (ret) { - printf("# [pselect] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[pselect] read"); + PERROR("[pselect] read"); } - } else { - printf("# [pselect] timeout\n"); } error: return; @@ -486,7 +537,8 @@ error: * Invalid pointer as writefds, should output a ppoll event * with 0 FDs. */ -void pselect_invalid_pointer(void) +static +void pselect_invalid_pointer(FILE *validation_output_file) { fd_set rfds; int ret; @@ -498,26 +550,22 @@ void pselect_invalid_pointer(void) ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL, NULL); - if (ret == -1) { - perror("# pselect()"); + /* Expected error. */ } else if (ret) { - printf("# [pselect] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[pselect] read"); + PERROR("[pselect] read"); } - } else { - printf("# [pselect] timeout\n"); } - } /* * Pass an invalid pointer to epoll_pwait, should fail with * "Bad address", the event returns 0 FDs. */ -void epoll_pwait_invalid_pointer(void) +static +void epoll_pwait_invalid_pointer(FILE *validation_output_file) { int ret, epollfd; char buf[BUF_SIZE]; @@ -526,33 +574,43 @@ void epoll_pwait_invalid_pointer(void) epollfd = epoll_create(NB_FD); if (epollfd < 0) { - perror("[eppoll] create"); + PERROR("[epoll_pwait] create"); goto end; } + ret = fprintf(validation_output_file, + "{ \"epollfd\": %i, \"pid\": %i }", epollfd, + getpid()); + if (ret < 0) { + PERROR("[epoll_pwait] Failed to write test validation output"); + goto error; + } + epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET; epoll_event.data.fd = wait_fd; ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event); if (ret < 0) { - perror("[eppoll] add"); - goto end; + PERROR("[epoll_pwait] add"); + goto error; } ret = syscall(SYS_epoll_pwait, epollfd, (struct epoll_event *) invalid, 1, -1, NULL); if (ret == 1) { - printf("# [eppoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[eppoll] read"); + PERROR("[epoll_pwait] read"); } - } else if (ret == 0) { - printf("# [eppoll] timeout\n"); - } else { - perror("# epoll_pwait"); + } else if (ret != 0) { + /* Expected error. */ } +error: + ret = close(epollfd); + if (ret) { + PERROR("close"); + } end: return; } @@ -561,7 +619,8 @@ end: * Set maxevents to INT_MAX, should output "Invalid argument" * The event should return an empty array. */ -void epoll_pwait_int_max(void) +static +void epoll_pwait_int_max(FILE *validation_output_file) { int ret, epollfd; char buf[BUF_SIZE]; @@ -569,37 +628,48 @@ void epoll_pwait_int_max(void) epollfd = epoll_create(NB_FD); if (epollfd < 0) { - perror("[eppoll] create"); + PERROR("[epoll_pwait] create"); goto end; } + ret = fprintf(validation_output_file, + "{ \"epollfd\": %i, \"pid\": %i }", epollfd, + getpid()); + if (ret < 0) { + PERROR("[epoll_pwait] Failed to write test validation output"); + goto error; + } + epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET; epoll_event.data.fd = wait_fd; ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event); if (ret < 0) { - perror("[eppoll] add"); - goto end; + PERROR("[epoll_pwait] add"); + goto error; } ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1, NULL); if (ret == 1) { - printf("# [eppoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[eppoll] read"); + PERROR("[epoll_pwait] read"); } - } else if (ret == 0) { - printf("# [eppoll] timeout\n"); - } else { - perror("# epoll_pwait"); + } else if (ret != 0) { + /* Expected error. */ } +error: + ret = close(epollfd); + if (ret) { + PERROR("close"); + } end: return; } +static void *ppoll_writer(void *arg) { struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg; @@ -613,6 +683,7 @@ void *ppoll_writer(void *arg) return NULL; } +static void do_ppoll(int *fds, struct pollfd *ufds) { int i, ret; @@ -630,18 +701,16 @@ void do_ppoll(int *fds, struct pollfd *ufds) ret = ppoll(ufds, MAX_FDS, &ts, NULL); if (ret < 0) { - perror("ppoll"); + PERROR("ppoll"); } else if (ret > 0) { - printf("# [ppoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[ppoll] read"); + PERROR("[ppoll] read"); } - } else { - printf("# [ppoll] timeout\n"); } } +static void stress_ppoll(int *fds, int value) { pthread_t writer; @@ -683,14 +752,15 @@ end: * * ppoll should work as expected and the trace should be readable at the end. */ -void ppoll_concurrent_write(void) +static +void ppoll_concurrent_write(FILE *validation_output_file) { int i, ret, fds[MAX_FDS]; for (i = 0; i < MAX_FDS; i++) { fds[i] = dup(wait_fd); if (fds[i] < 0) { - perror("dup"); + PERROR("dup"); } } @@ -701,13 +771,14 @@ void ppoll_concurrent_write(void) for (i = 0; i < MAX_FDS; i++) { ret = close(fds[i]); if (ret != 0) { - perror("close"); + PERROR("close"); } } return; } +static void *epoll_pwait_writer(void *addr) { srand(time(NULL)); @@ -725,38 +796,51 @@ void *epoll_pwait_writer(void *addr) * buffer allocated for the returned data. This should randomly segfault. * The trace should be readable and no kernel OOPS should occur. */ -void epoll_pwait_concurrent_munmap(void) +static +void epoll_pwait_concurrent_munmap(FILE *validation_output_file) { int ret, epollfd, i, fds[MAX_FDS]; char buf[BUF_SIZE]; struct epoll_event *epoll_event; pthread_t writer; + for (i = 0; i < MAX_FDS; i++) { + fds[i] = -1; + } epollfd = epoll_create(MAX_FDS); if (epollfd < 0) { - perror("[eppoll] create"); + PERROR("[epoll_pwait] create"); goto end; } - epoll_event = mmap(NULL, MAX_FDS * sizeof(struct epoll_event), - PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); + ret = fprintf(validation_output_file, + "{ \"epollfd\": %i, \"pid\": %i }", epollfd, + getpid()); + if (ret < 0) { + PERROR("[epoll_pwait] Failed to write test validation output"); + goto error; + } + + epoll_event = (struct epoll_event *) mmap(NULL, + MAX_FDS * sizeof(struct epoll_event), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, + 0); if (epoll_event == MAP_FAILED) { - perror("mmap"); - goto end; + PERROR("mmap"); + goto error; } for (i = 0; i < MAX_FDS; i++) { fds[i] = dup(wait_fd); if (fds[i] < 0) { - perror("dup"); + PERROR("dup"); } epoll_event[i].events = EPOLLIN | EPOLLPRI | EPOLLET; epoll_event[i].data.fd = fds[i]; ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], epoll_event); if (ret < 0) { - perror("[eppoll] add"); - goto end_unmap; + PERROR("[epoll_pwait] add"); + goto error_unmap; } } stop_thread = 0; @@ -764,55 +848,49 @@ void epoll_pwait_concurrent_munmap(void) (void *) epoll_event); if (ret != 0) { fprintf(stderr, "[error] pthread_create\n"); - goto end_unmap; + goto error_unmap; } ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL); if (ret == 1) { - printf("# [eppoll] data available\n"); ret = read(wait_fd, buf, BUF_SIZE); if (ret < 0) { - perror("[eppoll] read"); + PERROR("[epoll_pwait] read"); } - } else if (ret == 0) { - printf("# [eppoll] timeout\n"); - } else { - perror("# epoll_pwait"); + } else if (ret != 0) { + /* Expected error. */ } stop_thread = 1; ret = pthread_join(writer, NULL); if (ret) { fprintf(stderr, "[error] pthread_join\n"); - goto end_unmap; + goto error_unmap; } -end_unmap: +error_unmap: for (i = 0; i < MAX_FDS; i++) { ret = close(fds[i]); if (ret != 0) { - perror("close"); + PERROR("close"); } } ret = munmap(epoll_event, MAX_FDS * sizeof(struct epoll_event)); if (ret != 0) { - perror("munmap"); + PERROR("munmap"); } +error: + ret = close(epollfd); + if (ret) { + PERROR("close"); + } end: return; } -void usage(poptContext optCon, int exitcode, char *error, char *addl) -{ - poptPrintUsage(optCon, stderr, 0); - if (error) { - fprintf(stderr, "%s: %s\n", error, addl); - } - exit(exitcode); -} - +static void print_list(void) { fprintf(stderr, "Test list (-t X):\n"); @@ -844,15 +922,19 @@ int main(int argc, const char **argv) int c, ret, test = -1; poptContext optCon; struct rlimit open_lim; - + FILE *test_validation_output_file = NULL; + const char *test_validation_output_file_path = NULL; struct poptOption optionsTable[] = { { "test", 't', POPT_ARG_INT, &test, 0, "Test to run", NULL }, { "list", 'l', 0, 0, 'l', "List of tests (-t X)", NULL }, + { "validation-file", 'o', POPT_ARG_STRING, &test_validation_output_file_path, 0, + "Test case output", NULL }, POPT_AUTOHELP { NULL, 0, 0, NULL, 0 } }; + const struct test_case *test_case; optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); @@ -865,74 +947,75 @@ int main(int argc, const char **argv) ret = 0; while ((c = poptGetNextOpt(optCon)) >= 0) { - switch(c) { + switch (c) { case 'l': print_list(); goto end; } } + if (!test_validation_output_file_path) { + fprintf(stderr, "A test validation file path is required (--validation-file/-o)\n"); + ret = -1; + goto end; + } + + test_validation_output_file = fopen(test_validation_output_file_path, "w+"); + if (!test_validation_output_file) { + PERROR("Failed to create test validation output file at '%s'", + test_validation_output_file_path); + ret = -1; + goto end; + } + open_lim.rlim_cur = MAX_FDS + MIN_NR_FDS; open_lim.rlim_max = MAX_FDS + MIN_NR_FDS; ret = setrlimit(RLIMIT_NOFILE, &open_lim); if (ret < 0) { - perror("setrlimit"); + PERROR("setrlimit"); goto end; } /* * Some tests might segfault, but we need the getpid() to be output - * for the validation, disabling the buffering on stdout works. + * for the validation, disabling the buffering on the validation file + * works. */ - setbuf(stdout, NULL); - printf("%d\n", getpid()); - + setbuf(test_validation_output_file, NULL); wait_fd = STDIN_FILENO; - switch(test) { - case 1: - timeout = -1; - run_working_cases(); - break; - case 2: - timeout = 1; - run_working_cases(); - break; - case 3: - pselect_invalid_fd(); - break; - case 4: - test_ppoll_big(); - break; - case 5: - ppoll_fds_buffer_overflow(); - break; - case 6: - pselect_invalid_pointer(); - break; - case 7: - ppoll_fds_ulong_max(); - break; - case 8: - epoll_pwait_invalid_pointer(); - break; - case 9: - epoll_pwait_int_max(); - break; - case 10: - ppoll_concurrent_write(); - break; - case 11: - epoll_pwait_concurrent_munmap(); - break; - default: + /* Test case id is 1-based. */ + if (test < 1 || test > ARRAY_SIZE(test_cases)) { poptPrintUsage(optCon, stderr, 0); ret = -1; - break; } + test_case = &test_cases[test - 1]; + + timeout = test_case->timeout; + if (!test_case->produces_validation_info) { + /* + * All test cases need to provide, at minimum, the pid of the + * test application. + */ + ret = fprintf(test_validation_output_file, "{ \"pid\": %i }", getpid()); + if (ret < 0) { + PERROR("Failed to write application pid to test validation file"); + goto end; + } + } + + test_case->run(test_validation_output_file); + end: + if (test_validation_output_file) { + const int close_ret = fclose(test_validation_output_file); + + if (close_ret) { + PERROR("Failed to close test output file"); + } + } poptFreeContext(optCon); return ret; }