[lttng-dev] [PATCH lttng-tools v3] Test for select, poll and epoll syscall overrides

Jérémie Galarneau jeremie.galarneau at efficios.com
Tue Jun 28 18:31:31 UTC 2016


On Thu, May 12, 2016 at 5:21 PM, Julien Desfossez
<jdesfossez at efficios.com> wrote:
> This test for root_regression checks if the syscall overrides for
> select, pselect6, poll, ppoll, epoll_ctl, epoll_wait and epoll_pwait
> work as expected on arm and x86 (32 and 64-bit).
>
> There are 11 test cases that check for normal and abnormal behaviour. If
> the test system has the Babeltrace python bindings, the test validates
> the content of the events, otherwise only the presence of the generated
> events is checked.
>
> We also check if kernel OOPS, WARNING or BUG were generated during the
> test.
>
> Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
> ---
>  tests/regression/kernel/Makefile.am                |   7 +-
>  tests/regression/kernel/select_poll_epoll.c        | 904 +++++++++++++++++++++
>  tests/regression/kernel/test_select_poll_epoll     | 398 +++++++++
>  .../kernel/validate_select_poll_epoll.py           | 783 ++++++++++++++++++
>  tests/root_regression                              |   1 +
>  5 files changed, 2092 insertions(+), 1 deletion(-)
>  create mode 100644 tests/regression/kernel/select_poll_epoll.c
>  create mode 100755 tests/regression/kernel/test_select_poll_epoll
>  create mode 100755 tests/regression/kernel/validate_select_poll_epoll.py
>
> diff --git a/tests/regression/kernel/Makefile.am b/tests/regression/kernel/Makefile.am
> index 36ff6ee..023c4c6 100644
> --- a/tests/regression/kernel/Makefile.am
> +++ b/tests/regression/kernel/Makefile.am
> @@ -1,4 +1,9 @@
> -EXTRA_DIST = test_event_basic test_all_events test_syscall
> +noinst_PROGRAMS = select_poll_epoll
> +select_poll_epoll_SOURCES = select_poll_epoll.c
> +select_poll_epoll_LDADD = -lpthread -lpopt
> +select_poll_epoll_CFLAGS = -fno-stack-protector -D_FORTIFY_SOURCE=0
> +
> +EXTRA_DIST = test_event_basic test_all_events test_syscall test_select_poll_epoll
>
>  all-local:
>         @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
> diff --git a/tests/regression/kernel/select_poll_epoll.c b/tests/regression/kernel/select_poll_epoll.c
> new file mode 100644
> index 0000000..d99c2f6
> --- /dev/null
> +++ b/tests/regression/kernel/select_poll_epoll.c
> @@ -0,0 +1,904 @@
> +#include <stdio.h>
> +#include <poll.h>
> +#include <signal.h>
> +#include <unistd.h>
> +#include <sys/syscall.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stddef.h>
> +#include <sys/select.h>
> +#include <sys/epoll.h>
> +#include <popt.h>
> +#include <sys/time.h>
> +#include <sys/resource.h>
> +#include <limits.h>
> +#include <pthread.h>
> +#include <sys/mman.h>
> +#include <time.h>
> +
> +#define BUF_SIZE 256
> +#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 BIG_SELECT_FD 1022
> +
> +#define MSEC_PER_USEC 1000
> +#define MSEC_PER_NSEC (MSEC_PER_USEC * 1000)
> +
> +static int timeout; /* seconds, -1 to disable */
> +static int stop_thread;
> +static int wait_fd;
> +
> +struct ppoll_thread_data {
> +       struct pollfd *ufds;
> +       int value;
> +};
> +
> +void test_select_big(void)
> +{
> +       fd_set rfds, wfds, exfds;
> +       struct timeval tv;
> +       int ret;
> +       int fd2;
> +       char buf[BUF_SIZE];
> +
> +       FD_ZERO(&rfds);
> +       FD_ZERO(&wfds);
> +       FD_ZERO(&exfds);
> +
> +       fd2 = dup2(wait_fd, BIG_SELECT_FD);
> +       if (fd2 < 0) {
> +               perror("dup2");
> +               goto end;
> +       }
> +       FD_SET(fd2, &rfds);
> +
> +       tv.tv_sec = 0;
> +       tv.tv_usec = timeout * MSEC_PER_USEC;
> +
> +       if (timeout > 0) {
> +               ret = select(fd2 + 1, &rfds, &wfds, &exfds, &tv);
> +       } else {
> +               ret = select(fd2 + 1, &rfds, &wfds, &exfds, NULL);
> +       }
> +
> +       if (ret == -1) {
> +               perror("select()");
> +       } else if (ret) {
> +               printf("# [select] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[select] read");
> +               }
> +       } else {
> +               printf("# [select] timeout\n");
> +       }
> +
> +       ret = close(BIG_SELECT_FD);
> +       if (ret)
> +               perror("close");
> +
> +end:
> +       return;
> +}
> +
> +void test_pselect(void)
> +{
> +       fd_set rfds;
> +       struct timespec tv;
> +       int ret;
> +       char buf[BUF_SIZE];
> +
> +       FD_ZERO(&rfds);
> +       FD_SET(wait_fd, &rfds);
> +
> +       tv.tv_sec = 0;
> +       tv.tv_nsec = timeout * MSEC_PER_NSEC;
> +
> +       if (timeout > 0) {
> +               ret = pselect(1, &rfds, NULL, NULL, &tv, NULL);
> +       } else {
> +               ret = pselect(1, &rfds, NULL, NULL, NULL, NULL);
> +       }
> +
> +       if (ret == -1) {
> +               perror("pselect()");
> +       } else if (ret) {
> +               printf("# [pselect] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[pselect] read");
> +               }
> +       } else {
> +               printf("# [pselect] timeout\n");
> +       }
> +
> +}
> +
> +void test_select(void)
> +{
> +       fd_set rfds;
> +       struct timeval tv;
> +       int ret;
> +       char buf[BUF_SIZE];
> +
> +       FD_ZERO(&rfds);
> +       FD_SET(wait_fd, &rfds);
> +
> +       tv.tv_sec = 0;
> +       tv.tv_usec = timeout * MSEC_PER_USEC;
> +
> +       if (timeout > 0) {
> +               ret = select(1, &rfds, NULL, NULL, &tv);
> +       } else {
> +               ret = select(1, &rfds, NULL, NULL, NULL);
> +       }
> +
> +       if (ret == -1) {
> +               perror("select()");
> +       } else if (ret) {
> +               printf("# [select] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[select] read");
> +               }
> +       } else {
> +               printf("# [select] timeout\n");
> +       }
> +
> +}
> +
> +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;
> +
> +       ret = poll(ufds, 1, timeout);
> +
> +       if (ret < 0) {
> +               perror("poll");
> +       } else if (ret > 0) {
> +               printf("# [poll] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[poll] read");
> +               }
> +       } else {
> +               printf("# [poll] timeout\n");
> +       }
> +}
> +
> +void test_ppoll(void)
> +{
> +       struct pollfd ufds[NB_FD];
> +       char buf[BUF_SIZE];
> +       int ret;
> +       struct timespec ts;
> +
> +       ufds[0].fd = wait_fd;
> +       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);
> +       } else {
> +               ret = ppoll(ufds, 1, NULL, NULL);
> +       }
> +
> +
> +       if (ret < 0) {
> +               perror("ppoll");
> +       } else if (ret > 0) {
> +               printf("# [ppoll] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[ppoll] read");
> +               }
> +       } else {
> +               printf("# [ppoll] timeout\n");
> +       }
> +}
> +
> +void test_ppoll_big(void)
> +{
> +       struct pollfd ufds[MAX_FDS];
> +       char buf[BUF_SIZE];
> +       int ret, i, fds[MAX_FDS];
> +
> +       for (i = 0; i < MAX_FDS; i++) {
> +               fds[i] = dup(wait_fd);
> +               if (fds[i] < 0)
> +                       perror("dup");

Use braces on single-line conditions.

> +               ufds[i].fd = fds[i];
> +               ufds[i].events = POLLIN|POLLPRI;
> +       }
> +
> +       ret = ppoll(ufds, MAX_FDS, NULL, NULL);
> +
> +       if (ret < 0) {
> +               perror("ppoll");
> +       } else if (ret > 0) {
> +               printf("# [ppoll] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[ppoll] read");
> +               }
> +       } else {
> +               printf("# [ppoll] timeout\n");
> +       }
> +
> +       for (i = 0; i < MAX_FDS; i++) {
> +               ret = close(fds[i]);
> +               if (ret != 0)
> +                       perror("close");

Use braces on single-line conditions.

> +       }
> +

Remove trailing tab.

> +       return;
> +}
> +
> +void test_epoll(void)
> +{
> +       int ret, epollfd;
> +       char buf[BUF_SIZE];
> +       struct epoll_event epoll_event;
> +
> +       epollfd = epoll_create(NB_FD);
> +       if (epollfd < 0) {
> +               perror("[epoll] create");
> +               goto end;
> +       }
> +
> +       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;
> +       }
> +
> +       if (timeout > 0) {
> +               ret = epoll_wait(epollfd, &epoll_event, 1, timeout);
> +       } else {
> +               ret = epoll_wait(epollfd, &epoll_event, 1, -1);
> +       }
> +
> +       if (ret == 1) {
> +               printf("# [epoll] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[epoll] read");
> +               }
> +       } else if (ret == 0) {
> +               printf("# [epoll] timeout\n");
> +       } else {
> +               perror("epoll_wait");
> +       }
> +
> +end:
> +       return;
> +}
> +
> +void test_pepoll(void)
> +{
> +       int ret, epollfd;
> +       char buf[BUF_SIZE];
> +       struct epoll_event epoll_event;
> +
> +       epollfd = epoll_create(NB_FD);
> +       if (epollfd < 0) {
> +               perror("[eppoll] create");
> +               goto end;
> +       }
> +
> +       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;
> +       }
> +
> +       if (timeout > 0) {
> +               ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, NULL);
> +       } else {
> +               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");
> +               }
> +       } else if (ret == 0) {
> +               printf("# [eppoll] timeout\n");
> +       } else {
> +               perror("epoll_pwait");
> +       }
> +
> +end:
> +       return;
> +}
> +
> +void should_work(void)

Something like "run_working_cases()" seems clearer here? Better names
are welcome :-)

> +{
> +       int ret;
> +       int pipe_fds[2];
> +
> +       if (timeout > 0) {
> +               /*
> +                * When launched with the run.sh script, stdin randomly
> +                * receives some garbage that make the timeout cases
> +                * fail, use a dummy pipe for this test.

I'm not sure what you mean here.

> +                */
> +               ret = pipe(pipe_fds);
> +               if (ret != 0) {
> +                       perror("pipe");
> +                       goto end;
> +               }
> +               wait_fd = pipe_fds[0];
> +       }
> +       test_select();
> +       test_pselect();
> +       test_select_big();
> +       test_poll();
> +       test_ppoll();
> +       test_epoll();
> +       test_pepoll();
> +
> +       if (timeout > 0) {
> +               ret = close(pipe_fds[0]);
> +               if (ret)
> +                       perror("close");

Use braces on single-line conditions.

> +               ret = close(pipe_fds[1]);
> +               if (ret)
> +                       perror("close");

Use braces on single-line conditions.

> +       }
> +
> +end:
> +       return;
> +}
> +
> +/*
> + * 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.
> + */
> +void ppoll_fds_buffer_overflow(void)
> +{
> +       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);
> +
> +       if (ret < 0) {
> +               perror("ppoll");
> +       } else if (ret > 0) {
> +               printf("# [ppoll] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[ppoll] read");
> +               }
> +       } else {
> +               printf("# [ppoll] timeout\n");
> +       }
> +
> +       return;
> +}
> +
> +/*
> + * 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.
> + */
> +void ppoll_fds_ulong_max(void)
> +{
> +       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, ULONG_MAX, NULL, NULL);
> +
> +       if (ret < 0) {
> +               perror("# ppoll");
> +       } else if (ret > 0) {
> +               printf("# [ppoll] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[ppoll] read");
> +               }
> +       } else {
> +               printf("# [ppoll] timeout\n");
> +       }
> +
> +       return;
> +}
> +
> +/*
> + * Select is limited to 1024 FDs, should output a pselect event
> + * with 0 FDs.
> + */
> +void pselect_fd_too_big(void)
> +{
> +       fd_set rfds;
> +       int ret;
> +       int fd2;
> +       char buf[BUF_SIZE];
> +
> +       /*
> +        * Test if nfds > 1024.
> +        * Make sure ulimit is set correctly (ulimit -n 2048).
> +        */
> +       fd2 = dup2(wait_fd, 2047);
> +       if (fd2 != 2047) {
> +               perror("dup2");
> +               return;
> +       }
> +       FD_ZERO(&rfds);
> +       FD_SET(fd2, &rfds);
> +
> +       ret = syscall(SYS_pselect6, fd2 + 1, &rfds, NULL, NULL, NULL, NULL);
> +
> +       if (ret == -1) {
> +               perror("# pselect()");
> +       } else if (ret) {
> +               printf("# [pselect] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[pselect] read");
> +               }
> +       } else {
> +               printf("# [pselect] timeout\n");
> +       }
> +
> +}
> +
> +/*
> + * Invalid pointer as writefds, should output a ppoll event
> + * with 0 FDs.
> + */
> +void pselect_invalid_pointer(void)
> +{
> +       fd_set rfds;
> +       int ret;
> +       char buf[BUF_SIZE];
> +       void *invalid = (void *) 0x42;
> +
> +       FD_ZERO(&rfds);
> +       FD_SET(wait_fd, &rfds);
> +
> +       ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL,
> +                       NULL);
> +
> +       if (ret == -1) {
> +               perror("# pselect()");
> +       } else if (ret) {
> +               printf("# [pselect] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       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)
> +{
> +       int ret, epollfd;
> +       char buf[BUF_SIZE];
> +       struct epoll_event epoll_event;
> +       void *invalid = (void *) 0x42;
> +
> +       epollfd = epoll_create(NB_FD);
> +       if (epollfd < 0) {
> +               perror("[eppoll] create");
> +               goto end;
> +       }
> +
> +       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;
> +       }
> +
> +       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");
> +               }
> +       } else if (ret == 0) {
> +               printf("# [eppoll] timeout\n");
> +       } else {
> +               perror("# epoll_pwait");
> +       }
> +
> +end:
> +       return;
> +}
> +
> +/*
> + * Set maxevents to INT_MAX, should output "Invalid argument"
> + * The event should return an empty array.
> + */
> +void epoll_pwait_int_max(void)
> +{
> +       int ret, epollfd;
> +       char buf[BUF_SIZE];
> +       struct epoll_event epoll_event;
> +
> +       epollfd = epoll_create(NB_FD);
> +       if (epollfd < 0) {
> +               perror("[eppoll] create");
> +               goto end;
> +       }
> +
> +       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;
> +       }
> +
> +       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");
> +               }
> +       } else if (ret == 0) {
> +               printf("# [eppoll] timeout\n");
> +       } else {
> +               perror("# epoll_pwait");
> +       }
> +
> +end:
> +       return;
> +}
> +
> +void *ppoll_writer(void *arg)
> +{
> +       struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg;
> +
> +       while (!stop_thread) {

stop_thread should be declared "volatile" to ensure compiler
optimizations don't cache its value.

> +               memset(data->ufds, data->value,
> +                               MAX_FDS * sizeof(struct pollfd));
> +               usleep(100);
> +       }
> +
> +       return NULL;
> +}
> +
> +void do_ppoll(int *fds, struct pollfd *ufds)
> +{
> +       int i, ret;
> +       struct timespec ts;
> +       char buf[BUF_SIZE];
> +
> +       ts.tv_sec = 0;
> +       ts.tv_nsec = 1 * MSEC_PER_NSEC;
> +
> +       for (i = 0; i < MAX_FDS; i++) {
> +               ufds[i].fd = fds[i];
> +               ufds[i].events = POLLIN|POLLPRI;
> +       }
> +
> +       ret = ppoll(ufds, MAX_FDS, &ts, NULL);
> +
> +       if (ret < 0) {
> +               perror("ppoll");
> +       } else if (ret > 0) {
> +               printf("# [ppoll] data available\n");
> +               ret = read(wait_fd, buf, BUF_SIZE);
> +               if (ret < 0) {
> +                       perror("[ppoll] read");
> +               }
> +       } else {
> +               printf("# [ppoll] timeout\n");
> +       }
> +}
> +
> +void stress_ppoll(int *fds, int value)
> +{
> +       pthread_t writer;
> +       int iter;
> +       struct ppoll_thread_data thread_data;
> +       struct pollfd ufds[MAX_FDS];
> +
> +       thread_data.ufds = ufds;
> +       thread_data.value = value;
> +
> +       stop_thread = 0;
> +       pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data);

Check return value of pthread_create.

> +       for (iter = 0; iter < NR_ITER; iter++) {
> +               do_ppoll(fds, ufds);
> +       }
> +       stop_thread = 1;
> +       pthread_join(writer, NULL);
> +}
> +
> +/*
> + * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
> + * structure:
> + *   - memset to 0
> + *   - memset to 1
> + *   - memset to INT_MAX
> + * Waits for input, but also set a timeout in case the input FD is overwritten
> + * before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the
> + * resulting trace is big (20MB).
> + *
> + * ppoll should work as expected and the trace should be readable at the end.
> + */
> +void ppoll_concurrent_write(void)
> +{
> +       int i, ret, fds[MAX_FDS];
> +
> +       for (i = 0; i < MAX_FDS; i++) {
> +               fds[i] = dup(wait_fd);
> +               if (fds[i] < 0)
> +                       perror("dup");
> +       }
> +
> +       stress_ppoll(fds, 0);
> +       stress_ppoll(fds, 1);
> +       stress_ppoll(fds, INT_MAX);
> +
> +       for (i = 0; i < MAX_FDS; i++) {
> +               ret = close(fds[i]);
> +               if (ret != 0)
> +                       perror("close");
> +       }
> +
> +       return;
> +}
> +
> +void *epoll_pwait_writer(void *addr)
> +{
> +       srand(time(NULL));
> +
> +       while (!stop_thread) {
> +               usleep(rand() % 30);
> +               munmap(addr, MAX_FDS * sizeof(struct epoll_event));
> +       }
> +
> +       return NULL;
> +}
> +
> +/*
> + * epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the
> + * 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)
> +{
> +       int ret, epollfd, i, fds[MAX_FDS];
> +       char buf[BUF_SIZE];
> +       struct epoll_event *epoll_event;
> +       void *addr = NULL;
> +       pthread_t writer;
> +
> +
> +       epollfd = epoll_create(MAX_FDS);
> +       if (epollfd < 0) {
> +               perror("[eppoll] create");
> +               goto end;
> +       }
> +
> +       epoll_event = mmap(addr, 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;
> +       }
> +
> +       for (i = 0; i < MAX_FDS; i++) {
> +               fds[i] = dup(wait_fd);
> +               if (fds[i] < 0)
> +                       perror("dup");

Use braces on single-line conditions.

> +               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;
> +               }
> +       }
> +       stop_thread = 0;
> +       pthread_create(&writer, NULL, &epoll_pwait_writer, (void *) epoll_event);
> +
> +       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");
> +               }
> +       } else if (ret == 0) {
> +               printf("# [eppoll] timeout\n");
> +       } else {
> +               perror("# epoll_pwait");
> +       }
> +
> +       stop_thread = 1;
> +       pthread_join(writer, NULL);
> +
> +end_unmap:
> +       for (i = 0; i < MAX_FDS; i++) {
> +               ret = close(fds[i]);
> +               if (ret != 0)
> +                       perror("close");

Use braces on single-line conditions.

> +       }
> +
> +       ret = munmap(addr, MAX_FDS * sizeof(struct epoll_event));
> +       if (ret != 0)
> +               perror("munmap");
> +
> +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);

Use braces on single-line conditions.

> +       exit(exitcode);
> +}
> +
> +void print_list(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 a FD > 1023\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 "
> +                       "input\n");
> +       fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n");
> +       fprintf(stderr, "\t8: epoll_pwait with 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");
> +}
> +
> +int main(int argc, const char **argv)
> +{
> +       int c, ret, test = -1;
> +       poptContext optCon;
> +       struct rlimit open_lim;
> +
> +       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 },
> +               POPT_AUTOHELP
> +               { NULL, 0, 0, NULL, 0 }
> +       };
> +
> +       optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
> +
> +       if (argc < 2) {
> +               poptPrintUsage(optCon, stderr, 0);
> +               ret = -1;
> +               goto end;
> +       }
> +
> +       ret = 0;
> +
> +       while ((c = poptGetNextOpt(optCon)) >= 0) {
> +               switch(c) {
> +               case 'l':
> +                       print_list();
> +                       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");
> +               goto end;
> +       }
> +
> +       /*
> +        * Some tests might segfault, but we need the getpid() to be output
> +        * for the validation, disabling the buffering on stdout works.
> +        */
> +       setbuf(stdout, NULL);
> +       printf("%d\n", getpid());
> +
> +       wait_fd = STDIN_FILENO;
> +
> +       switch(test) {
> +       case 1:
> +               timeout = -1;
> +               should_work();
> +               break;
> +       case 2:
> +               timeout = 1;
> +               should_work();
> +               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:
> +               poptPrintUsage(optCon, stderr, 0);
> +               ret = -1;
> +               break;
> +       }
> +
> +end:
> +       poptFreeContext(optCon);
> +       return ret;
> +}
> diff --git a/tests/regression/kernel/test_select_poll_epoll b/tests/regression/kernel/test_select_poll_epoll
> new file mode 100755
> index 0000000..3dc517c
> --- /dev/null
> +++ b/tests/regression/kernel/test_select_poll_epoll
> @@ -0,0 +1,398 @@
> +#!/bin/bash
> +#
> +# Copyright (C) - 2016 Julien Desfossez <jdesfossez at efficios.com>
> +#
> +# This program is free software; you can redistribute it and/or modify it
> +# under the terms of the GNU General Public License, version 2 only, as
> +# published by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it will be useful, but WITHOUT
> +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> +# more details.
> +#
> +# You should have received a copy of the GNU General Public License along with
> +# this program; if not, write to the Free Software Foundation, Inc., 51
> +# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> +
> +TEST_DESC="Kernel tracer - select, poll and epoll payload extraction"
> +
> +CURDIR=$(dirname $0)/
> +TESTDIR=$CURDIR/../..
> +VALIDATE_SCRIPT="$CURDIR/validate_select_poll_epoll.py"
> +NUM_TESTS=102
> +
> +# Only run this test on x86 and arm
> +uname -m | grep -E "x86|arm" >/dev/null 2>&1
> +if test $? != 0; then
> +       exit 0
> +fi
> +
> +DISABLE_VALIDATE=0
> +# Babeltrace python bindings are required for the validation, but
> +# it is not a mandatory dependancy of the project, so fail run the
> +# without the content validation, at least we test that we are not
> +# crashing the kernel.
> +$VALIDATE_SCRIPT --help >/dev/null
> +if test $? != 0; then
> +       echo "# Failed to run the validation script, Babeltrace Python bindings might be missing"
> +       DISABLE_VALIDATE=1
> +fi
> +
> +LAST_WARNING=$(dmesg | grep " WARNING:" | cut -d' ' -f1 | tail -1)
> +LAST_OOPS=$(dmesg | grep " OOPS:" | cut -d' ' -f1 | tail -1)
> +LAST_BUG=$(dmesg | grep " BUG:" | cut -d' ' -f1 | tail -1)
> +
> +source $TESTDIR/utils/utils.sh
> +
> +function check_trace_content()
> +{
> +       if test $DISABLE_VALIDATE == 1; then
> +               ok 0 "Validation skipped"
> +               return
> +       fi
> +
> +       $VALIDATE_SCRIPT $@
> +       if test $? = 0; then
> +               ok 0 "Validation success"
> +       else
> +               fail "Validation"
> +       fi
> +}
> +
> +function test_working_cases()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="select,pselect6,poll,ppoll,epoll_ctl,epoll_wait,epoll_pwait"
> +
> +       diag "Working cases for select, pselect6, poll, ppoll and epoll, waiting for input"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       { out=$(yes | $CURDIR/select_poll_epoll -t 1); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +       check_trace_content -t 1 -p $pid $TRACE_PATH
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_timeout_cases()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="select,pselect6,poll,ppoll,epoll_ctl,epoll_wait,epoll_pwait"
> +
> +       diag "Timeout cases (1ms) for select, pselect6, poll, ppoll and epoll"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME "$SYSCALL_LIST"
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       { out=$($CURDIR/select_poll_epoll -t 2); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +       check_trace_content -t 2 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_big_pselect()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="pselect6"
> +
> +       diag "pselect with a FD > 1023"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       { out=$($CURDIR/select_poll_epoll -t 3); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +       check_trace_content -t 3 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_big_ppoll()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="ppoll"
> +
> +       diag "ppoll with 2047 FDs"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       { out=$(yes | $CURDIR/select_poll_epoll -t 4); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +       check_trace_content -t 4 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_ppoll_overflow()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="ppoll"
> +
> +       diag "ppoll buffer overflow, should segfault, waits for input"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       diag "Expect segfaults"
> +       { out=$(yes | $CURDIR/select_poll_epoll -t 5); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       echo $out
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +
> +       check_trace_content -t 5 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_pselect_invalid_ptr()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="pselect6"
> +
> +       diag "pselect with invalid pointer, waits for input"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       { out=$(yes | $CURDIR/select_poll_epoll -t 6); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +       check_trace_content -t 6 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_ppoll_ulong_max()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="ppoll"
> +
> +       diag "ppoll with ulong_max fds, waits for input"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       { out=$(yes | $CURDIR/select_poll_epoll -t 7); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +       check_trace_content -t 7 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_epoll_pwait_invalid_ptr()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="epoll_pwait"
> +
> +       diag "epoll_pwait with invalid pointer, waits for input"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       { out=$(yes | $CURDIR/select_poll_epoll -t 8); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +       check_trace_content -t 8 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_epoll_pwait_int_max()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="epoll_pwait"
> +
> +       diag "epoll_pwait with maxevents set to INT_MAX, waits for input"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       { out=$(yes | $CURDIR/select_poll_epoll -t 9); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +       check_trace_content -t 9 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_ppoll_concurrent()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="ppoll"
> +
> +       diag "ppoll with concurrent updates of the structure from user-space, stress test (3000 iterations), waits for input + timeout 1ms"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       { out=$(yes | $CURDIR/select_poll_epoll -t 10); } 2>/dev/null
> +       stop_lttng_tracing_ok
> +       pid=$(echo $out | cut -d' ' -f1)
> +
> +       validate_trace "$SYSCALL_LIST" $TRACE_PATH
> +       check_trace_content -t 10 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +function test_epoll_pwait_concurrent()
> +{
> +       TRACE_PATH=$(mktemp -d)
> +       SESSION_NAME="syscall_payload"
> +       SYSCALL_LIST="epoll_ctl,epoll_pwait"
> +
> +       diag "epoll_pwait with concurrent munmap of the buffer from user-space, should randomly segfault, run multiple times, waits for input + timeout 1ms"
> +
> +       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
> +
> +       lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
> +       add_context_kernel_ok $SESSION_NAME channel0 pid
> +
> +       start_lttng_tracing_ok
> +       diag "Expect segfaults"
> +       for i in $(seq 1 100); do
> +               { out=$($CURDIR/select_poll_epoll -t 11); } 2>/dev/null
> +       done
> +       pid=$(echo $out | cut -d' ' -f1)
> +       stop_lttng_tracing_ok
> +
> +       # epoll_wait is not always generated in the trace (stress test)
> +       validate_trace "epoll_ctl" $TRACE_PATH
> +       check_trace_content -t 11 -p $pid $TRACE_PATH 2>/dev/null
> +
> +       destroy_lttng_session_ok $SESSION_NAME
> +
> +       rm -rf $TRACE_PATH
> +}
> +
> +# MUST set TESTDIR before calling those functions
> +plan_tests $NUM_TESTS
> +
> +print_test_banner "$TEST_DESC"
> +
> +if [ "$(id -u)" == "0" ]; then
> +       isroot=1
> +else
> +       isroot=0
> +fi
> +
> +skip $isroot "Root access is needed. Skipping all tests." $NUM_TESTS ||
> +{
> +       start_lttng_sessiond
> +
> +       test_working_cases
> +       test_timeout_cases
> +       test_big_pselect
> +       test_big_ppoll
> +       test_ppoll_overflow
> +       test_pselect_invalid_ptr
> +       test_ppoll_ulong_max
> +       test_epoll_pwait_invalid_ptr
> +       test_epoll_pwait_int_max
> +       test_ppoll_concurrent
> +       test_epoll_pwait_concurrent
> +
> +       stop_lttng_sessiond
> +
> +       NEW_WARNING=$(dmesg | grep " WARNING:" | cut -d' ' -f1 | tail -1)
> +       NEW_OOPS=$(dmesg | grep " OOPS:" | cut -d' ' -f1 | tail -1)
> +       NEW_BUG=$(dmesg | grep " BUG:" | cut -d' ' -f1 | tail -1)
> +
> +       if test "$LAST_WARNING" != "$NEW_WARNING"; then
> +               fail "New WARNING generated"
> +       fi
> +       if test "$LAST_OOPS" != "$NEW_OOPS"; then
> +               fail "New OOPS generated"
> +       fi
> +       if test "$LAST_BUG" != "$NEW_BUG"; then
> +               fail "New BUG generated"
> +       fi
> +}
> diff --git a/tests/regression/kernel/validate_select_poll_epoll.py b/tests/regression/kernel/validate_select_poll_epoll.py
> new file mode 100755
> index 0000000..37d4042
> --- /dev/null
> +++ b/tests/regression/kernel/validate_select_poll_epoll.py
> @@ -0,0 +1,783 @@
> +#!/usr/bin/env python3
> +
> +import sys
> +import time
> +import argparse
> +
> +NSEC_PER_SEC = 1000000000
> +
> +try:
> +    from babeltrace import TraceCollection
> +except ImportError:
> +    # quick fix for debian-based distros
> +    sys.path.append("/usr/local/lib/python%d.%d/site-packages" %
> +                    (sys.version_info.major, sys.version_info.minor))
> +    from babeltrace import TraceCollection
> +
> +
> +class TraceParser:
> +    def __init__(self, trace, pid):
> +        self.trace = trace
> +        self.pid = pid
> +        self.expect = {}
> +
> +    def ns_to_hour_nsec(self, ns):
> +        d = time.localtime(ns/NSEC_PER_SEC)
> +        return "%02d:%02d:%02d.%09d" % (d.tm_hour, d.tm_min, d.tm_sec,
> +                                        ns % NSEC_PER_SEC)
> +
> +    def parse(self):
> +        # iterate over all the events
> +        for event in self.trace.events:
> +            if self.pid is not None and event["pid"] != self.pid:
> +                continue
> +
> +            method_name = "handle_%s" % event.name.replace(":", "_").replace("+", "_")
> +            # call the function to handle each event individually
> +            if hasattr(TraceParser, method_name):
> +                func = getattr(TraceParser, method_name)
> +                func(self, event)
> +
> +        ret = 0
> +        for i in self.expect.keys():
> +            if self.expect[i] == 0:
> +                print("%s not validated" % i)
> +                ret = 1
> +
> +        return ret
> +
> +    ### epoll_ctl

Use a single '#' for comments.

> +    def handle_compat_syscall_entry_epoll_ctl(self, event):
> +        self.epoll_ctl_entry(event)
> +
> +    def handle_compat_syscall_exit_epoll_ctl(self, event):
> +        self.epoll_ctl_exit(event)
> +
> +    def handle_syscall_entry_epoll_ctl(self, event):
> +        self.epoll_ctl_entry(event)
> +
> +    def handle_syscall_exit_epoll_ctl(self, event):
> +        self.epoll_ctl_exit(event)
> +
> +    def epoll_ctl_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        epfd = event["epfd"]
> +        op_enum = event["op_enum"]
> +        fd = event["fd"]
> +        _event = event["event"]

This method seems to have no side effect. Am I missing something?

If this is done to provide a default implementation of the method,
replace by "pass".

> +
> +    def epoll_ctl_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]

Same here.

> +
> +    ### epoll_wait + epoll_pwait

Use a single '#' for comments.

> +    def handle_compat_syscall_entry_epoll_wait(self, event):
> +        self.epoll_wait_entry(event)
> +
> +    def handle_compat_syscall_exit_epoll_wait(self, event):
> +        self.epoll_wait_exit(event)
> +
> +    def handle_syscall_entry_epoll_wait(self, event):
> +        self.epoll_wait_entry(event)
> +
> +    def handle_syscall_exit_epoll_wait(self, event):
> +        self.epoll_wait_exit(event)
> +
> +    def handle_compat_syscall_entry_epoll_pwait(self, event):
> +        self.epoll_wait_entry(event)
> +
> +    def handle_compat_syscall_exit_epoll_pwait(self, event):
> +        self.epoll_wait_exit(event)
> +
> +    def handle_syscall_entry_epoll_pwait(self, event):
> +        self.epoll_wait_entry(event)
> +
> +    def handle_syscall_exit_epoll_pwait(self, event):
> +        self.epoll_wait_exit(event)
> +
> +    def epoll_wait_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        epfd = event["epfd"]
> +        maxevents = event["maxevents"]
> +        timeout = event["timeout"]

No side effect?

> +
> +    def epoll_wait_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]

Same.

> +
> +    #### poll + ppoll

Use a single '#' for comments.


> +    def handle_compat_syscall_entry_poll(self, event):
> +        self.poll_entry(event)
> +
> +    def handle_compat_syscall_exit_poll(self, event):
> +        self.poll_exit(event)
> +
> +    def handle_syscall_entry_poll(self, event):
> +        self.poll_entry(event)
> +
> +    def handle_syscall_exit_poll(self, event):
> +        self.poll_exit(event)
> +
> +    def handle_compat_syscall_entry_ppoll(self, event):
> +        self.poll_entry(event)
> +
> +    def handle_compat_syscall_exit_ppoll(self, event):
> +        self.poll_exit(event)
> +
> +    def handle_syscall_entry_ppoll(self, event):
> +        self.poll_entry(event)
> +
> +    def handle_syscall_exit_ppoll(self, event):
> +        self.poll_exit(event)
> +
> +    def poll_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]

No side effect?

> +
> +    def poll_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        fds = event["fds"]

No side effect?

> +
> +    ### epoll_create

Use a single '#' for comments.

> +    def handle_compat_syscall_entry_epoll_create1(self, event):
> +        self.epoll_create_entry(event)
> +
> +    def handle_compat_syscall_exit_epoll_create1(self, event):
> +        self.epoll_create_exit(event)
> +
> +    def handle_compat_syscall_entry_epoll_create(self, event):
> +        self.epoll_create_entry(event)
> +
> +    def handle_compat_syscall_exit_epoll_create(self, event):
> +        self.epoll_create_exit(event)
> +
> +    def handle_syscall_entry_epoll_create1(self, event):
> +        self.epoll_create_entry(event)
> +
> +    def handle_syscall_exit_epoll_create1(self, event):
> +        self.epoll_create_exit(event)
> +
> +    def handle_syscall_entry_epoll_create(self, event):
> +        self.epoll_create_entry(event)
> +
> +    def handle_syscall_exit_epoll_create(self, event):
> +        self.epoll_create_exit(event)
> +
> +    def handle_compat_syscall_entry_epoll_create1(self, event):
> +        self.epoll_create_entry(event)
> +
> +    def handle_compat_syscall_exit_epoll_create(self, event):
> +        self.epoll_create_exit(event)
> +
> +    def epoll_create_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        flags = event["flags"]
> +
> +    def epoll_create_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +
> +    ### select + pselect6

Use a single '#' for comments.

> +    def handle_syscall_entry_pselect6(self, event):
> +        self.select_entry(event)
> +
> +    def handle_syscall_exit_pselect6(self, event):
> +        self.select_exit(event)
> +
> +    def handle_compat_syscall_entry_pselect6(self, event):
> +        self.select_entry(event)
> +
> +    def handle_compat_syscall_exit_pselect6(self, event):
> +        self.select_exit(event)
> +
> +    def handle_syscall_entry_select(self, event):
> +        self.select_entry(event)
> +
> +    def handle_syscall_exit_select(self, event):
> +        self.select_exit(event)
> +
> +    def handle_compat_syscall_entry_select(self, event):
> +        self.select_entry(event)
> +
> +    def handle_compat_syscall_exit_select(self, event):
> +        self.select_exit(event)
> +
> +    def select_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        n = event["n"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]

No side effect?

> +
> +    def select_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]

No side effect?

> +
> +
> +class Test1(TraceParser):
> +    def __init__(self, trace, pid):
> +        super().__init__(trace, pid)
> +        self.expect["select_in_fd0"] = 0
> +        self.expect["select_in_fd1023"] = 0
> +        self.expect["select_out_fd0"] = 0
> +        self.expect["select_out_fd1023"] = 0
> +        self.expect["poll_in_nfds1"] = 0
> +        self.expect["poll_out_nfds1"] = 0
> +        self.expect["epoll_ctl_in_add"] = 0
> +        self.expect["epoll_ctl_out_ok"] = 0
> +        self.expect["epoll_wait_in_ok"] = 0
> +        self.expect["epoll_wait_out_fd0"] = 0
> +
> +    def select_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        n = event["n"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]
> +
> +        if n == 1 and readfds[0] == 1:
> +            self.expect["select_in_fd0"] = 1
> +        if n == 1023:
> +            if readfds[127] == 0x40 and writefds[127] == 0 and \
> +                exceptfds[127] == 0 and overflow == 0:
> +                self.expect["select_in_fd1023"] = 1
> +
> +    def select_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]
> +
> +        if ret == 1:
> +            if readfds[0] == 1:
> +                self.expect["select_out_fd0"] = 1
> +            if _readfds_length == 128 and readfds[127] == 0x40 and \
> +                    writefds[127] == 0 and exceptfds[127] == 0 and tvp == 0:
> +                self.expect["select_out_fd1023"] = 1

Please add comments to explain what is being checked in the various
test methods.

> +
> +    def poll_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if nfds == 1 and fds_length == 1 and fds[0]["raw_events"] == 0x3 \
> +                and fds[0]["events"]["POLLIN"] == 1 and \
> +                fds[0]["events"]["padding"] == 0:
> +            self.expect["poll_in_nfds1"] = 1
> +
> +    def poll_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        fds = event["fds"]
> +
> +        if ret == 1 and fds_length == 1 and fds[0]["raw_events"] == 0x1 \
> +                and fds[0]["events"]["POLLIN"] == 1 and \
> +                fds[0]["events"]["padding"] == 0:
> +            self.expect["poll_out_nfds1"] = 1
> +
> +    def epoll_ctl_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        epfd = event["epfd"]
> +        op_enum = event["op_enum"]
> +        fd = event["fd"]
> +        _event = event["event"]
> +
> +        if epfd == 3 and op_enum == "EPOLL_CTL_ADD" and fd == 0 and \
> +                _event["data_union"]["fd"] == 0 and \
> +                _event["events"]["EPOLLIN"] == 1 and \
> +                _event["events"]["EPOLLPRI"] == 1:
> +            self.expect["epoll_ctl_in_add"] = 1
> +
> +    def epoll_ctl_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +
> +        if ret == 0:
> +            self.expect["epoll_ctl_out_ok"] = 1
> +
> +    def epoll_wait_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        epfd = event["epfd"]
> +        maxevents = event["maxevents"]
> +        timeout = event["timeout"]
> +
> +        if epfd == 3 and maxevents == 1 and timeout == -1:
> +            self.expect["epoll_wait_in_ok"] = 1
> +
> +

Remove extra blank line.

> +    def epoll_wait_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if ret == 1 and fds_length == 1 and overflow == 0 and \
> +                fds[0]["data_union"]["fd"] == 0 and \
> +                fds[0]["events"]["EPOLLIN"] == 1:
> +            self.expect["epoll_wait_out_fd0"] = 1
> +
> +
> +class Test2(TraceParser):
> +    def __init__(self, trace, pid):
> +        super().__init__(trace, pid)
> +        self.expect["select_timeout_in_fd0"] = 0
> +        self.expect["select_timeout_in_fd1023"] = 0
> +        self.expect["select_timeout_out"] = 0
> +        self.expect["poll_timeout_in"] = 0
> +        self.expect["poll_timeout_out"] = 0
> +        self.expect["epoll_ctl_timeout_in_add"] = 0
> +        self.expect["epoll_ctl_timeout_out_ok"] = 0
> +        self.expect["epoll_wait_timeout_in"] = 0
> +        self.expect["epoll_wait_timeout_out"] = 0
> +
> +    def select_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        n = event["n"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]
> +
> +        if n == 1 and tvp != 0:
> +            self.expect["select_timeout_in_fd0"] = 1
> +        if n == 1023:
> +            if readfds[127] == 0x40 and writefds[127] == 0 and \
> +                exceptfds[127] == 0 and tvp != 0:

Indent ^ by one more level.

> +                self.expect["select_timeout_in_fd1023"] = 1
> +
> +    def select_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]
> +
> +        if ret == 0 and tvp != 0:
> +            self.expect["select_timeout_out"] = 1
> +
> +    def poll_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if nfds == 1 and fds_length == 1 and fds[0]["raw_events"] == 0x3 \
> +                and fds[0]["events"]["POLLIN"] == 1 and \
> +                fds[0]["events"]["padding"] == 0:
> +            self.expect["poll_timeout_in"] = 1
> +
> +    def poll_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        fds = event["fds"]
> +
> +        if ret == 0 and nfds == 1 and fds_length == 0:
> +            self.expect["poll_timeout_out"] = 1
> +
> +    def epoll_ctl_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        epfd = event["epfd"]
> +        op_enum = event["op_enum"]
> +        fd = event["fd"]
> +        _event = event["event"]
> +
> +        if op_enum == "EPOLL_CTL_ADD" and \
> +                _event["events"]["EPOLLIN"] == 1 and \
> +                _event["events"]["EPOLLPRI"] == 1:
> +            self.expect["epoll_ctl_timeout_in_add"] = 1
> +
> +    def epoll_ctl_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +
> +        if ret == 0:
> +            self.expect["epoll_ctl_timeout_out_ok"] = 1
> +
> +    def epoll_wait_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        epfd = event["epfd"]
> +        maxevents = event["maxevents"]
> +        timeout = event["timeout"]
> +
> +        if maxevents == 1 and timeout == 1:
> +            self.expect["epoll_wait_timeout_in"] = 1
> +
> +

Remove extra blank line.

> +    def epoll_wait_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if ret == 0 and fds_length == 0 and overflow == 0:
> +            self.expect["epoll_wait_timeout_out"] = 1
> +
> +
> +class Test3(TraceParser):
> +    def __init__(self, trace, pid):
> +        super().__init__(trace, pid)
> +        self.expect["select_too_big_in"] = 0
> +        self.expect["select_too_big_out"] = 0
> +
> +    def select_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        n = event["n"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]
> +
> +        if n == 2048 and overflow == 0 and _readfds_length == 0:
> +            self.expect["select_too_big_in"] = 1
> +
> +    def select_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]
> +
> +        if ret == -9 and overflow == 0 and _readfds_length == 0:
> +            self.expect["select_too_big_out"] = 1
> +
> +
> +class Test4(TraceParser):
> +    def __init__(self, trace, pid):
> +        super().__init__(trace, pid)
> +        self.expect["big_poll_in"] = 0
> +        self.expect["big_poll_out"] = 0
> +
> +    def poll_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if nfds == 2047 and fds_length == 512 and overflow == 1 and \
> +                fds[0]["raw_events"] == 0x3 \
> +                and fds[0]["events"]["POLLIN"] == 1 and \
> +                fds[0]["events"]["padding"] == 0 and \
> +                fds[511]["events"]["POLLIN"] == 1 and \
> +                fds[511]["events"]["POLLPRI"] == 1:
> +            self.expect["big_poll_in"] = 1
> +
> +    def poll_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if ret == 2047 and nfds == 2047 and fds_length == 512 and \
> +                overflow == 1 and fds[0]["events"]["POLLIN"] == 1 and \
> +                fds[511]["events"]["POLLIN"] == 1:

^ Indent by one more level.

> +            self.expect["big_poll_out"] = 1
> +
> +
> +class Test5(TraceParser):
> +    def __init__(self, trace, pid):
> +        super().__init__(trace, pid)
> +        self.expect["poll_overflow_in"] = 0
> +        self.expect["poll_overflow_out"] = 0
> +
> +    def poll_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if nfds == 100 and fds_length == 100 and overflow == 0 and \
> +                fds[0]["events"]["POLLIN"] == 1:
> +            self.expect["poll_overflow_in"] = 1
> +
> +    def poll_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if nfds == 100 and overflow == 0:
> +            self.expect["poll_overflow_out"] = 1
> +
> +
> +class Test6(TraceParser):
> +    def __init__(self, trace, pid):
> +        super().__init__(trace, pid)
> +        self.expect["pselect_invalid_in"] = 0
> +        self.expect["pselect_invalid_out"] = 0
> +
> +    def select_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        n = event["n"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]
> +
> +        if n == 1 and overflow == 0 and _readfds_length == 0:
> +            self.expect["pselect_invalid_in"] = 1
> +
> +    def select_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        overflow = event["overflow"]
> +        tvp = event["tvp"]
> +        _readfds_length = event["_readfds_length"]
> +        readfds = event["readfds"]
> +        _writefds_length = event["_writefds_length"]
> +        writefds = event["writefds"]
> +        _exceptfds_length = event["_exceptfds_length"]
> +        exceptfds = event["exceptfds"]
> +
> +        if ret == -14 and overflow == 0 and _readfds_length == 0:
> +            self.expect["pselect_invalid_out"] = 1
> +
> +
> +class Test7(TraceParser):
> +    def __init__(self, trace, pid):
> +        super().__init__(trace, pid)
> +        self.expect["poll_max_in"] = 0
> +        self.expect["poll_max_out"] = 0
> +
> +    def poll_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if nfds == 4294967295 and overflow == 1:
> +            self.expect["poll_max_in"] = 1
> +
> +    def poll_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        nfds = event["nfds"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if ret == -22 and nfds == 4294967295 and overflow == 0:
> +            self.expect["poll_max_out"] = 1
> +
> +
> +class Test8(TraceParser):
> +    def __init__(self, trace, pid):
> +        super().__init__(trace, pid)
> +        self.expect["epoll_wait_invalid_in"] = 0
> +        self.expect["epoll_wait_invalid_out"] = 0
> +
> +    def epoll_wait_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        epfd = event["epfd"]
> +        maxevents = event["maxevents"]
> +        timeout = event["timeout"]
> +
> +        if epfd == 3 and maxevents == 1 and timeout == -1:
> +            self.expect["epoll_wait_invalid_in"] = 1
> +
> +

Remove extra blank line.

> +    def epoll_wait_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if ret == -14 and fds_length == 0 and overflow == 0:
> +            self.expect["epoll_wait_invalid_out"] = 1
> +
> +
> +class Test9(TraceParser):
> +    def __init__(self, trace, pid):
> +        super().__init__(trace, pid)
> +        self.expect["epoll_wait_max_in"] = 0
> +        self.expect["epoll_wait_max_out"] = 0
> +
> +    def epoll_wait_entry(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        epfd = event["epfd"]
> +        maxevents = event["maxevents"]
> +        timeout = event["timeout"]
> +
> +        if epfd == 3 and maxevents == 2147483647 and timeout == -1:
> +            self.expect["epoll_wait_max_in"] = 1
> +
> +

Remove extra blank line.

> +    def epoll_wait_exit(self, event):
> +        timestamp = event.timestamp
> +        cpu_id = event["cpu_id"]
> +        ret = event["ret"]
> +        fds_length = event["fds_length"]
> +        overflow = event["overflow"]
> +        fds = event["fds"]
> +
> +        if ret == -22 and fds_length == 0 and overflow == 0:
> +            self.expect["epoll_wait_max_out"] = 1
> +
> +
> +if __name__ == "__main__":
> +    parser = argparse.ArgumentParser(description='Trace parser')
> +    parser.add_argument('path', metavar="<path/to/trace>", help='Trace path')
> +    parser.add_argument('-t', '--test', type=int, help='Test to validate')
> +    parser.add_argument('-p', '--pid', type=int, help='PID of the app')
> +    args = parser.parse_args()
> +
> +    if not args.test:
> +        print("Need to pass a test to validate (-t)")
> +        sys.exit(1)
> +
> +    if not args.pid:
> +        print("Need to pass the PID to check (-p)")
> +        sys.exit(1)
> +
> +    traces = TraceCollection()
> +    handle = traces.add_traces_recursive(args.path, "ctf")
> +    if handle is None:
> +        sys.exit(1)
> +

Remove tab here ^


> +    t = None
> +
> +    if args.test == 1:
> +        t = Test1(traces, args.pid)
> +    elif args.test == 2:
> +        t = Test2(traces, args.pid)
> +    elif args.test == 3:
> +        t = Test3(traces, args.pid)
> +    elif args.test == 4:
> +        t = Test4(traces, args.pid)
> +    elif args.test == 5:
> +        t = Test5(traces, args.pid)
> +    elif args.test == 6:
> +        t = Test6(traces, args.pid)
> +    elif args.test == 7:
> +        t = Test7(traces, args.pid)
> +    elif args.test == 8:
> +        t = Test8(traces, args.pid)
> +    elif args.test == 9:
> +        t = Test9(traces, args.pid)
> +    elif args.test == 10:
> +        # stress test, nothing reliable to check
> +        ret = 0
> +    elif args.test == 11:
> +        # stress test, nothing reliable to check
> +        ret = 0
> +    else:
> +        print("Invalid test case")
> +        sys.exit(1)
> +
> +    if t is not None:
> +        ret = t.parse()
> +
> +    for h in handle.values():
> +        traces.remove_trace(h)
> +
> +    sys.exit(ret)
> diff --git a/tests/root_regression b/tests/root_regression
> index 869c560..93cad3e 100644
> --- a/tests/root_regression
> +++ b/tests/root_regression
> @@ -1,6 +1,7 @@
>  regression/kernel/test_all_events
>  regression/kernel/test_event_basic
>  regression/kernel/test_syscall
> +regression/kernel/test_select_poll_epoll
>  regression/tools/live/test_kernel
>  regression/tools/live/test_lttng_kernel
>  regression/tools/streaming/test_high_throughput_limits
> --
> 1.9.1
>
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev



-- 
Jérémie Galarneau
EfficiOS Inc.
http://www.efficios.com


More information about the lttng-dev mailing list