tevent: add support for immediate events
authorStefan Metzmacher <metze@samba.org>
Fri, 13 Mar 2009 14:47:33 +0000 (15:47 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 17 Mar 2009 18:59:00 +0000 (19:59 +0100)
They're like directly triggered timed events,
but you can preallocated them and scheduling them
will not fail.

metze

lib/tevent/libtevent.m4
lib/tevent/tevent.c
lib/tevent/tevent.h
lib/tevent/tevent_epoll.c
lib/tevent/tevent_immediate.c [new file with mode: 0644]
lib/tevent/tevent_internal.h
lib/tevent/tevent_select.c
lib/tevent/tevent_standard.c

index c316823a715c42928d95288591b372b6b72ecf63..20730b17d646efd78fb5057ae45c14e6aed853f3 100644 (file)
@@ -26,7 +26,8 @@ AC_SUBST(TEVENT_LIBS)
 
 TEVENT_CFLAGS="-I$teventdir"
 
-TEVENT_OBJ="tevent.o tevent_fd.o tevent_timed.o tevent_signal.o tevent_debug.o tevent_util.o"
+TEVENT_OBJ="tevent.o tevent_debug.o tevent_util.o"
+TEVENT_OBJ="$TEVENT_OBJ tevent_fd.o tevent_timed.o tevent_immediate.o tevent_signal.o"
 TEVENT_OBJ="$TEVENT_OBJ tevent_req.o tevent_wakeup.o tevent_queue.o"
 TEVENT_OBJ="$TEVENT_OBJ tevent_standard.o tevent_select.o"
 
index 31dc58d98e8c42cb2a453fa793e357f44170bd8c..ba2d93f4b98051e7f3abadc45a675c58b1a12b5e 100644 (file)
@@ -143,6 +143,7 @@ int tevent_common_context_destructor(struct tevent_context *ev)
 {
        struct tevent_fd *fd, *fn;
        struct tevent_timer *te, *tn;
+       struct tevent_immediate *ie, *in;
        struct tevent_signal *se, *sn;
 
        if (ev->pipe_fde) {
@@ -162,6 +163,13 @@ int tevent_common_context_destructor(struct tevent_context *ev)
                DLIST_REMOVE(ev->timer_events, te);
        }
 
+       for (ie = ev->immediate_events; ie; ie = in) {
+               in = ie->next;
+               ie->event_ctx = NULL;
+               ie->cancel_fn = NULL;
+               DLIST_REMOVE(ev->immediate_events, ie);
+       }
+
        for (se = ev->signal_events; se; se = sn) {
                sn = se->next;
                se->event_ctx = NULL;
@@ -349,6 +357,47 @@ struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
                                  handler_name, location);
 }
 
+/*
+  allocate an immediate event
+  return NULL on failure (memory allocation error)
+*/
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+                                                 const char *location)
+{
+       struct tevent_immediate *im;
+
+       im = talloc(mem_ctx, struct tevent_immediate);
+       if (im == NULL) return NULL;
+
+       im->prev                = NULL;
+       im->next                = NULL;
+       im->event_ctx           = NULL;
+       im->create_location     = location;
+       im->handler             = NULL;
+       im->private_data        = NULL;
+       im->handler_name        = NULL;
+       im->schedule_location   = NULL;
+       im->cancel_fn           = NULL;
+       im->additional_data     = NULL;
+
+       return im;
+}
+
+/*
+  schedule an immediate event
+  return NULL on failure
+*/
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+                               struct tevent_context *ev,
+                               tevent_immediate_handler_t handler,
+                               void *private_data,
+                               const char *handler_name,
+                               const char *location)
+{
+       ev->ops->schedule_immediate(im, ev, handler, private_data,
+                                   handler_name, location);
+}
+
 /*
   add a signal event
 
index 4a3f51ae5eedb4fe90e253845c240118bf63910a..6e64a8cdd93d450ead0e5800d0c5b6340b11e320 100644 (file)
@@ -37,6 +37,7 @@ struct tevent_context;
 struct tevent_ops;
 struct tevent_fd;
 struct tevent_timer;
+struct tevent_immediate;
 struct tevent_signal;
 
 /* event handler types */
@@ -52,6 +53,9 @@ typedef void (*tevent_timer_handler_t)(struct tevent_context *ev,
                                       struct tevent_timer *te,
                                       struct timeval current_time,
                                       void *private_data);
+typedef void (*tevent_immediate_handler_t)(struct tevent_context *ctx,
+                                          struct tevent_immediate *im,
+                                          void *private_data);
 typedef void (*tevent_signal_handler_t)(struct tevent_context *ev,
                                        struct tevent_signal *se,
                                        int signum,
@@ -87,6 +91,21 @@ struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
        _tevent_add_timer(ev, mem_ctx, next_event, handler, private_data, \
                          #handler, __location__)
 
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+                                                 const char *location);
+#define tevent_create_immediate(mem_ctx) \
+       _tevent_create_immediate(mem_ctx, __location__)
+
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+                               struct tevent_context *ctx,
+                               tevent_immediate_handler_t handler,
+                               void *private_data,
+                               const char *handler_name,
+                               const char *location);
+#define tevent_schedule_immediate(im, ctx, handler, private_data) \
+       _tevent_schedule_immediate(im, ctx, handler, private_data, \
+                                  #handler, __location__);
+
 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
                                         TALLOC_CTX *mem_ctx,
                                         int signum,
index 32544593de06e2e7016040036e650d7a14390b2b..7c7f389d5b9879889da4006fa7fd6a79abcb6995 100644 (file)
@@ -404,8 +404,13 @@ static int epoll_event_loop_once(struct tevent_context *ev, const char *location
                                                           struct epoll_event_context);
        struct timeval tval;
 
-       if (epoll_ev->ev->signal_events &&
-           tevent_common_check_signal(epoll_ev->ev)) {
+       if (ev->signal_events &&
+           tevent_common_check_signal(ev)) {
+               return 0;
+       }
+
+       if (ev->immediate_events &&
+           tevent_common_loop_immediate(ev)) {
                return 0;
        }
 
@@ -420,15 +425,16 @@ static int epoll_event_loop_once(struct tevent_context *ev, const char *location
 }
 
 static const struct tevent_ops epoll_event_ops = {
-       .context_init   = epoll_event_context_init,
-       .add_fd         = epoll_event_add_fd,
-       .set_fd_close_fn= tevent_common_fd_set_close_fn,
-       .get_fd_flags   = tevent_common_fd_get_flags,
-       .set_fd_flags   = epoll_event_set_fd_flags,
-       .add_timer      = tevent_common_add_timer,
-       .add_signal     = tevent_common_add_signal,
-       .loop_once      = epoll_event_loop_once,
-       .loop_wait      = tevent_common_loop_wait,
+       .context_init           = epoll_event_context_init,
+       .add_fd                 = epoll_event_add_fd,
+       .set_fd_close_fn        = tevent_common_fd_set_close_fn,
+       .get_fd_flags           = tevent_common_fd_get_flags,
+       .set_fd_flags           = epoll_event_set_fd_flags,
+       .add_timer              = tevent_common_add_timer,
+       .schedule_immediate     = tevent_common_schedule_immediate,
+       .add_signal             = tevent_common_add_signal,
+       .loop_once              = epoll_event_loop_once,
+       .loop_wait              = tevent_common_loop_wait,
 };
 
 bool tevent_epoll_init(void)
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
new file mode 100644 (file)
index 0000000..1ac293e
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   common events code for immediate events
+
+   Copyright (C) Stefan Metzmacher 2009
+
+     ** NOTE! The following LGPL license applies to the tevent
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+static void tevent_common_immediate_cancel(struct tevent_immediate *im)
+{
+       if (!im->event_ctx) {
+               return;
+       }
+
+       tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
+                    "Cancel immediate event %p \"%s\"\n",
+                    im, im->handler_name);
+
+       /* let the backend free im->additional_data */
+       if (im->cancel_fn) {
+               im->cancel_fn(im);
+       }
+
+       DLIST_REMOVE(im->event_ctx->immediate_events, im);
+       im->event_ctx           = NULL;
+       im->handler             = NULL;
+       im->private_data        = NULL;
+       im->handler_name        = NULL;
+       im->schedule_location   = NULL;
+       im->cancel_fn           = NULL;
+       im->additional_data     = NULL;
+
+       talloc_set_destructor(im, NULL);
+}
+
+/*
+  destroy an immediate event
+*/
+static int tevent_common_immediate_destructor(struct tevent_immediate *im)
+{
+       tevent_common_immediate_cancel(im);
+       return 0;
+}
+
+/*
+ * schedule an immediate event on
+ */
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+                                     struct tevent_context *ev,
+                                     tevent_immediate_handler_t handler,
+                                     void *private_data,
+                                     const char *handler_name,
+                                     const char *location)
+{
+       tevent_common_immediate_cancel(im);
+
+       if (!handler) {
+               return;
+       }
+
+       im->event_ctx           = ev;
+       im->handler             = handler;
+       im->private_data        = private_data;
+       im->handler_name        = handler_name;
+       im->schedule_location   = location;
+       im->cancel_fn           = NULL;
+       im->additional_data     = NULL;
+
+       DLIST_ADD_END(ev->immediate_events, im, struct tevent_immediate *);
+       talloc_set_destructor(im, tevent_common_immediate_destructor);
+
+       tevent_debug(ev, TEVENT_DEBUG_TRACE,
+                    "Schedule immediate event \"%s\": %p\n",
+                    handler_name, im);
+}
+
+/*
+  trigger the first immediate event and return true
+  if no event was triggered return false
+*/
+bool tevent_common_loop_immediate(struct tevent_context *ev)
+{
+       struct tevent_immediate *im = ev->immediate_events;
+       tevent_immediate_handler_t handler;
+       void *private_data;
+
+       if (!im) {
+               return false;
+       }
+
+       tevent_debug(ev, TEVENT_DEBUG_TRACE,
+                    "Run immediate event \"%s\": %p\n",
+                    im->handler_name, im);
+
+       /*
+        * remember the handler and then clear the event
+        * the handler might reschedule the event
+        */
+       handler = im->handler;
+       private_data = im->private_data;
+
+       DLIST_REMOVE(im->event_ctx->immediate_events, im);
+       im->event_ctx           = NULL;
+       im->handler             = NULL;
+       im->private_data        = NULL;
+       im->handler_name        = NULL;
+       im->schedule_location   = NULL;
+       im->cancel_fn           = NULL;
+       im->additional_data     = NULL;
+
+       talloc_set_destructor(im, NULL);
+
+       handler(ev, im, private_data);
+
+       return true;
+}
+
index f63a58aadda7f8cf4436e32a658ef1d3a47fec4d..cf54242da1a2b5283e8711447f863d72db2eb24c 100644 (file)
@@ -143,6 +143,15 @@ struct tevent_ops {
                                          void *private_data,
                                          const char *handler_name,
                                          const char *location);
+
+       /* immediate event functions */
+       void (*schedule_immediate)(struct tevent_immediate *im,
+                                  struct tevent_context *ev,
+                                  tevent_immediate_handler_t handler,
+                                  void *private_data,
+                                  const char *handler_name,
+                                  const char *location);
+
        /* signal functions */
        struct tevent_signal *(*add_signal)(struct tevent_context *ev,
                                            TALLOC_CTX *mem_ctx,
@@ -188,6 +197,21 @@ struct tevent_timer {
        void *additional_data;
 };
 
+struct tevent_immediate {
+       struct tevent_immediate *prev, *next;
+       struct tevent_context *event_ctx;
+       tevent_immediate_handler_t handler;
+       /* this is private for the specific handler */
+       void *private_data;
+       /* this is for debugging only! */
+       const char *handler_name;
+       const char *create_location;
+       const char *schedule_location;
+       /* this is private for the events_ops implementation */
+       void (*cancel_fn)(struct tevent_immediate *im);
+       void *additional_data;
+};
+
 struct tevent_signal {
        struct tevent_signal *prev, *next;
        struct tevent_context *event_ctx;
@@ -222,6 +246,9 @@ struct tevent_context {
        /* list of timed events - used by common code */
        struct tevent_timer *timer_events;
 
+       /* list of immediate events - used by common code */
+       struct tevent_immediate *immediate_events;
+
        /* list of signal events - used by common code */
        struct tevent_signal *signal_events;
 
@@ -273,6 +300,14 @@ struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
                                             const char *location);
 struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
 
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+                                     struct tevent_context *ev,
+                                     tevent_immediate_handler_t handler,
+                                     void *private_data,
+                                     const char *handler_name,
+                                     const char *location);
+bool tevent_common_loop_immediate(struct tevent_context *ev);
+
 struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
                                               TALLOC_CTX *mem_ctx,
                                               int signum,
index 1c295d7ca471267d598b1ee6c88871b9caaa0118..d97418991ae3e3dd8bec6edd13d7fb5a0144b0ff 100644 (file)
@@ -210,8 +210,13 @@ static int select_event_loop_once(struct tevent_context *ev, const char *locatio
                                                           struct select_event_context);
        struct timeval tval;
 
-       if (select_ev->ev->signal_events &&
-           tevent_common_check_signal(select_ev->ev)) {
+       if (ev->signal_events &&
+           tevent_common_check_signal(ev)) {
+               return 0;
+       }
+
+       if (ev->immediate_events &&
+           tevent_common_loop_immediate(ev)) {
                return 0;
        }
 
@@ -224,15 +229,16 @@ static int select_event_loop_once(struct tevent_context *ev, const char *locatio
 }
 
 static const struct tevent_ops select_event_ops = {
-       .context_init   = select_event_context_init,
-       .add_fd         = select_event_add_fd,
-       .set_fd_close_fn= tevent_common_fd_set_close_fn,
-       .get_fd_flags   = tevent_common_fd_get_flags,
-       .set_fd_flags   = tevent_common_fd_set_flags,
-       .add_timer      = tevent_common_add_timer,
-       .add_signal     = tevent_common_add_signal,
-       .loop_once      = select_event_loop_once,
-       .loop_wait      = tevent_common_loop_wait,
+       .context_init           = select_event_context_init,
+       .add_fd                 = select_event_add_fd,
+       .set_fd_close_fn        = tevent_common_fd_set_close_fn,
+       .get_fd_flags           = tevent_common_fd_get_flags,
+       .set_fd_flags           = tevent_common_fd_set_flags,
+       .add_timer              = tevent_common_add_timer,
+       .schedule_immediate     = tevent_common_schedule_immediate,
+       .add_signal             = tevent_common_add_signal,
+       .loop_once              = select_event_loop_once,
+       .loop_wait              = tevent_common_loop_wait,
 };
 
 bool tevent_select_init(void)
index 88db6a172576422c8c66d9739b8f956abb925028..c3f8b36e840faf52773d1e7c6327a23cf909c7c4 100644 (file)
@@ -524,8 +524,13 @@ static int std_event_loop_once(struct tevent_context *ev, const char *location)
                                                           struct std_event_context);
        struct timeval tval;
 
-       if (std_ev->ev->signal_events &&
-           tevent_common_check_signal(std_ev->ev)) {
+       if (ev->signal_events &&
+           tevent_common_check_signal(ev)) {
+               return 0;
+       }
+
+       if (ev->immediate_events &&
+           tevent_common_loop_immediate(ev)) {
                return 0;
        }
 
@@ -544,15 +549,16 @@ static int std_event_loop_once(struct tevent_context *ev, const char *location)
 }
 
 static const struct tevent_ops std_event_ops = {
-       .context_init   = std_event_context_init,
-       .add_fd         = std_event_add_fd,
-       .set_fd_close_fn= tevent_common_fd_set_close_fn,
-       .get_fd_flags   = tevent_common_fd_get_flags,
-       .set_fd_flags   = std_event_set_fd_flags,
-       .add_timer      = tevent_common_add_timer,
-       .add_signal     = tevent_common_add_signal,
-       .loop_once      = std_event_loop_once,
-       .loop_wait      = tevent_common_loop_wait,
+       .context_init           = std_event_context_init,
+       .add_fd                 = std_event_add_fd,
+       .set_fd_close_fn        = tevent_common_fd_set_close_fn,
+       .get_fd_flags           = tevent_common_fd_get_flags,
+       .set_fd_flags           = std_event_set_fd_flags,
+       .add_timer              = tevent_common_add_timer,
+       .schedule_immediate     = tevent_common_schedule_immediate,
+       .add_signal             = tevent_common_add_signal,
+       .loop_once              = std_event_loop_once,
+       .loop_wait              = tevent_common_loop_wait,
 };