summaryrefslogtreecommitdiff
path: root/lib/tevent/tevent.c
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2016-07-29 08:53:59 +0200
committerJeremy Allison <jra@samba.org>2016-08-24 01:33:48 +0200
commit8a9b8ac72461657a3a5de2fd5232eaa9861bf696 (patch)
tree46587574e9189441cd8698e0461b359533b399e6 /lib/tevent/tevent.c
parentc4ef0c8f3ecc4266fed3af8537ba2998730b3750 (diff)
downloadsamba-8a9b8ac72461657a3a5de2fd5232eaa9861bf696.tar.gz
tevent: Move the async wakeup pipe to common
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>
Diffstat (limited to 'lib/tevent/tevent.c')
-rw-r--r--lib/tevent/tevent.c87
1 files changed, 83 insertions, 4 deletions
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index 843cf0560f3..34cd402d5e4 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -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;
+}