Tests: fix: select_poll_epoll: test assumes epoll fd value
[lttng-tools.git] / tests / regression / kernel / select_poll_epoll.c
index dfb52370bf761a050ca68ac64a8f88ae42411d1b..abedc0aa929557c7aa859e76788d71d53e0f0cb4 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * Copyright (C) 2016 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
 #include <stdio.h>
 #include <poll.h>
 #include <signal.h>
@@ -17,7 +24,8 @@
 #include <limits.h>
 #include <pthread.h>
 #include <sys/mman.h>
-#include <time.h>
+#include <common/compat/time.h>
+#include <common/error.h>
 
 #define BUF_SIZE 256
 #define NB_FD 1
 #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,65 +480,65 @@ 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;
 }
 
 /*
- * Select is limited to 1024 FDs, should output a pselect event
- * with 0 FDs.
+ * Pass an invalid file descriptor to pselect6(). The syscall should return
+ * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
  */
-void pselect_fd_too_big(void)
+static
+void pselect_invalid_fd(FILE *validation_output_file)
 {
-       long rfds[2048 / (sizeof(long) * CHAR_BIT)] = { 0 };
+       fd_set rfds;
        int ret;
-       int fd2;
+       int fd;
        char buf[BUF_SIZE];
 
        /*
-        * Test if nfds > 1024.
-        * Make sure ulimit is set correctly (ulimit -n 2048).
+        * Open a file, close it and use the closed FD in the pselect6 call.
         */
-       fd2 = dup2(wait_fd, 2047);
-       if (fd2 != 2047) {
-               perror("dup2");
-               return;
+       fd = open("/dev/null", O_RDONLY);
+       if (fd == -1) {
+               PERROR("open");
+               goto error;
        }
 
-       FD_SET(fd2, (fd_set *) &rfds);
-       ret = syscall(SYS_pselect6, fd2 + 1, &rfds, NULL, NULL, NULL, NULL);
+       ret = close(fd);
+       if (ret == -1) {
+               PERROR("close");
+               goto error;
+       }
+
+       FD_ZERO(&rfds);
+       FD_SET(fd, &rfds);
 
+       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;
 }
 
 /*
  * 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;
@@ -490,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];
@@ -518,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;
 }
@@ -553,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];
@@ -561,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;
@@ -605,6 +683,7 @@ void *ppoll_writer(void *arg)
        return NULL;
 }
 
+static
 void do_ppoll(int *fds, struct pollfd *ufds)
 {
        int i, ret;
@@ -622,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;
@@ -675,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");
                }
        }
 
@@ -693,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));
@@ -717,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;
@@ -756,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");
@@ -812,14 +898,14 @@ void print_list(void)
                        "and epoll, waiting for input\n");
        fprintf(stderr, "\t2: Timeout cases (1ms) for select, pselect6, poll, "
                        "ppoll and epoll\n");
-       fprintf(stderr, "\t3: pselect with a FD > 1023\n");
+       fprintf(stderr, "\t3: pselect with an invalid fd\n");
        fprintf(stderr, "\t4: ppoll with %d FDs\n", MAX_FDS);
        fprintf(stderr, "\t5: ppoll buffer overflow, should segfault, waits "
                        "for input\n");
-       fprintf(stderr, "\t6: pselect with invalid pointer, waits for "
+       fprintf(stderr, "\t6: pselect with an invalid pointer, waits for "
                        "input\n");
        fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n");
-       fprintf(stderr, "\t8: epoll_pwait with invalid pointer, waits for "
+       fprintf(stderr, "\t8: epoll_pwait with an invalid pointer, waits for "
                        "input\n");
        fprintf(stderr, "\t9: epoll_pwait with maxevents set to INT_MAX, "
                        "waits for input\n");
@@ -836,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);
 
@@ -857,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_fd_too_big();
-               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;
 }
This page took 0.036379 seconds and 4 git commands to generate.