]> git.proxmox.com Git - mirror_corosync-qdevice.git/commitdiff
pr-poll-loop: Add pre poll callbacks
authorJan Friesse <jfriesse@redhat.com>
Thu, 27 Aug 2020 12:16:14 +0000 (14:16 +0200)
committerJan Friesse <jfriesse@redhat.com>
Fri, 28 Aug 2020 06:57:15 +0000 (08:57 +0200)
Signed-off-by: Jan Friesse <jfriesse@redhat.com>
qdevices/pr-poll-loop.c
qdevices/pr-poll-loop.h
qdevices/test-pr-poll-loop.c

index fe4287c1e4f78cd2d06a04afcf4d8fe35546253d..5ce27e655bfec378dede58f213545b2eeabb19b7 100644 (file)
 /*
  * Helper functions declarations
  */
-static PRInt16                          poll_events_to_pr_events(short events);
+static PRInt16                                  poll_events_to_pr_events(short events);
 
-static short                            pr_events_to_poll_events(PRInt16 events);
+static short                                    pr_events_to_poll_events(PRInt16 events);
 
-static int                              pr_poll_loop_add_fd_int(struct pr_poll_loop *poll_loop,
+static int                                      pr_poll_loop_add_fd_int(struct pr_poll_loop *poll_loop,
     int fd, PRFileDesc *prfd,
     short events, pr_poll_loop_fd_set_events_cb_fn fd_set_events_cb,
     pr_poll_loop_prfd_set_events_cb_fn prfd_set_events_cb,
@@ -66,12 +66,16 @@ static int                           pr_poll_loop_add_fd_int(struct pr_poll_loop *poll_loop,
     pr_poll_loop_fd_err_cb_fn fd_err_cb, pr_poll_loop_prfd_err_cb_fn prfd_err_cb,
     void *user_data1, void *user_data2);
 
-static int                              pr_poll_loop_del_fd_int(struct pr_poll_loop *poll_loop,
-    int fd, PRFileDesc *prfd);
+static int                                      pr_poll_loop_del_fd_int(
+    struct pr_poll_loop *poll_loop, int fd, PRFileDesc *prfd);
 
-static struct pr_poll_loop_fd_entry    *pr_poll_loop_find_by_fd(
+static struct pr_poll_loop_fd_entry            *pr_poll_loop_find_by_fd(
     const struct pr_poll_loop *poll_loop, int fd, PRFileDesc *prfd);
 
+static struct pr_poll_loop_pre_poll_cb_entry   *pr_poll_loop_find_pre_poll_cb(
+    const struct pr_poll_loop *poll_loop,
+    pr_poll_loop_pre_poll_cb_fn pre_poll_cb);
+
 static int                              prepare_poll_array(struct pr_poll_loop *poll_loop);
 
 /*
@@ -239,11 +243,28 @@ pr_poll_loop_find_by_fd(const struct pr_poll_loop *poll_loop, int fd, PRFileDesc
        return (NULL);
 }
 
+static struct pr_poll_loop_pre_poll_cb_entry *
+pr_poll_loop_find_pre_poll_cb(const struct pr_poll_loop *poll_loop,
+    pr_poll_loop_pre_poll_cb_fn pre_poll_cb)
+{
+       struct pr_poll_loop_pre_poll_cb_entry *pre_poll_cb_entry;
+
+       TAILQ_FOREACH(pre_poll_cb_entry, &poll_loop->pre_poll_cb_list, entries) {
+               if (pre_poll_cb_entry->pre_poll_cb == pre_poll_cb) {
+                       return (pre_poll_cb_entry);
+               }
+       }
+
+       return (NULL);
+}
+
 static
 int prepare_poll_array(struct pr_poll_loop *poll_loop)
 {
        struct pr_poll_loop_fd_entry *fd_entry;
        struct pr_poll_loop_fd_entry *fd_entry_next;
+       struct pr_poll_loop_pre_poll_cb_entry *pre_poll_cb_entry;
+       struct pr_poll_loop_pre_poll_cb_entry *pre_poll_cb_entry_next;
        struct pr_poll_loop_fd_entry **user_data;
        short events;
        int res;
@@ -254,6 +275,40 @@ int prepare_poll_array(struct pr_poll_loop *poll_loop)
 
        pr_poll_array_clean(poll_array);
 
+       /*
+        * Call pre poll callbacks
+        */
+       pre_poll_cb_entry = TAILQ_FIRST(&poll_loop->pre_poll_cb_list);
+       while (pre_poll_cb_entry != NULL) {
+               pre_poll_cb_entry_next = TAILQ_NEXT(pre_poll_cb_entry, entries);
+
+               if (pre_poll_cb_entry->pre_poll_cb != NULL) {
+                       res = pre_poll_cb_entry->pre_poll_cb(pre_poll_cb_entry->user_data1,
+                           pre_poll_cb_entry->user_data2);
+               } else {
+                       res = 0;
+               }
+
+               switch (res) {
+               case 0:
+                       /*
+                        * Continue
+                        */
+                       break;
+               case -1:
+                       /*
+                        * return immediately
+                        */
+                       return (-1);
+                       break;
+               default:
+                       return (-2);
+                       break;
+               }
+
+               pre_poll_cb_entry = pre_poll_cb_entry_next;
+       }
+
        /*
         * Fill in poll_array
         */
@@ -338,6 +393,7 @@ pr_poll_loop_init(struct pr_poll_loop *poll_loop)
        memset(poll_loop, 0, sizeof(*poll_loop));
 
        TAILQ_INIT(&(poll_loop->fd_list));
+       TAILQ_INIT(&(poll_loop->pre_poll_cb_list));
 
        pr_poll_array_init(&poll_loop->poll_array, sizeof(struct pr_poll_loop_fd_entry *));
        timer_list_init(&poll_loop->tlist);
@@ -350,6 +406,24 @@ pr_poll_loop_del_fd(struct pr_poll_loop *poll_loop, int fd)
        return (pr_poll_loop_del_fd_int(poll_loop, fd, NULL));
 }
 
+int
+pr_poll_loop_del_pre_poll_cb(struct pr_poll_loop *poll_loop,
+    pr_poll_loop_pre_poll_cb_fn pre_poll_cb)
+{
+       struct pr_poll_loop_pre_poll_cb_entry *pre_poll_cb_entry;
+
+       pre_poll_cb_entry = pr_poll_loop_find_pre_poll_cb(poll_loop, pre_poll_cb);
+       if (pre_poll_cb_entry == NULL) {
+               return (-1);
+       }
+
+       TAILQ_REMOVE(&poll_loop->pre_poll_cb_list, pre_poll_cb_entry, entries);
+
+       free(pre_poll_cb_entry);
+
+       return (0);
+}
+
 int
 pr_poll_loop_del_prfd(struct pr_poll_loop *poll_loop, PRFileDesc *prfd)
 {
@@ -362,6 +436,8 @@ pr_poll_loop_destroy(struct pr_poll_loop *poll_loop)
 {
        struct pr_poll_loop_fd_entry *fd_entry;
        struct pr_poll_loop_fd_entry *fd_entry_next;
+       struct pr_poll_loop_pre_poll_cb_entry *pre_poll_cb_entry;
+       struct pr_poll_loop_pre_poll_cb_entry *pre_poll_cb_entry_next;
 
        fd_entry = TAILQ_FIRST(&poll_loop->fd_list);
 
@@ -379,6 +455,18 @@ pr_poll_loop_destroy(struct pr_poll_loop *poll_loop)
 
        TAILQ_INIT(&(poll_loop->fd_list));
 
+       pre_poll_cb_entry = TAILQ_FIRST(&poll_loop->pre_poll_cb_list);
+
+       while (pre_poll_cb_entry != NULL) {
+               pre_poll_cb_entry_next = TAILQ_NEXT(pre_poll_cb_entry, entries);
+
+               free(pre_poll_cb_entry);
+
+               pre_poll_cb_entry = pre_poll_cb_entry_next;
+       }
+
+       TAILQ_INIT(&(poll_loop->pre_poll_cb_list));
+
        pr_poll_array_destroy(&poll_loop->poll_array);
        timer_list_free(&poll_loop->tlist);
 
@@ -400,6 +488,34 @@ pr_poll_loop_add_fd(struct pr_poll_loop *poll_loop, int fd,
            user_data1, user_data2));
 }
 
+int
+pr_poll_loop_add_pre_poll_cb(struct pr_poll_loop *poll_loop,
+    pr_poll_loop_pre_poll_cb_fn pre_poll_cb,
+    void *user_data1, void *user_data2)
+{
+       struct pr_poll_loop_pre_poll_cb_entry *new_entry;
+
+       if (pr_poll_loop_find_pre_poll_cb(poll_loop, pre_poll_cb) != NULL) {
+               return (-1);
+       }
+
+       new_entry = malloc(sizeof(*new_entry));
+       if (new_entry == NULL) {
+               return (-1);
+       }
+
+       memset(new_entry, 0, sizeof(*new_entry));
+
+       new_entry->pre_poll_cb = pre_poll_cb;
+
+       new_entry->user_data1 = user_data1;
+       new_entry->user_data2 = user_data2;
+
+       TAILQ_INSERT_TAIL(&poll_loop->pre_poll_cb_list, new_entry, entries);
+
+       return (0);
+}
+
 int
 pr_poll_loop_add_prfd(struct pr_poll_loop *poll_loop, PRFileDesc *prfd,
     short events, pr_poll_loop_prfd_set_events_cb_fn prfd_set_events_cb,
index a5536fea9f879ce0a070e5fe2904ff91db7d90ec..3171e83566de71804372037b50238843ab5f8e40 100644 (file)
@@ -77,6 +77,11 @@ typedef int (*pr_poll_loop_fd_err_cb_fn)(int fd, short revents, void *user_data1
 typedef int (*pr_poll_loop_prfd_err_cb_fn)(PRFileDesc *prfd, short revents, const PRPollDesc *pd,
     void *user_data1, void *user_data2);
 
+/*
+ * Return code: 0 - Ok, -1 - Return error
+ */
+typedef int (*pr_poll_loop_pre_poll_cb_fn)(void *user_data1, void *user_data2);
+
 struct pr_poll_loop_fd_entry {
        int fd;
        PRFileDesc *prfd;
@@ -94,8 +99,16 @@ struct pr_poll_loop_fd_entry {
        TAILQ_ENTRY(pr_poll_loop_fd_entry) entries;
 };
 
+struct pr_poll_loop_pre_poll_cb_entry {
+       pr_poll_loop_pre_poll_cb_fn pre_poll_cb;
+       void *user_data1;
+       void *user_data2;
+       TAILQ_ENTRY(pr_poll_loop_pre_poll_cb_entry) entries;
+};
+
 struct pr_poll_loop {
        TAILQ_HEAD(, pr_poll_loop_fd_entry) fd_list;
+       TAILQ_HEAD(, pr_poll_loop_pre_poll_cb_entry) pre_poll_cb_list;
        struct timer_list tlist;
        struct pr_poll_array poll_array;
 };
@@ -109,6 +122,10 @@ extern int                  pr_poll_loop_add_fd(struct pr_poll_loop *poll_loop, int fd,
     pr_poll_loop_fd_err_cb_fn fd_err_cb,
     void *user_data1, void *user_data2);
 
+extern int                      pr_poll_loop_add_pre_poll_cb(struct pr_poll_loop *poll_loop,
+    pr_poll_loop_pre_poll_cb_fn pre_poll_cb,
+    void *user_data1, void *user_data2);
+
 extern int                      pr_poll_loop_add_prfd(struct pr_poll_loop *poll_loop,
     PRFileDesc *prfd, short events,
     pr_poll_loop_prfd_set_events_cb_fn prfd_set_events_cb,
@@ -119,6 +136,9 @@ extern int                   pr_poll_loop_add_prfd(struct pr_poll_loop *poll_loop,
 
 extern int                      pr_poll_loop_del_fd(struct pr_poll_loop *poll_loop, int fd);
 
+extern int                     pr_poll_loop_del_pre_poll_cb(struct pr_poll_loop *poll_loop,
+    pr_poll_loop_pre_poll_cb_fn pre_poll_cb);
+
 extern int                      pr_poll_loop_del_prfd(struct pr_poll_loop *poll_loop,
     PRFileDesc *prfd);
 
index 1a26b85aab8e865e662b1987026543534a27a01c..d85aa2777c9e222a880a3d4124602fb2bd5ea3bd 100644 (file)
  */
 #define READ_STR               "test"
 
-static int fd_set_events_cb1_return_called = 0;
-static int fd_set_events_cb2_return_called = 0;
-static int fd_read_cb1_called = 0;
-static int fd_read_cb2_called = 0;
-static int fd_write_cb1_called = 0;
-static int fd_err_cb1_called = 0;
-static int timeout_cb_called = 0;
-
-static int prfd_set_events_cb1_return_called = 0;
-static int prfd_set_events_cb2_return_called = 0;
-static int prfd_read_cb1_called = 0;
-static int prfd_read_cb2_called = 0;
-static int prfd_write_cb1_called = 0;
-static int prfd_err_cb1_called = 0;
-
-static int test_complex_state = 0;
-static int test_complex_set_events_pipe1_read_called = 0;
-static int test_complex_read_pipe1_read_called = 0;
-static int test_complex_set_events_pipe1_write_called = 0;
-static int test_complex_write_pipe1_write_called = 0;
-static int test_complex_set_events_pipe2_read_called = 0;
-static int test_complex_read_pipe2_read_called = 0;
-static int test_complex_set_events_pipe2_write_called = 0;
-static int test_complex_write_pipe2_write_called = 0;
-static int test_complex_read_pipe1_fd = 0;
+static int fd_set_events_cb1_return_called = -1;
+static int fd_set_events_cb2_return_called = -1;
+static int fd_read_cb1_called = -1;
+static int fd_read_cb2_called = -1;
+static int fd_write_cb1_called = -1;
+static int fd_err_cb1_called = -1;
+static int timeout_cb_called = -1;
+
+static int prfd_set_events_cb1_return_called = -1;
+static int prfd_set_events_cb2_return_called = -1;
+static int prfd_read_cb1_called = -1;
+static int prfd_read_cb2_called = -1;
+static int prfd_write_cb1_called = -1;
+static int prfd_err_cb1_called = -1;
+
+static int test_complex_state = -1;
+static int test_complex_set_events_pipe1_read_called = -1;
+static int test_complex_read_pipe1_read_called = -1;
+static int test_complex_set_events_pipe1_write_called = -1;
+static int test_complex_write_pipe1_write_called = -1;
+static int test_complex_set_events_pipe2_read_called = -1;
+static int test_complex_read_pipe2_read_called = -1;
+static int test_complex_set_events_pipe2_write_called = -1;
+static int test_complex_write_pipe2_write_called = -1;
+static int test_complex_read_pipe1_fd = -1;
+
+static int pre_poll_cb1_called = -1;
+static int pre_poll_cb2_called = -1;
+static int pre_poll_cb_return_called = -1;
 
 static int
 timeout_cb(void *data1, void *data2)
@@ -402,6 +406,39 @@ test_complex_write_pipe2_write_cb(PRFileDesc *prfd, const PRPollDesc *pd, void *
        return (0);
 }
 
+static int
+test_pre_poll_cb1(void *user_data1, void *user_data2)
+{
+
+       assert(user_data1 == &pre_poll_cb1_called);
+       assert(user_data2 == test_pre_poll_cb1);
+       pre_poll_cb1_called++;
+
+       return (0);
+}
+
+static int
+test_pre_poll_cb2(void *user_data1, void *user_data2)
+{
+
+       assert(user_data1 == &pre_poll_cb2_called);
+       assert(user_data2 == test_pre_poll_cb2);
+       pre_poll_cb2_called++;
+
+       return (0);
+}
+
+static int
+test_pre_poll_cb_return(void *user_data1, void *user_data2)
+{
+
+       assert(user_data1 == &pre_poll_cb_return_called);
+       assert(user_data2 == test_pre_poll_cb_return);
+       pre_poll_cb_return_called++;
+
+       return (-1);
+}
+
 static void
 init_global_vars(void)
 {
@@ -419,6 +456,16 @@ init_global_vars(void)
        prfd_read_cb2_called = -1;
        prfd_write_cb1_called = -1;
        prfd_err_cb1_called = -1;
+
+       test_complex_set_events_pipe1_read_called = -1;
+       test_complex_read_pipe1_read_called = -1;
+       test_complex_set_events_pipe1_write_called = -1;
+       test_complex_write_pipe1_write_called = -1;
+       test_complex_set_events_pipe2_read_called = -1;
+       test_complex_read_pipe2_read_called = -1;
+       test_complex_set_events_pipe2_write_called = -1;
+       test_complex_write_pipe2_write_called = -1;
+       test_complex_read_pipe1_fd = -1;
 }
 
 static void
@@ -429,25 +476,27 @@ test_fd_basics(struct pr_poll_loop *poll_loop)
 
        init_global_vars();
 
+       assert(pipe(pipe_fd1) == 0);
+
        /*
         * Add POLLNVAL -> failure
         */
-       assert(pr_poll_loop_add_fd(poll_loop, 0, POLLNVAL, NULL, NULL, NULL, NULL,
+       assert(pr_poll_loop_add_fd(poll_loop, pipe_fd1[0], POLLNVAL, NULL, NULL, NULL, NULL,
            NULL, NULL) == -1);
        /*
         * Del non-existing fdL -> failure
         */
-       assert(pr_poll_loop_del_fd(poll_loop, 0) == -1);
+       assert(pr_poll_loop_del_fd(poll_loop, pipe_fd1[0]) == -1);
 
        /*
         * Add and delete fd twice
         */
-       assert(pr_poll_loop_add_fd(poll_loop, 0, 0, NULL, NULL, NULL, NULL,
+       assert(pr_poll_loop_add_fd(poll_loop, pipe_fd1[0], 0, NULL, NULL, NULL, NULL,
            NULL, NULL) == 0);
-       assert(pr_poll_loop_add_fd(poll_loop, 0, 0, NULL, NULL, NULL, NULL,
+       assert(pr_poll_loop_add_fd(poll_loop, pipe_fd1[0], 0, NULL, NULL, NULL, NULL,
            NULL, NULL) == -1);
-       assert(pr_poll_loop_del_fd(poll_loop, 0) == 0);
-       assert(pr_poll_loop_del_fd(poll_loop, 0) == -1);
+       assert(pr_poll_loop_del_fd(poll_loop, pipe_fd1[0]) == 0);
+       assert(pr_poll_loop_del_fd(poll_loop, pipe_fd1[0]) == -1);
 
        /*
         * Test timeout timer
@@ -462,7 +511,6 @@ test_fd_basics(struct pr_poll_loop *poll_loop)
        /*
         * Test user_data passing
         */
-       assert(pipe(pipe_fd1) == 0);
        assert(pr_poll_loop_add_fd(poll_loop, pipe_fd1[0], POLLIN, fd_set_events_cb1_return,
            NULL, NULL, NULL, (void *)&fd_set_events_cb1_return_called, NULL) == 0);
 
@@ -806,11 +854,19 @@ test_complex(struct pr_poll_loop *poll_loop)
        PRFileDesc *write_pipe2;
        struct timer_list_entry *timeout_timer;
 
+       init_global_vars();
+
        assert(pipe(pipe_fd1) == 0);
        assert(pipe(pipe_fd2) == 0);
 
        test_complex_read_pipe1_fd = pipe_fd1[0];
 
+       /*
+        * Add pre poll cb1
+        */
+       assert(pr_poll_loop_add_pre_poll_cb(poll_loop, test_pre_poll_cb1,
+           &pre_poll_cb1_called, test_pre_poll_cb1) == 0);
+
        assert((read_pipe1 = PR_CreateSocketPollFd(pipe_fd1[0])) != NULL);
        assert((write_pipe2 = PR_CreateSocketPollFd(pipe_fd2[1])) != NULL);
 
@@ -830,6 +886,18 @@ test_complex(struct pr_poll_loop *poll_loop)
            test_complex_read_pipe2_write_cb, test_complex_write_pipe2_write_cb, NULL,
            &test_complex_set_events_pipe2_write_called, test_complex_set_events_pipe2_write_cb) == 0);
 
+       timeout_cb_called = 0;
+       test_complex_set_events_pipe1_read_called = 0;
+       test_complex_read_pipe1_read_called = 0;
+       test_complex_set_events_pipe1_write_called = 0;
+       test_complex_write_pipe1_write_called = 0;
+       test_complex_set_events_pipe2_read_called = 0;
+       test_complex_read_pipe2_read_called = 0;
+       test_complex_set_events_pipe2_write_called = 0;
+       test_complex_write_pipe2_write_called = 0;
+       pre_poll_cb1_called = 0;
+       pre_poll_cb2_called = 0;
+
        /*
         * Call for first time -> all set_events should be called and pipe2_write should be called
         */
@@ -837,6 +905,8 @@ test_complex(struct pr_poll_loop *poll_loop)
            pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
        assert(pr_poll_loop_exec(poll_loop) == 0);
 
+       assert(pre_poll_cb1_called == 1);
+       assert(pre_poll_cb2_called == 0);
        assert(test_complex_set_events_pipe1_read_called == 1);
        assert(test_complex_read_pipe1_read_called == 0);
        assert(test_complex_set_events_pipe1_write_called == 1);
@@ -856,6 +926,8 @@ test_complex(struct pr_poll_loop *poll_loop)
            pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
        assert(pr_poll_loop_exec(poll_loop) == 0);
 
+       assert(pre_poll_cb1_called == 2);
+       assert(pre_poll_cb2_called == 0);
        assert(test_complex_set_events_pipe1_read_called == 2);
        assert(test_complex_read_pipe1_read_called == 0);
        assert(test_complex_set_events_pipe1_write_called == 2);
@@ -876,6 +948,8 @@ test_complex(struct pr_poll_loop *poll_loop)
            pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
        assert(pr_poll_loop_exec(poll_loop) == 0);
 
+       assert(pre_poll_cb1_called == 3);
+       assert(pre_poll_cb2_called == 0);
        assert(test_complex_set_events_pipe1_read_called == 3);
        assert(test_complex_read_pipe1_read_called == 0);
        assert(test_complex_set_events_pipe1_write_called == 3);
@@ -897,6 +971,8 @@ test_complex(struct pr_poll_loop *poll_loop)
            pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
        assert(pr_poll_loop_exec(poll_loop) == 0);
 
+       assert(pre_poll_cb1_called == 4);
+       assert(pre_poll_cb2_called == 0);
        assert(test_complex_set_events_pipe1_read_called == 4);
        assert(test_complex_read_pipe1_read_called == 0);
        assert(test_complex_set_events_pipe1_write_called == 4);
@@ -909,6 +985,11 @@ test_complex(struct pr_poll_loop *poll_loop)
        assert(timeout_cb_called == 0);
        timer_list_delete(pr_poll_loop_get_timer_list(poll_loop), timeout_timer);
 
+       /*
+        * Delete pre poll cb
+        */
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb1) == 0);
+
        /*
         * Change state so write can propagate
         */
@@ -917,6 +998,8 @@ test_complex(struct pr_poll_loop *poll_loop)
            pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
        assert(pr_poll_loop_exec(poll_loop) == 0);
 
+       assert(pre_poll_cb1_called == 4);
+       assert(pre_poll_cb2_called == 0);
        assert(test_complex_set_events_pipe1_read_called == 5);
        assert(test_complex_read_pipe1_read_called == 1);
        assert(test_complex_set_events_pipe1_write_called == 5);
@@ -929,6 +1012,14 @@ test_complex(struct pr_poll_loop *poll_loop)
        assert(timeout_cb_called == 0);
        timer_list_delete(pr_poll_loop_get_timer_list(poll_loop), timeout_timer);
 
+       /*
+        * Add pre poll cb 1 and 2
+        */
+       assert(pr_poll_loop_add_pre_poll_cb(poll_loop, test_pre_poll_cb1,
+           &pre_poll_cb1_called, test_pre_poll_cb1) == 0);
+       assert(pr_poll_loop_add_pre_poll_cb(poll_loop, test_pre_poll_cb2,
+           &pre_poll_cb2_called, test_pre_poll_cb2) == 0);
+
        /*
         * Change state so pipe1 events are not called any longer
         */
@@ -937,6 +1028,8 @@ test_complex(struct pr_poll_loop *poll_loop)
            pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
        assert(pr_poll_loop_exec(poll_loop) == 0);
 
+       assert(pre_poll_cb1_called == 5);
+       assert(pre_poll_cb2_called == 1);
        assert(test_complex_set_events_pipe1_read_called == 6);
        assert(test_complex_read_pipe1_read_called == 1);
        assert(test_complex_set_events_pipe1_write_called == 6);
@@ -958,6 +1051,8 @@ test_complex(struct pr_poll_loop *poll_loop)
            pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
        assert(pr_poll_loop_exec(poll_loop) == 0);
 
+       assert(pre_poll_cb1_called == 6);
+       assert(pre_poll_cb2_called == 2);
        assert(test_complex_set_events_pipe1_read_called == 7);
        assert(test_complex_read_pipe1_read_called == 1);
        assert(test_complex_set_events_pipe1_write_called == 7);
@@ -977,6 +1072,8 @@ test_complex(struct pr_poll_loop *poll_loop)
            pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
        assert(pr_poll_loop_exec(poll_loop) == 0);
 
+       assert(pre_poll_cb1_called == 7);
+       assert(pre_poll_cb2_called == 3);
        assert(test_complex_set_events_pipe1_read_called == 8);
        assert(test_complex_read_pipe1_read_called == 1);
        assert(test_complex_set_events_pipe1_write_called == 8);
@@ -997,6 +1094,140 @@ test_complex(struct pr_poll_loop *poll_loop)
 
        assert(close(pipe_fd2[0]) == 0);
        assert(close(pipe_fd2[1]) == 0);
+
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb1) == 0);
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb2) == 0);
+
+       assert(pr_poll_loop_del_prfd(poll_loop, read_pipe1) == 0);
+       assert(pr_poll_loop_del_fd(poll_loop, pipe_fd1[1]) == 0);
+       assert(pr_poll_loop_del_fd(poll_loop, pipe_fd2[0]) == 0);
+       assert(pr_poll_loop_del_prfd(poll_loop, write_pipe2) == 0);
+}
+
+static void
+test_pre_poll_cb(struct pr_poll_loop *poll_loop)
+{
+       struct timer_list_entry *timeout_timer;
+
+       init_global_vars();
+
+       assert(pr_poll_loop_add_pre_poll_cb(poll_loop, test_pre_poll_cb1,
+           &pre_poll_cb1_called, test_pre_poll_cb1) == 0);
+       assert(pr_poll_loop_add_pre_poll_cb(poll_loop, test_pre_poll_cb1,
+           &pre_poll_cb1_called, test_pre_poll_cb1) == -1);
+
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb1) == 0);
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb1) == -1);
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb2) == -1);
+
+       /*
+        * Just one pre poll cb
+        */
+       pre_poll_cb1_called = 0;
+       pre_poll_cb2_called = 0;
+       pre_poll_cb_return_called = 0;
+
+       assert(pr_poll_loop_add_pre_poll_cb(poll_loop, test_pre_poll_cb1,
+           &pre_poll_cb1_called, test_pre_poll_cb1) == 0);
+
+       assert((timeout_timer = timer_list_add(
+           pr_poll_loop_get_timer_list(poll_loop), TIMER_TEST_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
+       timeout_cb_called = 0;
+
+       assert(pr_poll_loop_exec(poll_loop) == 0);
+       assert(timeout_cb_called == 1);
+       assert(pre_poll_cb1_called == 1);
+       assert(pre_poll_cb2_called == 0);
+       assert(pre_poll_cb_return_called == 0);
+
+       /*
+        * Test again
+        */
+       assert((timeout_timer = timer_list_add(
+           pr_poll_loop_get_timer_list(poll_loop), TIMER_TEST_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
+       timeout_cb_called = 0;
+
+       assert(pr_poll_loop_exec(poll_loop) == 0);
+       assert(timeout_cb_called == 1);
+       assert(pre_poll_cb1_called == 2);
+       assert(pre_poll_cb2_called == 0);
+       assert(pre_poll_cb_return_called == 0);
+
+       /*
+        * Add second cb
+        */
+       assert(pr_poll_loop_add_pre_poll_cb(poll_loop, test_pre_poll_cb2,
+           &pre_poll_cb2_called, test_pre_poll_cb2) == 0);
+
+       assert((timeout_timer = timer_list_add(
+           pr_poll_loop_get_timer_list(poll_loop), TIMER_TEST_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
+       timeout_cb_called = 0;
+
+       assert(pr_poll_loop_exec(poll_loop) == 0);
+       assert(timeout_cb_called == 1);
+       assert(pre_poll_cb1_called == 3);
+       assert(pre_poll_cb2_called == 1);
+       assert(pre_poll_cb_return_called == 0);
+
+       /*
+        * Remove cb1
+        */
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb1) == 0);
+
+       assert((timeout_timer = timer_list_add(
+           pr_poll_loop_get_timer_list(poll_loop), TIMER_TEST_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
+       timeout_cb_called = 0;
+
+       assert(pr_poll_loop_exec(poll_loop) == 0);
+       assert(timeout_cb_called == 1);
+       assert(pre_poll_cb1_called == 3);
+       assert(pre_poll_cb2_called == 2);
+       assert(pre_poll_cb_return_called == 0);
+
+       /*
+        * Add cb1 and cb return
+        */
+       assert(pr_poll_loop_add_pre_poll_cb(poll_loop, test_pre_poll_cb1,
+           &pre_poll_cb1_called, test_pre_poll_cb1) == 0);
+       assert(pr_poll_loop_add_pre_poll_cb(poll_loop, test_pre_poll_cb_return,
+           &pre_poll_cb_return_called, test_pre_poll_cb_return) == 0);
+
+       assert((timeout_timer = timer_list_add(
+           pr_poll_loop_get_timer_list(poll_loop), TIMER_TEST_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
+       timeout_cb_called = 0;
+
+       assert(pr_poll_loop_exec(poll_loop) == -1);
+       assert(timeout_cb_called == 0);
+       assert(pre_poll_cb1_called == 4);
+       assert(pre_poll_cb2_called == 3);
+       assert(pre_poll_cb_return_called == 1);
+       timer_list_delete(pr_poll_loop_get_timer_list(poll_loop), timeout_timer);
+
+       /*
+        * Remove cb_return
+        */
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb_return) == 0);
+
+       assert((timeout_timer = timer_list_add(
+           pr_poll_loop_get_timer_list(poll_loop), TIMER_TEST_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
+       timeout_cb_called = 0;
+
+       assert(pr_poll_loop_exec(poll_loop) == 0);
+
+       assert(timeout_cb_called == 1);
+       assert(pre_poll_cb1_called == 5);
+       assert(pre_poll_cb2_called == 4);
+       assert(pre_poll_cb_return_called == 1);
+
+       /*
+        * Cleanup
+        */
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb1) == 0);
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb2) == 0);
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb_return) == -1);
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb1) == -1);
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb2) == -1);
+       assert(pr_poll_loop_del_pre_poll_cb(poll_loop, test_pre_poll_cb_return) == -1);
 }
 
 int
@@ -1012,6 +1243,8 @@ main(void)
 
        test_prfd_basics(&poll_loop);
 
+       test_pre_poll_cb(&poll_loop);
+
        test_complex(&poll_loop);
 
        pr_poll_loop_destroy(&poll_loop);