ソースを参照

pr-poll-loop: Add pre poll callbacks

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Jan Friesse 5 年 前
コミット
ea6d7a909d
3 ファイル変更407 行追加38 行削除
  1. 122 6
      qdevices/pr-poll-loop.c
  2. 20 0
      qdevices/pr-poll-loop.h
  3. 265 32
      qdevices/test-pr-poll-loop.c

+ 122 - 6
qdevices/pr-poll-loop.c

@@ -53,11 +53,11 @@
 /*
 /*
  * Helper functions declarations
  * 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,
     int fd, PRFileDesc *prfd,
     short events, pr_poll_loop_fd_set_events_cb_fn fd_set_events_cb,
     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,
     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,
     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);
     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);
     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);
 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);
 	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
 static
 int prepare_poll_array(struct pr_poll_loop *poll_loop)
 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;
 	struct pr_poll_loop_fd_entry *fd_entry_next;
 	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;
 	struct pr_poll_loop_fd_entry **user_data;
 	short events;
 	short events;
 	int res;
 	int res;
@@ -254,6 +275,40 @@ int prepare_poll_array(struct pr_poll_loop *poll_loop)
 
 
 	pr_poll_array_clean(poll_array);
 	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
 	 * 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));
 	memset(poll_loop, 0, sizeof(*poll_loop));
 
 
 	TAILQ_INIT(&(poll_loop->fd_list));
 	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 *));
 	pr_poll_array_init(&poll_loop->poll_array, sizeof(struct pr_poll_loop_fd_entry *));
 	timer_list_init(&poll_loop->tlist);
 	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));
 	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
 int
 pr_poll_loop_del_prfd(struct pr_poll_loop *poll_loop, PRFileDesc *prfd)
 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;
 	struct pr_poll_loop_fd_entry *fd_entry_next;
 	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);
 	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));
 	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);
 	pr_poll_array_destroy(&poll_loop->poll_array);
 	timer_list_free(&poll_loop->tlist);
 	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));
 	    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
 int
 pr_poll_loop_add_prfd(struct pr_poll_loop *poll_loop, PRFileDesc *prfd,
 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,
     short events, pr_poll_loop_prfd_set_events_cb_fn prfd_set_events_cb,

+ 20 - 0
qdevices/pr-poll-loop.h

@@ -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,
 typedef int (*pr_poll_loop_prfd_err_cb_fn)(PRFileDesc *prfd, short revents, const PRPollDesc *pd,
     void *user_data1, void *user_data2);
     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 {
 struct pr_poll_loop_fd_entry {
 	int fd;
 	int fd;
 	PRFileDesc *prfd;
 	PRFileDesc *prfd;
@@ -94,8 +99,16 @@ struct pr_poll_loop_fd_entry {
 	TAILQ_ENTRY(pr_poll_loop_fd_entry) entries;
 	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 {
 struct pr_poll_loop {
 	TAILQ_HEAD(, pr_poll_loop_fd_entry) fd_list;
 	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 timer_list tlist;
 	struct pr_poll_array poll_array;
 	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,
     pr_poll_loop_fd_err_cb_fn fd_err_cb,
     void *user_data1, void *user_data2);
     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,
 extern int			 pr_poll_loop_add_prfd(struct pr_poll_loop *poll_loop,
     PRFileDesc *prfd, short events,
     PRFileDesc *prfd, short events,
     pr_poll_loop_prfd_set_events_cb_fn prfd_set_events_cb,
     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_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,
 extern int			 pr_poll_loop_del_prfd(struct pr_poll_loop *poll_loop,
     PRFileDesc *prfd);
     PRFileDesc *prfd);
 
 

+ 265 - 32
qdevices/test-pr-poll-loop.c

@@ -54,31 +54,35 @@
  */
  */
 #define READ_STR		"test"
 #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
 static int
 timeout_cb(void *data1, void *data2)
 timeout_cb(void *data1, void *data2)
@@ -402,6 +406,39 @@ test_complex_write_pipe2_write_cb(PRFileDesc *prfd, const PRPollDesc *pd, void *
 	return (0);
 	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
 static void
 init_global_vars(void)
 init_global_vars(void)
 {
 {
@@ -419,6 +456,16 @@ init_global_vars(void)
 	prfd_read_cb2_called = -1;
 	prfd_read_cb2_called = -1;
 	prfd_write_cb1_called = -1;
 	prfd_write_cb1_called = -1;
 	prfd_err_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
 static void
@@ -429,25 +476,27 @@ test_fd_basics(struct pr_poll_loop *poll_loop)
 
 
 	init_global_vars();
 	init_global_vars();
 
 
+	assert(pipe(pipe_fd1) == 0);
+
 	/*
 	/*
 	 * Add POLLNVAL -> failure
 	 * 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);
 	    NULL, NULL) == -1);
 	/*
 	/*
 	 * Del non-existing fdL -> failure
 	 * 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
 	 * 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);
 	    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);
 	    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
 	 * Test timeout timer
@@ -462,7 +511,6 @@ test_fd_basics(struct pr_poll_loop *poll_loop)
 	/*
 	/*
 	 * Test user_data passing
 	 * 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,
 	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);
 	    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;
 	PRFileDesc *write_pipe2;
 	struct timer_list_entry *timeout_timer;
 	struct timer_list_entry *timeout_timer;
 
 
+	init_global_vars();
+
 	assert(pipe(pipe_fd1) == 0);
 	assert(pipe(pipe_fd1) == 0);
 	assert(pipe(pipe_fd2) == 0);
 	assert(pipe(pipe_fd2) == 0);
 
 
 	test_complex_read_pipe1_fd = pipe_fd1[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((read_pipe1 = PR_CreateSocketPollFd(pipe_fd1[0])) != NULL);
 	assert((write_pipe2 = PR_CreateSocketPollFd(pipe_fd2[1])) != 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_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);
 	    &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
 	 * 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);
 	    pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
 	assert(pr_poll_loop_exec(poll_loop) == 0);
 	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_set_events_pipe1_read_called == 1);
 	assert(test_complex_read_pipe1_read_called == 0);
 	assert(test_complex_read_pipe1_read_called == 0);
 	assert(test_complex_set_events_pipe1_write_called == 1);
 	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);
 	    pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
 	assert(pr_poll_loop_exec(poll_loop) == 0);
 	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_set_events_pipe1_read_called == 2);
 	assert(test_complex_read_pipe1_read_called == 0);
 	assert(test_complex_read_pipe1_read_called == 0);
 	assert(test_complex_set_events_pipe1_write_called == 2);
 	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);
 	    pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
 	assert(pr_poll_loop_exec(poll_loop) == 0);
 	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_set_events_pipe1_read_called == 3);
 	assert(test_complex_read_pipe1_read_called == 0);
 	assert(test_complex_read_pipe1_read_called == 0);
 	assert(test_complex_set_events_pipe1_write_called == 3);
 	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);
 	    pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
 	assert(pr_poll_loop_exec(poll_loop) == 0);
 	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_set_events_pipe1_read_called == 4);
 	assert(test_complex_read_pipe1_read_called == 0);
 	assert(test_complex_read_pipe1_read_called == 0);
 	assert(test_complex_set_events_pipe1_write_called == 4);
 	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);
 	assert(timeout_cb_called == 0);
 	timer_list_delete(pr_poll_loop_get_timer_list(poll_loop), timeout_timer);
 	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
 	 * 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);
 	    pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
 	assert(pr_poll_loop_exec(poll_loop) == 0);
 	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_set_events_pipe1_read_called == 5);
 	assert(test_complex_read_pipe1_read_called == 1);
 	assert(test_complex_read_pipe1_read_called == 1);
 	assert(test_complex_set_events_pipe1_write_called == 5);
 	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);
 	assert(timeout_cb_called == 0);
 	timer_list_delete(pr_poll_loop_get_timer_list(poll_loop), timeout_timer);
 	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
 	 * 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);
 	    pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
 	assert(pr_poll_loop_exec(poll_loop) == 0);
 	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_set_events_pipe1_read_called == 6);
 	assert(test_complex_read_pipe1_read_called == 1);
 	assert(test_complex_read_pipe1_read_called == 1);
 	assert(test_complex_set_events_pipe1_write_called == 6);
 	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);
 	    pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
 	assert(pr_poll_loop_exec(poll_loop) == 0);
 	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_set_events_pipe1_read_called == 7);
 	assert(test_complex_read_pipe1_read_called == 1);
 	assert(test_complex_read_pipe1_read_called == 1);
 	assert(test_complex_set_events_pipe1_write_called == 7);
 	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);
 	    pr_poll_loop_get_timer_list(poll_loop), TIMER_TIMEOUT, timeout_cb, NULL, NULL)) != NULL);
 	assert(pr_poll_loop_exec(poll_loop) == 0);
 	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_set_events_pipe1_read_called == 8);
 	assert(test_complex_read_pipe1_read_called == 1);
 	assert(test_complex_read_pipe1_read_called == 1);
 	assert(test_complex_set_events_pipe1_write_called == 8);
 	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[0]) == 0);
 	assert(close(pipe_fd2[1]) == 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
 int
@@ -1012,6 +1243,8 @@ main(void)
 
 
 	test_prfd_basics(&poll_loop);
 	test_prfd_basics(&poll_loop);
 
 
+	test_pre_poll_cb(&poll_loop);
+
 	test_complex(&poll_loop);
 	test_complex(&poll_loop);
 
 
 	pr_poll_loop_destroy(&poll_loop);
 	pr_poll_loop_destroy(&poll_loop);