Clean-up: modernize pretty_xml.cpp
[lttng-tools.git] / tests / regression / kernel / select_poll_epoll.cpp
index 5dabf55b6e560d403374ee054981bfb101963aa3..b6f0210d503d24a03bf9e50235019d4b37c718be 100644 (file)
@@ -5,6 +5,18 @@
  *
  */
 
+/*
+ * This test voluntarily does buffer overflows and stack overruns, disable
+ * source fortification.
+ */
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+
+#include <common/compat/time.hpp>
+#include <common/error.hpp>
+
+#include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
 #include <poll.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <common/compat/time.hpp>
-#include <common/error.hpp>
-
 #define BUF_SIZE 256
-#define NB_FD 1
-#define MAX_FDS 2047
-#define NR_ITER 1000 /* for stress-tests */
+#define NB_FD   1
+#define MAX_FDS         2047
+#define NR_ITER         1000 /* for stress-tests */
 
-#define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */
+#define MIN_NR_FDS    5 /* the minimum number of open FDs required for the test to run */
 #define BIG_SELECT_FD 1022
 
 #define MSEC_PER_USEC 1000
@@ -47,11 +56,11 @@ static int wait_fd;
 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 pselect_invalid_fd(FILE *validation_output_file);
 static void ppoll_fds_ulong_max(FILE *validation_output_file);
+static void ppoll_fds_buffer_overflow(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);
@@ -59,32 +68,81 @@ static void epoll_pwait_concurrent_munmap(FILE *validation_output_file);
 
 typedef void (*test_case_cb)(FILE *output_file);
 
-static const struct test_case {
+namespace {
+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, .timeout = 0 },
-       { .run = test_ppoll_big, .produces_validation_info = false, .timeout = 0 },
-       { .run = ppoll_fds_buffer_overflow, .produces_validation_info = false, .timeout = 0 },
-       { .run = pselect_invalid_pointer, .produces_validation_info = false, .timeout = 0 },
-       { .run = ppoll_fds_ulong_max, .produces_validation_info = false, .timeout = 0 },
-       { .run = epoll_pwait_invalid_pointer, .produces_validation_info = true, .timeout = 0 },
-       { .run = epoll_pwait_int_max, .produces_validation_info = true, .timeout = 0 },
-       { .run = ppoll_concurrent_write, .produces_validation_info = false, .timeout = 0 },
-       { .run = epoll_pwait_concurrent_munmap, .produces_validation_info = true, .timeout = 0 },
+       const char *name;
+       const char *description;
+} test_cases[] = {
+       { .run = run_working_cases,
+         .produces_validation_info = true,
+         .timeout = -1,
+         .name = "working_cases",
+         .description =
+                 "Working cases for select, pselect6, poll, ppoll and epoll, waiting for input" },
+       { .run = run_working_cases,
+         .produces_validation_info = true,
+         .timeout = 1,
+         .name = "working_cases_timeout",
+         .description = "Timeout cases (1ms) for select, pselect6, poll, ppoll and epoll" },
+       { .run = test_ppoll_big,
+         .produces_validation_info = false,
+         .timeout = 0,
+         .name = "ppoll_big",
+         .description = "ppoll with " XSTR(MAX_FDS) " FDs" },
+       { .run = epoll_pwait_invalid_pointer,
+         .produces_validation_info = true,
+         .timeout = 0,
+         .name = "epoll_pwait_invalid_pointer",
+         .description = "epoll_pwait with an invalid pointer, waits for input" },
+       { .run = epoll_pwait_int_max,
+         .produces_validation_info = true,
+         .timeout = 0,
+         .name = "epoll_pwait_int_max",
+         .description = "epoll_pwait with maxevents set to INT_MAX waits for input" },
+       { .run = ppoll_concurrent_write,
+         .produces_validation_info = false,
+         .timeout = 0,
+         .name = "ppoll_concurrent_write",
+         .description =
+                 "ppoll with concurrent updates of the structure from user-space, stress test (3000 iterations) waits for input + timeout 1ms" },
+       { .run = epoll_pwait_concurrent_munmap,
+         .produces_validation_info = true,
+         .timeout = 0,
+         .name = "epoll_pwait_concurrent_munmap",
+         .description =
+                 "epoll_pwait with concurrent munmap of the buffer from user-space, should randomly segfault, run multiple times, waits for input + timeout 1ms" },
+       { .run = pselect_invalid_pointer,
+         .produces_validation_info = false,
+         .timeout = 0,
+         .name = "pselect_invalid_pointer",
+         .description = "pselect with an invalid pointer, waits for input" },
+       { .run = pselect_invalid_fd,
+         .produces_validation_info = false,
+         .timeout = 0,
+         .name = "pselect_invalid_fd",
+         .description = "pselect with an invalid fd" },
+       { .run = ppoll_fds_ulong_max,
+         .produces_validation_info = false,
+         .timeout = 0,
+         .name = "ppoll_fds_ulong_max",
+         .description = "ppoll with ulong_max fds, waits for input" },
+       { .run = ppoll_fds_buffer_overflow,
+         .produces_validation_info = false,
+         .timeout = 0,
+         .name = "ppoll_fds_buffer_overflow",
+         .description = "ppoll buffer overflow, should segfault, waits for input" },
 };
 
 struct ppoll_thread_data {
        struct pollfd *ufds;
        int value;
 };
+} /* namespace */
 
-static
-void test_select_big(void)
+static void test_select_big(void)
 {
        fd_set rfds, wfds, exfds;
        struct timeval tv;
@@ -130,8 +188,7 @@ end:
        return;
 }
 
-static
-void test_pselect(void)
+static void test_pselect_generic(long int syscall_id)
 {
        fd_set rfds;
        struct timespec tv;
@@ -145,9 +202,9 @@ void test_pselect(void)
        tv.tv_nsec = timeout * MSEC_PER_NSEC;
 
        if (timeout > 0) {
-               ret = pselect(1, &rfds, NULL, NULL, &tv, NULL);
+               ret = syscall(syscall_id, 1, &rfds, NULL, NULL, &tv, NULL);
        } else {
-               ret = pselect(1, &rfds, NULL, NULL, NULL, NULL);
+               ret = syscall(syscall_id, 1, &rfds, NULL, NULL, NULL, NULL);
        }
 
        if (ret == -1) {
@@ -160,8 +217,12 @@ void test_pselect(void)
        }
 }
 
-static
-void test_select(void)
+static void test_pselect(void)
+{
+       test_pselect_generic(SYS_pselect6);
+}
+
+static void test_select(void)
 {
        fd_set rfds;
        struct timeval tv;
@@ -190,15 +251,14 @@ void test_select(void)
        }
 }
 
-static
-void test_poll(void)
+static void test_poll(void)
 {
        struct pollfd ufds[NB_FD];
        char buf[BUF_SIZE];
        int ret;
 
        ufds[0].fd = wait_fd;
-       ufds[0].events = POLLIN|POLLPRI;
+       ufds[0].events = POLLIN | POLLPRI;
 
        ret = poll(ufds, 1, timeout);
 
@@ -212,8 +272,7 @@ void test_poll(void)
        }
 }
 
-static
-void test_ppoll(void)
+static void test_ppoll_generic(long int syscall_id)
 {
        struct pollfd ufds[NB_FD];
        char buf[BUF_SIZE];
@@ -221,17 +280,16 @@ void test_ppoll(void)
        struct timespec ts;
 
        ufds[0].fd = wait_fd;
-       ufds[0].events = POLLIN|POLLPRI;
+       ufds[0].events = POLLIN | POLLPRI;
 
        if (timeout > 0) {
                ts.tv_sec = 0;
                ts.tv_nsec = timeout * MSEC_PER_NSEC;
-               ret = ppoll(ufds, 1, &ts, NULL);
+               ret = syscall(syscall_id, ufds, 1, &ts, NULL);
        } else {
-               ret = ppoll(ufds, 1, NULL, NULL);
+               ret = syscall(syscall_id, ufds, 1, NULL, NULL);
        }
 
-
        if (ret < 0) {
                PERROR("ppoll");
        } else if (ret > 0) {
@@ -242,8 +300,12 @@ void test_ppoll(void)
        }
 }
 
-static
-void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
+static void test_ppoll(void)
+{
+       test_ppoll_generic(SYS_ppoll);
+}
+
+static void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
 {
        struct pollfd ufds[MAX_FDS];
        char buf[BUF_SIZE];
@@ -255,7 +317,7 @@ void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
                        PERROR("dup");
                }
                ufds[i].fd = fds[i];
-               ufds[i].events = POLLIN|POLLPRI;
+               ufds[i].events = POLLIN | POLLPRI;
        }
 
        ret = ppoll(ufds, MAX_FDS, NULL, NULL);
@@ -279,8 +341,7 @@ void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
        return;
 }
 
-static
-void test_epoll(FILE *validation_output_file)
+static void test_epoll(FILE *validation_output_file)
 {
        int ret, epollfd;
        char buf[BUF_SIZE];
@@ -292,8 +353,7 @@ void test_epoll(FILE *validation_output_file)
                goto end;
        }
 
-       ret = fprintf(validation_output_file,
-                       ", \"epoll_wait_fd\": %i", epollfd);
+       ret = fprintf(validation_output_file, ", \"epoll_wait_fd\": %i", epollfd);
        if (ret < 0) {
                PERROR("[epoll] Failed to write test validation output");
                goto error;
@@ -331,8 +391,7 @@ end:
        return;
 }
 
-static
-void test_epoll_pwait(FILE *validation_output_file)
+static void test_epoll_pwait(FILE *validation_output_file)
 {
        int ret, epollfd;
        char buf[BUF_SIZE];
@@ -344,8 +403,7 @@ void test_epoll_pwait(FILE *validation_output_file)
                goto end;
        }
 
-       ret = fprintf(validation_output_file,
-                       ", \"epoll_pwait_fd\": %i", epollfd);
+       ret = fprintf(validation_output_file, ", \"epoll_pwait_fd\": %i", epollfd);
        if (ret < 0) {
                PERROR("[epoll_pwait] Failed to write test validation output");
                goto error;
@@ -383,8 +441,7 @@ end:
        return;
 }
 
-static
-void run_working_cases(FILE *validation_output_file)
+static void run_working_cases(FILE *validation_output_file)
 {
        int ret;
        int pipe_fds[2];
@@ -403,12 +460,21 @@ void run_working_cases(FILE *validation_output_file)
                wait_fd = pipe_fds[0];
        }
        test_select();
+#ifdef sys_pselect6_time64
+       test_pselect_time64();
+#else
        test_pselect();
+#endif /* sys_pselect6_time64 */
        test_select_big();
        test_poll();
        test_ppoll();
+#ifdef sys_ppoll_time64
+       test_ppoll_time64();
+#else
+       test_ppoll();
+#endif /* sys_ppoll_time64 */
 
-       ret = fprintf(validation_output_file, "{ \"pid\": %i", getpid());
+       ret = fprintf(validation_output_file, "{\"pid\": %i", getpid());
        if (ret < 0) {
                PERROR("Failed to write pid to test validation file");
                goto end;
@@ -439,65 +505,80 @@ end:
 }
 
 /*
- * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
- * segfault (eventually with a "*** stack smashing detected ***" message).
- * The event should contain an array of 100 FDs filled with garbage.
+ * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
+ * cleanly fail with a "Invalid argument".
+ * The event should contain an empty array of FDs and overflow = 1.
  */
-static
-void ppoll_fds_buffer_overflow(
-               FILE *validation_output_file __attribute__((unused)))
+static void generic_ppoll_fds_ulong_max(long int syscall_id)
 {
        struct pollfd ufds[NB_FD];
        char buf[BUF_SIZE];
        int ret;
 
        ufds[0].fd = wait_fd;
-       ufds[0].events = POLLIN|POLLPRI;
-
-       ret = syscall(SYS_ppoll, ufds, 100, NULL, NULL);
+       ufds[0].events = POLLIN | POLLPRI;
 
+       /* ppoll and/or ppoll_time64 are used, depending on platform support. */
+       ret = syscall(syscall_id, ufds, ULONG_MAX, NULL, NULL);
        if (ret < 0) {
-               PERROR("ppoll");
+               /* Expected error. */
        } else if (ret > 0) {
                ret = read(wait_fd, buf, BUF_SIZE);
                if (ret < 0) {
-                       PERROR("[ppoll] read");
+                       PERROR("Failed to read from wait file descriptor");
                }
        }
 }
 
 /*
- * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
- * cleanly fail with a "Invalid argument".
- * The event should contain an empty array of FDs and overflow = 1.
+ * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
+ * segfault (eventually with a "*** stack smashing detected ***" message).
+ * The event should contain an array of 100 FDs filled with garbage.
  */
-static
-void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused)))
+static void generic_ppoll_fds_buffer_overflow(long int syscall_id)
 {
        struct pollfd ufds[NB_FD];
        char buf[BUF_SIZE];
        int ret;
 
        ufds[0].fd = wait_fd;
-       ufds[0].events = POLLIN|POLLPRI;
+       ufds[0].events = POLLIN | POLLPRI;
 
-       ret = syscall(SYS_ppoll, ufds, ULONG_MAX, NULL, NULL);
+       /* ppoll and/or ppoll_time64 are used, depending on platform support. */
+       ret = syscall(syscall_id, ufds, 100, NULL, NULL);
        if (ret < 0) {
-               /* Expected error. */
+               PERROR("Failed to wait using ppoll/ppoll_time64");
        } else if (ret > 0) {
                ret = read(wait_fd, buf, BUF_SIZE);
                if (ret < 0) {
-                       PERROR("[ppoll] read");
+                       PERROR("Failed to read from wait file descriptor");
                }
        }
 }
 
+static void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused)))
+{
+#ifdef SYS_ppoll_time64
+       generic_ppoll_fds_ulong_max(SYS_ppoll_time64);
+#else
+       generic_ppoll_fds_ulong_max(SYS_ppoll);
+#endif /* SYS_ppoll_time64 */
+}
+
+static void ppoll_fds_buffer_overflow(FILE *validation_output_file __attribute__((unused)))
+{
+#ifdef SYS_ppoll_time64
+       generic_ppoll_fds_buffer_overflow(SYS_ppoll_time64);
+#else
+       generic_ppoll_fds_buffer_overflow(SYS_ppoll);
+#endif /* SYS_ppoll_time64 */
+}
+
 /*
  * Pass an invalid file descriptor to pselect6(). The syscall should return
  * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
  */
-static
-void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
+static void generic_invalid_fd(long int syscall_id)
 {
        fd_set rfds;
        int ret;
@@ -509,26 +590,26 @@ void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
         */
        fd = open("/dev/null", O_RDONLY);
        if (fd == -1) {
-               PERROR("open");
+               PERROR("Failed to open /dev/null");
                goto error;
        }
 
        ret = close(fd);
        if (ret == -1) {
-               PERROR("close");
+               PERROR("Failed to close /dev/null file descriptor");
                goto error;
        }
 
        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);
 
-       ret = syscall(SYS_pselect6, fd + 1, &rfds, NULL, NULL, NULL, NULL);
+       ret = syscall(syscall_id, fd + 1, &rfds, NULL, NULL, NULL, NULL);
        if (ret == -1) {
                /* Expected error. */
        } else if (ret) {
                ret = read(wait_fd, buf, BUF_SIZE);
                if (ret < 0) {
-                       PERROR("[pselect] read");
+                       PERROR("Failed to read from wait file descriptor");
                }
        }
 error:
@@ -539,9 +620,7 @@ error:
  * Invalid pointer as writefds, should output a ppoll event
  * with 0 FDs.
  */
-static
-void pselect_invalid_pointer(
-               FILE *validation_output_file __attribute__((unused)))
+static void generic_invalid_pointer(int syscall_id)
 {
        fd_set rfds;
        int ret;
@@ -551,24 +630,44 @@ void pselect_invalid_pointer(
        FD_ZERO(&rfds);
        FD_SET(wait_fd, &rfds);
 
-       ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL,
-                       NULL);
+       ret = syscall(syscall_id, 1, &rfds, (fd_set *) invalid, NULL, NULL, NULL);
        if (ret == -1) {
                /* Expected error. */
        } else if (ret) {
                ret = read(wait_fd, buf, BUF_SIZE);
                if (ret < 0) {
-                       PERROR("[pselect] read");
+                       PERROR("Failed to read from wait file descriptor");
                }
        }
 }
 
+static void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
+{
+#ifdef SYS_pselect6_time64
+       generic_invalid_fd(SYS_pselect6_time64);
+#else
+       generic_invalid_fd(SYS_pselect6);
+#endif /* SYS_pselect6_time64 */
+}
+
+/*
+ * Invalid pointer as writefds, should output a ppoll event
+ * with 0 FDs.
+ */
+static void pselect_invalid_pointer(FILE *validation_output_file __attribute__((unused)))
+{
+#ifdef SYS_pselect6_time64
+       generic_invalid_pointer(SYS_pselect6_time64);
+#else
+       generic_invalid_pointer(SYS_pselect6);
+#endif /* SYS_pselect6_time64 */
+}
+
 /*
  * Pass an invalid pointer to epoll_pwait, should fail with
  * "Bad address", the event returns 0 FDs.
  */
-static
-void epoll_pwait_invalid_pointer(FILE *validation_output_file)
+static void epoll_pwait_invalid_pointer(FILE *validation_output_file)
 {
        int ret, epollfd;
        char buf[BUF_SIZE];
@@ -581,9 +680,7 @@ void epoll_pwait_invalid_pointer(FILE *validation_output_file)
                goto end;
        }
 
-       ret = fprintf(validation_output_file,
-                       "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
-                       getpid());
+       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;
@@ -597,8 +694,7 @@ void epoll_pwait_invalid_pointer(FILE *validation_output_file)
                goto error;
        }
 
-       ret = syscall(SYS_epoll_pwait, epollfd,
-                       (struct epoll_event *) invalid, 1, -1, NULL);
+       ret = syscall(SYS_epoll_pwait, epollfd, (struct epoll_event *) invalid, 1, -1, NULL);
 
        if (ret == 1) {
                ret = read(wait_fd, buf, BUF_SIZE);
@@ -622,8 +718,7 @@ end:
  * Set maxevents to INT_MAX, should output "Invalid argument"
  * The event should return an empty array.
  */
-static
-void epoll_pwait_int_max(FILE *validation_output_file)
+static void epoll_pwait_int_max(FILE *validation_output_file)
 {
        int ret, epollfd;
        char buf[BUF_SIZE];
@@ -635,9 +730,7 @@ void epoll_pwait_int_max(FILE *validation_output_file)
                goto end;
        }
 
-       ret = fprintf(validation_output_file,
-                       "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
-                       getpid());
+       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;
@@ -651,8 +744,7 @@ void epoll_pwait_int_max(FILE *validation_output_file)
                goto error;
        }
 
-       ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1,
-                       NULL);
+       ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1, NULL);
 
        if (ret == 1) {
                ret = read(wait_fd, buf, BUF_SIZE);
@@ -672,22 +764,19 @@ end:
        return;
 }
 
-static
-void *ppoll_writer(void *arg)
+static void *ppoll_writer(void *arg)
 {
        struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg;
 
        while (!stop_thread) {
-               memset(data->ufds, data->value,
-                               MAX_FDS * sizeof(struct pollfd));
+               memset(data->ufds, data->value, MAX_FDS * sizeof(struct pollfd));
                usleep(100);
        }
 
        return NULL;
 }
 
-static
-void do_ppoll(int *fds, struct pollfd *ufds)
+static void do_ppoll(int *fds, struct pollfd *ufds)
 {
        int i, ret;
        struct timespec ts;
@@ -698,7 +787,7 @@ void do_ppoll(int *fds, struct pollfd *ufds)
 
        for (i = 0; i < MAX_FDS; i++) {
                ufds[i].fd = fds[i];
-               ufds[i].events = POLLIN|POLLPRI;
+               ufds[i].events = POLLIN | POLLPRI;
        }
 
        ret = ppoll(ufds, MAX_FDS, &ts, NULL);
@@ -713,8 +802,7 @@ void do_ppoll(int *fds, struct pollfd *ufds)
        }
 }
 
-static
-void stress_ppoll(int *fds, int value)
+static void stress_ppoll(int *fds, int value)
 {
        pthread_t writer;
        int iter, ret;
@@ -755,9 +843,7 @@ end:
  *
  * ppoll should work as expected and the trace should be readable at the end.
  */
-static
-void ppoll_concurrent_write(
-               FILE *validation_output_file __attribute__((unused)))
+static void ppoll_concurrent_write(FILE *validation_output_file __attribute__((unused)))
 {
        int i, ret, fds[MAX_FDS];
 
@@ -782,8 +868,7 @@ void ppoll_concurrent_write(
        return;
 }
 
-static
-void *epoll_pwait_writer(void *addr)
+static void *epoll_pwait_writer(void *addr)
 {
        srand(time(NULL));
 
@@ -800,8 +885,7 @@ 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.
  */
-static
-void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
+static void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
 {
        int ret, epollfd, i, fds[MAX_FDS];
        char buf[BUF_SIZE];
@@ -817,18 +901,18 @@ void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
                goto end;
        }
 
-       ret = fprintf(validation_output_file,
-                       "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
-                       getpid());
+       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);
+                                                 MAX_FDS * sizeof(struct epoll_event),
+                                                 PROT_READ | PROT_WRITE,
+                                                 MAP_PRIVATE | MAP_ANONYMOUS,
+                                                 -1,
+                                                 0);
        if (epoll_event == MAP_FAILED) {
                PERROR("mmap");
                goto error;
@@ -848,8 +932,7 @@ void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
                }
        }
        stop_thread = 0;
-       ret = pthread_create(&writer, NULL, &epoll_pwait_writer,
-                       (void *) epoll_event);
+       ret = pthread_create(&writer, NULL, &epoll_pwait_writer, (void *) epoll_event);
        if (ret != 0) {
                fprintf(stderr, "[error] pthread_create\n");
                goto error_unmap;
@@ -894,51 +977,85 @@ end:
        return;
 }
 
-static
-void print_list(void)
+static void print_list(void)
+{
+       printf("Test list (-t X):\n");
+
+       for (size_t test_id = 0; test_id < ARRAY_SIZE(test_cases); test_id++) {
+               printf("\t%zu: %s - %s\n",
+                      test_id + 1,
+                      test_cases[test_id].name,
+                      test_cases[test_id].description);
+       }
+}
+
+static void print_test_syscalls(void)
 {
-       fprintf(stderr, "Test list (-t X):\n");
-       fprintf(stderr, "\t1: Working cases for select, pselect6, poll, ppoll "
-                       "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 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 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 an invalid pointer, waits for "
-                       "input\n");
-       fprintf(stderr, "\t9: epoll_pwait with maxevents set to INT_MAX, "
-                       "waits for input\n");
-       fprintf(stderr, "\t10: ppoll with concurrent updates of the structure "
-                       "from user-space, stress test (3000 iterations), "
-                       "waits for input + timeout 1ms\n");
-       fprintf(stderr, "\t11: epoll_pwait with concurrent munmap of the buffer "
-                       "from user-space, should randomly segfault, run "
-                       "multiple times, waits for input + timeout 1ms\n");
+       const char *supported_syscalls[] = {
+#ifdef SYS_select
+               "select",
+#endif
+#if defined SYS_pselect6_time64 && defined SYS_pselect6
+               "pselect6",
+               "pselect6_time32",
+#elif defined SYS_pselect6_time32 ^ defined SYS_pselect6
+               "pselect6",
+#endif /* SYS_pselect6_time64 && defined SYS_pselect6 */
+#ifdef SYS_poll
+               "poll",
+#endif
+#if defined SYS_ppoll && defined SYS_ppoll_time64
+               "ppoll",
+               "ppoll_time32",
+#elif defined SYS_ppoll ^ defined SYS_ppoll_time64
+               "ppoll",
+#endif /* defined SYS_ppoll && defined SYS_ppoll_time64 */
+#ifdef SYS_epoll_ctl
+               "epoll_ctl",
+#endif
+#ifdef SYS_epoll_wait
+               "epoll_wait",
+#endif
+#ifdef SYS_epoll_pwait
+               "epoll_pwait",
+#endif
+       };
+
+       for (size_t i = 0; i < ARRAY_SIZE(supported_syscalls); i++) {
+               fputs(supported_syscalls[i], stdout);
+               fputs(i != ARRAY_SIZE(supported_syscalls) - 1 ? "," : "\n", stdout);
+       }
 }
 
 int main(int argc, const char **argv)
 {
-       int c, ret, test = -1;
+       int c, ret;
+       const char *test_name;
        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, NULL, NULL }
+               { "test", 't', POPT_ARG_STRING, &test_name, 0, "Name of test to run", NULL },
+               { "list-tests", 'l', 0, 0, 'l', "List tests (-t X)", NULL },
+               { "list-supported-test-syscalls",
+                 's',
+                 0,
+                 0,
+                 's',
+                 "List supported test syscalls",
+                 NULL },
+               { "validation-file",
+                 'o',
+                 POPT_ARG_STRING,
+                 &test_validation_output_file_path,
+                 0,
+                 "Test case output",
+                 NULL },
+               POPT_AUTOHELP{ NULL, 0, 0, NULL, 0, NULL, NULL }
        };
        const struct test_case *test_case;
+       size_t test_case_id;
 
        optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
 
@@ -955,6 +1072,9 @@ int main(int argc, const char **argv)
                case 'l':
                        print_list();
                        goto end;
+               case 's':
+                       print_test_syscalls();
+                       goto end;
                }
        }
 
@@ -967,7 +1087,7 @@ int main(int argc, const char **argv)
        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);
+                      test_validation_output_file_path);
                ret = -1;
                goto end;
        }
@@ -990,12 +1110,19 @@ int main(int argc, const char **argv)
        wait_fd = STDIN_FILENO;
 
        /* Test case id is 1-based. */
-       if (test < 1 || test > ARRAY_SIZE(test_cases)) {
+       for (test_case_id = 0; test_case_id < ARRAY_SIZE(test_cases); test_case_id++) {
+               if (!strcmp(test_cases[test_case_id].name, test_name)) {
+                       break;
+               }
+       }
+
+       if (test_case_id == ARRAY_SIZE(test_cases)) {
                poptPrintUsage(optCon, stderr, 0);
                ret = -1;
+               goto end;
        }
 
-       test_case = &test_cases[test - 1];
+       test_case = &test_cases[test_case_id];
 
        timeout = test_case->timeout;
        if (!test_case->produces_validation_info) {
@@ -1003,7 +1130,7 @@ int main(int argc, const char **argv)
                 * All test cases need to provide, at minimum, the pid of the
                 * test application.
                 */
-               ret = fprintf(test_validation_output_file, "{ \"pid\": %i }", getpid());
+               ret = fprintf(test_validation_output_file, "{\"pid\": %i }", getpid());
                if (ret < 0) {
                        PERROR("Failed to write application pid to test validation file");
                        goto end;
This page took 0.033083 seconds and 4 git commands to generate.