tevent: Use eventfd for signal/thread wakeup
authorVolker Lendecke <vl@samba.org>
Fri, 12 Aug 2016 14:32:33 +0000 (16:32 +0200)
committerJeremy Allison <jra@samba.org>
Tue, 23 Aug 2016 23:33:48 +0000 (01:33 +0200)
According to the manpage, eventfd is cheaper than a pipe. At least, we can save
a file descriptor and space for it in struct tevent_context :-)

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

index e35eb5ddc93a86c0b68a4949a3ee3611eb19c3a7..331be0eb11089c71f2a892e30680ab5c17a3a396 100644 (file)
@@ -66,6 +66,9 @@
 #include "tevent.h"
 #include "tevent_internal.h"
 #include "tevent_util.h"
+#ifdef HAVE_EVENTFD
+#include <sys/eventfd.h>
+#endif
 
 static void tevent_abort(struct tevent_context *ev, const char *reason);
 
@@ -767,7 +770,7 @@ done:
 bool tevent_common_have_events(struct tevent_context *ev)
 {
        if (ev->fd_events != NULL) {
-               if (ev->fd_events != ev->pipe_fde) {
+               if (ev->fd_events != ev->wakeup_fde) {
                        return true;
                }
                if (ev->fd_events->next != NULL) {
@@ -840,10 +843,14 @@ static void wakeup_pipe_handler(struct tevent_context *ev,
 {
        ssize_t ret;
 
-       /* its non-blocking, doesn't matter if we read too much */
        do {
-               char c[16];
-               ret = read(fde->fd, c, sizeof(c));
+               /*
+                * This is the boilerplate for eventfd, but it works
+                * for pipes too. And as we don't care about the data
+                * we read, we're fine.
+                */
+               uint64_t val;
+               ret = read(fde->fd, &val, sizeof(val));
        } while (ret == -1 && errno == EINTR);
 }
 
@@ -855,23 +862,39 @@ int tevent_common_wakeup_init(struct tevent_context *ev)
 {
        int ret;
 
-       if (ev->pipe_fde != NULL) {
+       if (ev->wakeup_fde != NULL) {
                return 0;
        }
 
-       ret = pipe(ev->pipe_fds);
+#ifdef HAVE_EVENTFD
+       ret = eventfd(0, EFD_NONBLOCK);
        if (ret == -1) {
                return errno;
        }
-       ev_set_blocking(ev->pipe_fds[0], false);
-       ev_set_blocking(ev->pipe_fds[1], false);
+       ev->wakeup_fd = ret;
+#else
+       {
+               int pipe_fds[2];
+               ret = pipe(pipe_fds);
+               if (ret == -1) {
+                       return errno;
+               }
+               ev->wakeup_fd = pipe_fds[0];
+               ev->wakeup_write_fd = pipe_fds[1];
+
+               ev_set_blocking(ev->wakeup_fd, false);
+               ev_set_blocking(ev->wakeup_write_fd, false);
+       }
+#endif
 
-       ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
+       ev->wakeup_fde = tevent_add_fd(ev, ev, ev->wakeup_fd,
                                     TEVENT_FD_READ,
                                     wakeup_pipe_handler, NULL);
-       if (ev->pipe_fde == NULL) {
-               close(ev->pipe_fds[0]);
-               close(ev->pipe_fds[1]);
+       if (ev->wakeup_fde == NULL) {
+               close(ev->wakeup_fd);
+#ifndef HAVE_EVENTFD
+               close(ev->wakeup_write_fd);
+#endif
                return ENOMEM;
        }
 
@@ -882,13 +905,18 @@ int tevent_common_wakeup(struct tevent_context *ev)
 {
        ssize_t ret;
 
-       if (ev->pipe_fds[1] == -1) {
+       if (ev->wakeup_fde == NULL) {
                return ENOTCONN;
        }
 
        do {
+#ifdef HAVE_EVENTFD
+               uint64_t val = 1;
+               ret = write(ev->wakeup_fd, &val, sizeof(val));
+#else
                char c = '\0';
-               ret = write(ev->pipe_fds[1], &c, 1);
+               ret = write(ev->wakeup_write_fd, &c, 1);
+#endif
        } while ((ret == -1) && (errno == EINTR));
 
        return 0;
@@ -896,12 +924,14 @@ int tevent_common_wakeup(struct tevent_context *ev)
 
 static void tevent_common_wakeup_fini(struct tevent_context *ev)
 {
-       if (ev->pipe_fde == NULL) {
+       if (ev->wakeup_fde == NULL) {
                return;
        }
 
-       TALLOC_FREE(ev->pipe_fde);
+       TALLOC_FREE(ev->wakeup_fde);
 
-       close(ev->pipe_fds[0]);
-       close(ev->pipe_fds[1]);
+       close(ev->wakeup_fd);
+#ifndef HAVE_EVENTFD
+       close(ev->wakeup_write_fd);
+#endif
 }
index f17ce9403652c72b5e0d0b0e548e9e0635e3208f..d960544970816d9740705a2748a7afe3fc4f81d8 100644 (file)
@@ -276,8 +276,11 @@ struct tevent_context {
        void *additional_data;
 
        /* pipe hack used with signal handlers */
-       struct tevent_fd *pipe_fde;
-       int pipe_fds[2];
+       struct tevent_fd *wakeup_fde;
+       int wakeup_fd;
+#ifndef HAVE_EVENT_FD
+       int wakeup_write_fd;
+#endif
 
        /* debugging operations */
        struct tevent_debug_ops debug_ops;