tevent: Move the async wakeup pipe to common
authorVolker Lendecke <vl@samba.org>
Fri, 29 Jul 2016 06:53:59 +0000 (08:53 +0200)
committerJeremy Allison <jra@samba.org>
Tue, 23 Aug 2016 23:33:48 +0000 (01:33 +0200)
Signalling the main event loop will also happen from threads soon, and
that will use the same mechanism. This also keeps the pipe open after the last
signal handler is removed. Threaded jobs will come and go very frequently, and
always setting up and tearing down the pipe for each job will be expensive.
Also, this is "just" two file descriptors, and with eventfd just one.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
lib/tevent/ABI/tevent-0.9.29.sigs
lib/tevent/tevent.c
lib/tevent/tevent_internal.h
lib/tevent/tevent_poll.c
lib/tevent/tevent_signal.c

index 135775171eae86573bd0e5c95dfbf2f61c0eed3e..4b647419d081f52d5ec5f7d4a20cee944e1d9d0f 100644 (file)
@@ -28,10 +28,13 @@ tevent_common_fd_destructor: int (struct tevent_fd *)
 tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
 tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
 tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_have_events: bool (struct tevent_context *)
 tevent_common_loop_immediate: bool (struct tevent_context *)
 tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
 tevent_common_loop_wait: int (struct tevent_context *, const char *)
 tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_common_wakeup: int (struct tevent_context *)
+tevent_common_wakeup_init: int (struct tevent_context *)
 tevent_context_init: struct tevent_context *(TALLOC_CTX *)
 tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
 tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
index 843cf0560f3b5190f4e1f10d9bd421e0db4cc047..34cd402d5e46e69bf64e555f9a741b314cd29173 100644 (file)
@@ -620,6 +620,28 @@ done:
        return ret;
 }
 
+bool tevent_common_have_events(struct tevent_context *ev)
+{
+       if (ev->fd_events != NULL) {
+               if (ev->fd_events != ev->pipe_fde) {
+                       return true;
+               }
+               if (ev->fd_events->next != NULL) {
+                       return true;
+               }
+
+               /*
+                * At this point we just have the wakeup pipe event as
+                * the only fd_event. That one does not count as a
+                * regular event, so look at the other event types.
+                */
+       }
+
+       return ((ev->timer_events != NULL) ||
+               (ev->immediate_events != NULL) ||
+               (ev->signal_events != NULL));
+}
+
 /*
   return on failure or (with 0) if all fd events are removed
 */
@@ -629,10 +651,7 @@ int tevent_common_loop_wait(struct tevent_context *ev,
        /*
         * loop as long as we have events pending
         */
-       while (ev->fd_events ||
-              ev->timer_events ||
-              ev->immediate_events ||
-              ev->signal_events) {
+       while (tevent_common_have_events(ev)) {
                int ret;
                ret = _tevent_loop_once(ev, location);
                if (ret != 0) {
@@ -670,3 +689,63 @@ int tevent_re_initialise(struct tevent_context *ev)
 
        return ev->ops->context_init(ev);
 }
+
+static void wakeup_pipe_handler(struct tevent_context *ev,
+                               struct tevent_fd *fde,
+                               uint16_t flags, void *_private)
+{
+       ssize_t ret;
+
+       char c[16];
+       /* its non-blocking, doesn't matter if we read too much */
+       do {
+               ret = read(fde->fd, c, sizeof(c));
+       } while (ret == -1 && errno == EINTR);
+}
+
+/*
+ * Initialize the wakeup pipe and pipe fde
+ */
+
+int tevent_common_wakeup_init(struct tevent_context *ev)
+{
+       int ret;
+
+       if (ev->pipe_fde != NULL) {
+               return 0;
+       }
+
+       ret = pipe(ev->pipe_fds);
+       if (ret == -1) {
+               return errno;
+       }
+       ev_set_blocking(ev->pipe_fds[0], false);
+       ev_set_blocking(ev->pipe_fds[1], false);
+
+       ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
+                                    TEVENT_FD_READ,
+                                    wakeup_pipe_handler, NULL);
+       if (ev->pipe_fde == NULL) {
+               close(ev->pipe_fds[0]);
+               close(ev->pipe_fds[1]);
+               return ENOMEM;
+       }
+
+       return 0;
+}
+
+int tevent_common_wakeup(struct tevent_context *ev)
+{
+       ssize_t ret;
+
+       if (ev->pipe_fds[1] == -1) {
+               return ENOTCONN;
+       }
+
+       do {
+               char c = '\0';
+               ret = write(ev->pipe_fds[1], &c, 1);
+       } while ((ret == -1) && (errno == EINTR));
+
+       return 0;
+}
index 10cc4a47f83e55b64ae3b6a247e79ed9137a2654..83627705095bcecd4b75bc0fe7d40f877f6af9fc 100644 (file)
@@ -328,6 +328,10 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
                                      const char *location);
 bool tevent_common_loop_immediate(struct tevent_context *ev);
 
+bool tevent_common_have_events(struct tevent_context *ev);
+int tevent_common_wakeup_init(struct tevent_context *ev);
+int tevent_common_wakeup(struct tevent_context *ev);
+
 struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
                                               TALLOC_CTX *mem_ctx,
                                               int signum,
index e1c305d20eaea399ded2095634ccdb7a6232d2e7..3547e912b2c07ba3cdabe2fbc5f8376646410c23 100644 (file)
@@ -667,10 +667,7 @@ static int poll_event_loop_wait(struct tevent_context *ev,
        /*
         * loop as long as we have events pending
         */
-       while (ev->fd_events ||
-              ev->timer_events ||
-              ev->immediate_events ||
-              ev->signal_events ||
+       while (tevent_common_have_events(ev) ||
               poll_ev->fresh ||
               poll_ev->disabled) {
                int ret;
index 635a7a177aa976b8e9c62f7dd6b221eb5b665abc..c85e1c528c4ef3579fa006e5bd9a42c027ddaf1c 100644 (file)
@@ -95,7 +95,6 @@ static uint32_t tevent_sig_count(struct tevent_sigcounter s)
 */
 static void tevent_common_signal_handler(int signum)
 {
-       char c = 0;
        struct tevent_common_signal_list *sl;
        struct tevent_context *ev = NULL;
        int saved_errno = errno;
@@ -106,13 +105,8 @@ static void tevent_common_signal_handler(int signum)
        /* Write to each unique event context. */
        for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
                if (sl->se->event_ctx && sl->se->event_ctx != ev) {
-                       ssize_t ret;
-
                        ev = sl->se->event_ctx;
-                       /* doesn't matter if this pipe overflows */
-                       do {
-                               ret = write(ev->pipe_fds[1], &c, 1);
-                       } while (ret == -1 && errno == EINTR);
+                       tevent_common_wakeup(ev);
                }
        }
 
@@ -198,16 +192,6 @@ static int tevent_signal_destructor(struct tevent_signal *se)
                struct tevent_context *ev = se->event_ctx;
 
                DLIST_REMOVE(ev->signal_events, se);
-
-               if (ev->signal_events == NULL && ev->pipe_fde != NULL) {
-                       /*
-                        * This was the last signal. Destroy the pipe.
-                        */
-                       TALLOC_FREE(ev->pipe_fde);
-
-                       close(ev->pipe_fds[0]);
-                       close(ev->pipe_fds[1]);
-               }
        }
 
        talloc_free(sl);
@@ -232,21 +216,6 @@ static int tevent_signal_destructor(struct tevent_signal *se)
        return 0;
 }
 
-/*
-  this is part of the pipe hack needed to avoid the signal race condition
-*/
-static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, 
-                               uint16_t flags, void *_private)
-{
-       ssize_t ret;
-
-       char c[16];
-       /* its non-blocking, doesn't matter if we read too much */
-       do {
-               ret = read(fde->fd, c, sizeof(c));
-       } while (ret == -1 && errno == EINTR);
-}
-
 /*
   add a signal event
   return NULL on failure (memory allocation error)
@@ -263,6 +232,13 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
        struct tevent_signal *se;
        struct tevent_common_signal_list *sl;
        sigset_t set, oldset;
+       int ret;
+
+       ret = tevent_common_wakeup_init(ev);
+       if (ret != 0) {
+               errno = ret;
+               return NULL;
+       }
 
        if (signum >= TEVENT_NUM_SIGNALS) {
                errno = EINVAL;
@@ -304,26 +280,6 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
                return NULL;
        }
 
-       /* we need to setup the pipe hack handler if not already
-          setup */
-       if (ev->pipe_fde == NULL) {
-               if (pipe(ev->pipe_fds) == -1) {
-                       talloc_free(se);
-                       return NULL;
-               }
-               ev_set_blocking(ev->pipe_fds[0], false);
-               ev_set_blocking(ev->pipe_fds[1], false);
-               ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
-                                            TEVENT_FD_READ,
-                                            signal_pipe_handler, NULL);
-               if (!ev->pipe_fde) {
-                       close(ev->pipe_fds[0]);
-                       close(ev->pipe_fds[1]);
-                       talloc_free(se);
-                       return NULL;
-               }
-       }
-
        /* only install a signal handler if not already installed */
        if (sig_state->sig_handlers[signum] == NULL) {
                struct sigaction act;