tevent: add tevent_context_wrapper_create() infrastructure
authorStefan Metzmacher <metze@samba.org>
Tue, 22 Jul 2014 14:51:38 +0000 (16:51 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 17 May 2018 07:51:48 +0000 (09:51 +0200)
This allows to specify wrapper tevent_contexts which adds the ability
to run functions before and after the event handler functions.

This can be used to implement impersonation hooks
or advanced debugging/profiling hooks.

lib/tevent/tevent.c
lib/tevent/tevent.h
lib/tevent/tevent_debug.c
lib/tevent/tevent_fd.c
lib/tevent/tevent_immediate.c
lib/tevent/tevent_internal.h
lib/tevent/tevent_signal.c
lib/tevent/tevent_threads.c
lib/tevent/tevent_timed.c
lib/tevent/tevent_wrapper.c [new file with mode: 0644]
lib/tevent/wscript

index 08a7896016a01487de27f2b2f9a42d7e7740ab99..90094000f99e626d229cd056f38ebb2448921d17 100644 (file)
@@ -298,6 +298,7 @@ int tevent_common_context_destructor(struct tevent_context *ev)
        struct tevent_timer *te, *tn;
        struct tevent_immediate *ie, *in;
        struct tevent_signal *se, *sn;
+       struct tevent_wrapper_glue *gl, *gn;
 
 #ifdef HAVE_PTHREAD
        int ret;
@@ -345,6 +346,13 @@ int tevent_common_context_destructor(struct tevent_context *ev)
        }
 #endif
 
+       for (gl = ev->wrapper.list; gl; gl = gn) {
+               gn = gl->next;
+
+               gl->main_ev = NULL;
+               DLIST_REMOVE(ev->wrapper.list, gl);
+       }
+
        tevent_common_wakeup_fini(ev);
 
        for (fd = ev->fd_events; fd; fd = fn) {
@@ -675,6 +683,16 @@ struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
 
 void tevent_loop_allow_nesting(struct tevent_context *ev)
 {
+       if (ev->wrapper.glue != NULL) {
+               tevent_abort(ev, "tevent_loop_allow_nesting() on wrapper");
+               return;
+       }
+
+       if (ev->wrapper.list != NULL) {
+               tevent_abort(ev, "tevent_loop_allow_nesting() with wrapper");
+               return;
+       }
+
        ev->nesting.allowed = true;
 }
 
index 0e2e806ee5c450baed9eef6904ec86c67ce522fe..52e081b4ff4ec53dde231c845d1b546019bd7ec7 100644 (file)
@@ -1967,6 +1967,199 @@ bool tevent_register_backend(const char *name, const struct tevent_ops *ops);
 
 /* @} */
 
+/**
+ * @defgroup tevent_wrapper_ops The tevent wrapper operation functions
+ * @ingroup tevent
+ *
+ * The following structure and registration functions are exclusively
+ * needed for people writing wrapper functions for event handlers
+ * e.g. wrappers can be used for debugging/profiling or impersonation.
+ *
+ * There is nothing useful for normal tevent user in here.
+ * @{
+ */
+
+struct tevent_wrapper_ops {
+       const char *name;
+
+       bool (*before_use)(struct tevent_context *wrap_ev,
+                          void *private_state,
+                          struct tevent_context *main_ev,
+                          const char *location);
+       void (*after_use)(struct tevent_context *wrap_ev,
+                         void *private_state,
+                         struct tevent_context *main_ev,
+                         const char *location);
+
+       void (*before_fd_handler)(struct tevent_context *wrap_ev,
+                                 void *private_state,
+                                 struct tevent_context *main_ev,
+                                 struct tevent_fd *fde,
+                                 uint16_t flags,
+                                 const char *handler_name,
+                                 const char *location);
+       void (*after_fd_handler)(struct tevent_context *wrap_ev,
+                                void *private_state,
+                                struct tevent_context *main_ev,
+                                struct tevent_fd *fde,
+                                uint16_t flags,
+                                const char *handler_name,
+                                const char *location);
+
+       void (*before_timer_handler)(struct tevent_context *wrap_ev,
+                                    void *private_state,
+                                    struct tevent_context *main_ev,
+                                    struct tevent_timer *te,
+                                    struct timeval requested_time,
+                                    struct timeval trigger_time,
+                                    const char *handler_name,
+                                    const char *location);
+       void (*after_timer_handler)(struct tevent_context *wrap_ev,
+                                   void *private_state,
+                                   struct tevent_context *main_ev,
+                                   struct tevent_timer *te,
+                                   struct timeval requested_time,
+                                   struct timeval trigger_time,
+                                   const char *handler_name,
+                                   const char *location);
+
+       void (*before_immediate_handler)(struct tevent_context *wrap_ev,
+                                        void *private_state,
+                                        struct tevent_context *main_ev,
+                                        struct tevent_immediate *im,
+                                        const char *handler_name,
+                                        const char *location);
+       void (*after_immediate_handler)(struct tevent_context *wrap_ev,
+                                       void *private_state,
+                                       struct tevent_context *main_ev,
+                                       struct tevent_immediate *im,
+                                       const char *handler_name,
+                                       const char *location);
+
+       void (*before_signal_handler)(struct tevent_context *wrap_ev,
+                                     void *private_state,
+                                     struct tevent_context *main_ev,
+                                     struct tevent_signal *se,
+                                     int signum,
+                                     int count,
+                                     void *siginfo,
+                                     const char *handler_name,
+                                     const char *location);
+       void (*after_signal_handler)(struct tevent_context *wrap_ev,
+                                    void *private_state,
+                                    struct tevent_context *main_ev,
+                                    struct tevent_signal *se,
+                                    int signum,
+                                    int count,
+                                    void *siginfo,
+                                    const char *handler_name,
+                                    const char *location);
+};
+
+#ifdef DOXYGEN
+/**
+ * @brief Create a wrapper tevent_context.
+ *
+ * @param[in]  main_ev        The main event context to work on.
+ *
+ * @param[in]  mem_ctx        The talloc memory context to use.
+ *
+ * @param[in]  ops            The tevent_wrapper_ops function table.
+ *
+ * @param[out] private_state  The private state use by the wrapper functions.
+ *
+ * @param[in]  private_type   The talloc type of the private_state.
+ *
+ * @return                    The wrapper event context, NULL on error.
+ *
+ */
+struct tevent_context *tevent_context_wrapper_create(struct tevent_context *main_ev,
+                                               TALLOC_CTX *mem_ctx,
+                                               const struct tevent_wrapper_ops *ops,
+                                               void **private_state,
+                                               const char *private_type);
+#else
+struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
+                                               TALLOC_CTX *mem_ctx,
+                                               const struct tevent_wrapper_ops *ops,
+                                               void *pstate,
+                                               size_t psize,
+                                               const char *type,
+                                               const char *location);
+#define tevent_context_wrapper_create(main_ev, mem_ctx, ops, state, type) \
+       _tevent_context_wrapper_create(main_ev, mem_ctx, ops, \
+                                      state, sizeof(type), #type, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Prepare the environment of a (wrapper) event context.
+ *
+ * A caller might call this before passing a wrapper event context
+ * to a tevent_req based *_send() function.
+ *
+ * The wrapper event context might do something like impersonation.
+ *
+ * @param[in]  ev       The event context to work on.
+ *
+ * @return              Success (true) or failure (false).
+ *
+ * @note This is only needed if wrapper event contexts are in use.
+ *
+ * @see tevent_context_after_use
+ */
+bool tevent_context_before_use(struct tevent_context *ev);
+#else
+bool _tevent_context_before_use(struct tevent_context *ev,
+                               const char *location);
+#define tevent_context_before_use(ev) \
+       _tevent_context_before_use(ev, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Release the environment of a (wrapper) event context.
+ *
+ * A caller might call this after receiving the result from
+ * a *_recv function of a tevent_req based function pair.
+ *
+ * The wrapper event context might undo something like impersonation.
+ *
+ * @param[in]  ev       The event context to work on.
+ *
+ * @note This is only needed if wrapper event contexts are in use.
+ *
+ * @see tevent_context_before_use
+ */
+void tevent_context_after_use(struct tevent_context *ev);
+#else
+void _tevent_context_after_use(struct tevent_context *ev,
+                              const char *location);
+#define tevent_context_after_use(ev) \
+       _tevent_context_after_use(ev, __location__)
+#endif
+
+/**
+ * @brief Check is the two context pointers belong to the same low level loop
+ *
+ * With the introduction of wrapper contexts it's not trivial
+ * to check if two context pointers belong to the same low level
+ * event loop. Some code may need to know this in order
+ * to make some caching decisions.
+ *
+ * @param[in]  ev1       The first event context.
+ * @param[in]  ev2       The second event context.
+ *
+ * @return true if both contexts belong to the same (still existing) context
+ * loop, false otherwise.
+ *
+ * @see tevent_context_wrapper_create
+ */
+bool tevent_context_same_loop(struct tevent_context *ev1,
+                             struct tevent_context *ev2);
+
+/* @} */
+
 /**
  * @defgroup tevent_compat The tevent compatibility functions
  * @ingroup tevent
index 31da7b968366cad509e33bcb8e40caf4455d70ca..0a57639076e28d391718a5fa6e1a1bb10eabc799 100644 (file)
@@ -41,6 +41,13 @@ int tevent_set_debug(struct tevent_context *ev,
                                   va_list ap) PRINTF_ATTRIBUTE(3,0),
                     void *context)
 {
+       if (ev->wrapper.glue != NULL) {
+               ev = tevent_wrapper_main_ev(ev);
+               tevent_abort(ev, "tevent_set_debug() on wrapper");
+               errno = EINVAL;
+               return -1;
+       }
+
        ev->debug_ops.debug = debug;
        ev->debug_ops.context = context;
        return 0;
@@ -86,6 +93,9 @@ void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
        if (!ev) {
                return;
        }
+       if (ev->wrapper.glue != NULL) {
+               ev = tevent_wrapper_main_ev(ev);
+       }
        if (ev->debug_ops.debug == NULL) {
                return;
        }
@@ -98,6 +108,12 @@ void tevent_set_trace_callback(struct tevent_context *ev,
                               tevent_trace_callback_t cb,
                               void *private_data)
 {
+       if (ev->wrapper.glue != NULL) {
+               ev = tevent_wrapper_main_ev(ev);
+               tevent_abort(ev, "tevent_set_trace_callback() on wrapper");
+               return;
+       }
+
        ev->tracing.callback = cb;
        ev->tracing.private_data = private_data;
 }
index f8234641ad3de0008053248dd52525f6986eb1db..38d0eaeba73a5b982c14442f7a407fd8abdee125 100644 (file)
@@ -110,6 +110,8 @@ _PRIVATE_
 int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
                                    bool *removed)
 {
+       struct tevent_context *handler_ev = fde->event_ctx;
+
        if (removed != NULL) {
                *removed = false;
        }
@@ -119,7 +121,28 @@ int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
        }
 
        fde->busy = true;
-       fde->handler(fde->event_ctx, fde, flags, fde->private_data);
+       if (fde->wrapper != NULL) {
+               fde->wrapper->ops->before_fd_handler(
+                                       fde->wrapper->wrap_ev,
+                                       fde->wrapper->private_state,
+                                       fde->wrapper->main_ev,
+                                       fde,
+                                       flags,
+                                       fde->handler_name,
+                                       fde->location);
+               handler_ev = fde->wrapper->wrap_ev;
+       }
+       fde->handler(handler_ev, fde, flags, fde->private_data);
+       if (fde->wrapper != NULL) {
+               fde->wrapper->ops->after_fd_handler(
+                                       fde->wrapper->wrap_ev,
+                                       fde->wrapper->private_state,
+                                       fde->wrapper->main_ev,
+                                       fde,
+                                       flags,
+                                       fde->handler_name,
+                                       fde->location);
+       }
        fde->busy = false;
 
        if (fde->destroyed) {
index 6d4a97f87746289da76e2841fa15b00a7712512f..c50bbd97d8b7e4b55190d546aa82d686618727f6 100644 (file)
@@ -129,6 +129,7 @@ _PRIVATE_
 int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
                                           bool *removed)
 {
+       struct tevent_context *handler_ev = im->event_ctx;
        struct tevent_context *ev = im->event_ctx;
        struct tevent_immediate cur = *im;
 
@@ -148,7 +149,26 @@ int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
        im->busy = true;
        im->handler_name = NULL;
        tevent_common_immediate_cancel(im);
-       cur.handler(ev, im, cur.private_data);
+       if (cur.wrapper != NULL) {
+               cur.wrapper->ops->before_immediate_handler(
+                                       cur.wrapper->wrap_ev,
+                                       cur.wrapper->private_state,
+                                       cur.wrapper->main_ev,
+                                       im,
+                                       cur.handler_name,
+                                       cur.schedule_location);
+               handler_ev = cur.wrapper->wrap_ev;
+       }
+       cur.handler(handler_ev, im, cur.private_data);
+       if (cur.wrapper != NULL) {
+               cur.wrapper->ops->after_immediate_handler(
+                                       cur.wrapper->wrap_ev,
+                                       cur.wrapper->private_state,
+                                       cur.wrapper->main_ev,
+                                       im,
+                                       cur.handler_name,
+                                       cur.schedule_location);
+       }
        im->busy = false;
        if (im->handler == NULL) {
                talloc_set_destructor(im, NULL);
index ed39aa2bebe45ca3e7d075b18febcd4937b91b2e..e90dd5ef82682dfb2c351aca4589f5f923bc178b 100644 (file)
@@ -170,6 +170,7 @@ struct tevent_req {
 struct tevent_fd {
        struct tevent_fd *prev, *next;
        struct tevent_context *event_ctx;
+       struct tevent_wrapper_glue *wrapper;
        bool busy;
        bool destroyed;
        int fd;
@@ -189,6 +190,7 @@ struct tevent_fd {
 struct tevent_timer {
        struct tevent_timer *prev, *next;
        struct tevent_context *event_ctx;
+       struct tevent_wrapper_glue *wrapper;
        bool busy;
        bool destroyed;
        struct timeval next_event;
@@ -205,6 +207,7 @@ struct tevent_timer {
 struct tevent_immediate {
        struct tevent_immediate *prev, *next;
        struct tevent_context *event_ctx;
+       struct tevent_wrapper_glue *wrapper;
        bool busy;
        bool destroyed;
        tevent_immediate_handler_t handler;
@@ -222,6 +225,7 @@ struct tevent_immediate {
 struct tevent_signal {
        struct tevent_signal *prev, *next;
        struct tevent_context *event_ctx;
+       struct tevent_wrapper_glue *wrapper;
        bool busy;
        bool destroyed;
        int signum;
@@ -314,6 +318,18 @@ struct tevent_context {
                void *private_data;
        } tracing;
 
+       struct {
+               /*
+                * This is used on the main event context
+                */
+               struct tevent_wrapper_glue *list;
+
+               /*
+                * This is used on the wrapper event context
+                */
+               struct tevent_wrapper_glue *glue;
+       } wrapper;
+
        /*
         * an optimization pointer into timer_events
         * used by used by common code via
@@ -397,6 +413,18 @@ int tevent_common_invoke_signal_handler(struct tevent_signal *se,
                                        int signum, int count, void *siginfo,
                                        bool *removed);
 
+struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev);
+
+struct tevent_wrapper_ops;
+
+struct tevent_wrapper_glue {
+       struct tevent_wrapper_glue *prev, *next;
+       struct tevent_context *wrap_ev;
+       struct tevent_context *main_ev;
+       const struct tevent_wrapper_ops *ops;
+       void *private_state;
+};
+
 bool tevent_standard_init(void);
 bool tevent_poll_init(void);
 void tevent_poll_event_add_fd_internal(struct tevent_context *ev,
index 3ca03334c92f13108d5cef88e85c5e042ce180f6..e0665cbafee6514a17db87fe147ea92227d8ea5b 100644 (file)
@@ -338,6 +338,7 @@ int tevent_common_invoke_signal_handler(struct tevent_signal *se,
                                        int signum, int count, void *siginfo,
                                        bool *removed)
 {
+       struct tevent_context *handler_ev = se->event_ctx;
        bool remove = false;
 
        if (removed != NULL) {
@@ -349,7 +350,32 @@ int tevent_common_invoke_signal_handler(struct tevent_signal *se,
        }
 
        se->busy = true;
-       se->handler(se->event_ctx, se, signum, count, siginfo, se->private_data);
+       if (se->wrapper != NULL) {
+               se->wrapper->ops->before_signal_handler(
+                                               se->wrapper->wrap_ev,
+                                               se->wrapper->private_state,
+                                               se->wrapper->main_ev,
+                                               se,
+                                               signum,
+                                               count,
+                                               siginfo,
+                                               se->handler_name,
+                                               se->location);
+               handler_ev = se->wrapper->wrap_ev;
+       }
+       se->handler(handler_ev, se, signum, count, siginfo, se->private_data);
+       if (se->wrapper != NULL) {
+               se->wrapper->ops->after_signal_handler(
+                                               se->wrapper->wrap_ev,
+                                               se->wrapper->private_state,
+                                               se->wrapper->main_ev,
+                                               se,
+                                               signum,
+                                               count,
+                                               siginfo,
+                                               se->handler_name,
+                                               se->location);
+       }
        se->busy = false;
 
 #ifdef SA_RESETHAND
index f50f42146089fefb3c0b458893419a9956770dfd..176dd6b6a5f3b49744e7ca86aef475b535d5e396 100644 (file)
@@ -28,8 +28,8 @@
 #include "tevent_internal.h"
 #include "tevent_util.h"
 
-#if defined(HAVE_PTHREAD)
-#include <pthread.h>
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
 
 struct tevent_immediate_list {
        struct tevent_immediate_list *next, *prev;
@@ -217,6 +217,18 @@ struct tevent_thread_proxy *tevent_thread_proxy_create(
        int pipefds[2];
        struct tevent_thread_proxy *tp;
 
+       if (dest_ev_ctx->wrapper.glue != NULL) {
+               /*
+                * stacking of wrappers is not supported
+                */
+               tevent_debug(dest_ev_ctx->wrapper.glue->main_ev,
+                            TEVENT_DEBUG_FATAL,
+                            "%s() not allowed on a wrapper context\n",
+                            __func__);
+               errno = EINVAL;
+               return NULL;
+       }
+
        tp = talloc_zero(dest_ev_ctx, struct tevent_thread_proxy);
        if (tp == NULL) {
                return NULL;
@@ -375,10 +387,11 @@ void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
 static int tevent_threaded_context_destructor(
        struct tevent_threaded_context *tctx)
 {
+       struct tevent_context *main_ev = tevent_wrapper_main_ev(tctx->event_ctx);
        int ret;
 
-       if (tctx->event_ctx != NULL) {
-               DLIST_REMOVE(tctx->event_ctx->threaded_contexts, tctx);
+       if (main_ev != NULL) {
+               DLIST_REMOVE(main_ev->threaded_contexts, tctx);
        }
 
        /*
@@ -410,10 +423,11 @@ struct tevent_threaded_context *tevent_threaded_context_create(
        TALLOC_CTX *mem_ctx, struct tevent_context *ev)
 {
 #ifdef HAVE_PTHREAD
+       struct tevent_context *main_ev = tevent_wrapper_main_ev(ev);
        struct tevent_threaded_context *tctx;
        int ret;
 
-       ret = tevent_common_wakeup_init(ev);
+       ret = tevent_common_wakeup_init(main_ev);
        if (ret != 0) {
                errno = ret;
                return NULL;
@@ -431,7 +445,7 @@ struct tevent_threaded_context *tevent_threaded_context_create(
                return NULL;
        }
 
-       DLIST_ADD(ev->threaded_contexts, tctx);
+       DLIST_ADD(main_ev->threaded_contexts, tctx);
        talloc_set_destructor(tctx, tevent_threaded_context_destructor);
 
        return tctx;
@@ -458,7 +472,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 {
 #ifdef HAVE_PTHREAD
        const char *create_location = im->create_location;
-       struct tevent_context *ev;
+       struct tevent_context *main_ev = NULL;
        int ret, wakeup_fd;
 
        ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
@@ -466,9 +480,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
                abort();
        }
 
-       ev = tctx->event_ctx;
-
-       if (ev == NULL) {
+       if (tctx->event_ctx == NULL) {
                /*
                 * Our event context is already gone.
                 */
@@ -489,8 +501,10 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
                abort();
        }
 
+       main_ev = tevent_wrapper_main_ev(tctx->event_ctx);
+
        *im = (struct tevent_immediate) {
-               .event_ctx              = ev,
+               .event_ctx              = tctx->event_ctx,
                .handler                = handler,
                .private_data           = private_data,
                .handler_name           = handler_name,
@@ -500,15 +514,15 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx,
 
        talloc_set_destructor(im, tevent_threaded_schedule_immediate_destructor);
 
-       ret = pthread_mutex_lock(&ev->scheduled_mutex);
+       ret = pthread_mutex_lock(&main_ev->scheduled_mutex);
        if (ret != 0) {
                abort();
        }
 
-       DLIST_ADD_END(ev->scheduled_immediates, im);
-       wakeup_fd = ev->wakeup_fd;
+       DLIST_ADD_END(main_ev->scheduled_immediates, im);
+       wakeup_fd = main_ev->wakeup_fd;
 
-       ret = pthread_mutex_unlock(&ev->scheduled_mutex);
+       ret = pthread_mutex_unlock(&main_ev->scheduled_mutex);
        if (ret != 0) {
                abort();
        }
index d460e7001dcae0601915bcc867eacf375278e197..5ede71696af43e2a854671d75d724b802e378513 100644 (file)
@@ -321,6 +321,8 @@ int tevent_common_invoke_timer_handler(struct tevent_timer *te,
                                       struct timeval current_time,
                                       bool *removed)
 {
+       struct tevent_context *handler_ev = te->event_ctx;
+
        if (removed != NULL) {
                *removed = false;
        }
@@ -351,7 +353,30 @@ int tevent_common_invoke_timer_handler(struct tevent_timer *te,
         * otherwise we pass the current time
         */
        te->busy = true;
-       te->handler(te->event_ctx, te, current_time, te->private_data);
+       if (te->wrapper != NULL) {
+               te->wrapper->ops->before_timer_handler(
+                                       te->wrapper->wrap_ev,
+                                       te->wrapper->private_state,
+                                       te->wrapper->main_ev,
+                                       te,
+                                       te->next_event,
+                                       current_time,
+                                       te->handler_name,
+                                       te->location);
+               handler_ev = te->wrapper->wrap_ev;
+       }
+       te->handler(handler_ev, te, current_time, te->private_data);
+       if (te->wrapper != NULL) {
+               te->wrapper->ops->after_timer_handler(
+                                       te->wrapper->wrap_ev,
+                                       te->wrapper->private_state,
+                                       te->wrapper->main_ev,
+                                       te,
+                                       te->next_event,
+                                       current_time,
+                                       te->handler_name,
+                                       te->location);
+       }
        te->busy = false;
 
        tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
diff --git a/lib/tevent/tevent_wrapper.c b/lib/tevent/tevent_wrapper.c
new file mode 100644 (file)
index 0000000..f9cde89
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+   Infrastructure for event context wrappers
+
+   Copyright (C) Stefan Metzmacher 2014
+
+     ** 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"
+#ifdef HAVE_PTHREAD
+#include "system/threads.h"
+#endif
+#include "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+static int tevent_wrapper_glue_context_init(struct tevent_context *ev)
+{
+       return 0;
+}
+
+static struct tevent_fd *tevent_wrapper_glue_add_fd(struct tevent_context *ev,
+                                                   TALLOC_CTX *mem_ctx,
+                                                   int fd, uint16_t flags,
+                                                   tevent_fd_handler_t handler,
+                                                   void *private_data,
+                                                   const char *handler_name,
+                                                   const char *location)
+{
+       struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+       struct tevent_fd *fde;
+
+       if (glue->main_ev == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
+                            handler, private_data,
+                            handler_name, location);
+       if (fde == NULL) {
+               return NULL;
+       }
+
+       fde->wrapper = glue;
+
+       return fde;
+}
+
+static struct tevent_timer *tevent_wrapper_glue_add_timer(struct tevent_context *ev,
+                                                         TALLOC_CTX *mem_ctx,
+                                                         struct timeval next_event,
+                                                         tevent_timer_handler_t handler,
+                                                         void *private_data,
+                                                         const char *handler_name,
+                                                         const char *location)
+{
+       struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+       struct tevent_timer *te;
+
+       if (glue->main_ev == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
+                              handler, private_data,
+                              handler_name, location);
+       if (te == NULL) {
+               return NULL;
+       }
+
+       te->wrapper = glue;
+
+       return te;
+}
+
+static void tevent_wrapper_glue_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)
+{
+       struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+
+       if (glue->main_ev == NULL) {
+               tevent_abort(ev, location);
+               errno = EINVAL;
+               return;
+       }
+
+       _tevent_schedule_immediate(im, glue->main_ev,
+                                  handler, private_data,
+                                  handler_name, location);
+
+       im->wrapper = glue;
+
+       return;
+}
+
+static struct tevent_signal *tevent_wrapper_glue_add_signal(struct tevent_context *ev,
+                                                           TALLOC_CTX *mem_ctx,
+                                                           int signum, int sa_flags,
+                                                           tevent_signal_handler_t handler,
+                                                           void *private_data,
+                                                           const char *handler_name,
+                                                           const char *location)
+{
+       struct tevent_wrapper_glue *glue = ev->wrapper.glue;
+       struct tevent_signal *se;
+
+       if (glue->main_ev == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       se = _tevent_add_signal(glue->main_ev, mem_ctx,
+                               signum, sa_flags,
+                               handler, private_data,
+                               handler_name, location);
+       if (se == NULL) {
+               return NULL;
+       }
+
+       se->wrapper = glue;
+
+       return se;
+}
+
+static int tevent_wrapper_glue_loop_once(struct tevent_context *ev, const char *location)
+{
+       tevent_abort(ev, "tevent_wrapper_glue_loop_once() called");
+       errno = ENOSYS;
+       return -1;
+}
+
+static int tevent_wrapper_glue_loop_wait(struct tevent_context *ev, const char *location)
+{
+       tevent_abort(ev, "tevent_wrapper_glue_loop_wait() called");
+       errno = ENOSYS;
+       return -1;
+}
+
+static const struct tevent_ops tevent_wrapper_glue_ops = {
+       .context_init           = tevent_wrapper_glue_context_init,
+       .add_fd                 = tevent_wrapper_glue_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_wrapper_glue_add_timer,
+       .schedule_immediate     = tevent_wrapper_glue_schedule_immediate,
+       .add_signal             = tevent_wrapper_glue_add_signal,
+       .loop_once              = tevent_wrapper_glue_loop_once,
+       .loop_wait              = tevent_wrapper_glue_loop_wait,
+};
+
+static int tevent_wrapper_glue_destructor(struct tevent_wrapper_glue *glue)
+{
+       struct tevent_context *main_ev = glue->main_ev;
+       struct tevent_fd *fd, *fn;
+       struct tevent_timer *te, *tn;
+       struct tevent_immediate *ie, *in;
+       struct tevent_signal *se, *sn;
+#ifdef HAVE_PTHREAD
+       struct tevent_threaded_context *tctx, *tctxn;
+#endif
+
+       if (main_ev == NULL) {
+               return 0;
+       }
+
+       glue->main_ev = NULL;
+       DLIST_REMOVE(main_ev->wrapper.list, glue);
+
+#ifdef HAVE_PTHREAD
+       for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
+               int ret;
+
+               tctxn = tctx->next;
+
+               if (tctx->event_ctx != glue->wrap_ev) {
+                       continue;
+               }
+
+               ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
+               if (ret != 0) {
+                       abort();
+               }
+
+               /*
+                * Indicate to the thread that the tevent_context is
+                * gone. The counterpart of this is in
+                * _tevent_threaded_schedule_immediate, there we read
+                * this under the threaded_context's mutex.
+                */
+
+               tctx->event_ctx = NULL;
+
+               ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
+               if (ret != 0) {
+                       abort();
+               }
+
+               DLIST_REMOVE(main_ev->threaded_contexts, tctx);
+       }
+#endif
+
+       for (fd = main_ev->fd_events; fd; fd = fn) {
+               fn = fd->next;
+
+               if (fd->wrapper != glue) {
+                       continue;
+               }
+
+               tevent_fd_set_flags(fd, 0);
+
+               fd->event_ctx = NULL;
+               DLIST_REMOVE(main_ev->fd_events, fd);
+       }
+
+       for (te = main_ev->timer_events; te; te = tn) {
+               tn = te->next;
+
+               if (te->wrapper != glue) {
+                       continue;
+               }
+
+               te->event_ctx = NULL;
+
+               if (main_ev->last_zero_timer == te) {
+                       main_ev->last_zero_timer = DLIST_PREV(te);
+               }
+               DLIST_REMOVE(main_ev->timer_events, te);
+       }
+
+       for (ie = main_ev->immediate_events; ie; ie = in) {
+               in = ie->next;
+
+               if (ie->wrapper != glue) {
+                       continue;
+               }
+
+               ie->event_ctx = NULL;
+               ie->cancel_fn = NULL;
+               DLIST_REMOVE(main_ev->immediate_events, ie);
+       }
+
+       for (se = main_ev->signal_events; se; se = sn) {
+               sn = se->next;
+
+               if (se->wrapper != glue) {
+                       continue;
+               }
+
+               tevent_cleanup_pending_signal_handlers(se);
+       }
+
+       return 0;
+}
+
+_PRIVATE_
+struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
+                                               TALLOC_CTX *mem_ctx,
+                                               const struct tevent_wrapper_ops *ops,
+                                               void *pstate,
+                                               size_t psize,
+                                               const char *type,
+                                               const char *location)
+{
+       void **ppstate = (void **)pstate;
+       struct tevent_context *ev;
+
+       if (main_ev->wrapper.glue != NULL) {
+               /*
+                * stacking of wrappers is not supported
+                */
+               tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
+                            "%s: %s() stacking not allowed\n",
+                            __func__, location);
+               errno = EINVAL;
+               return NULL;
+       }
+
+       if (main_ev->nesting.allowed) {
+               /*
+                * wrappers conflict with nesting
+                */
+               tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
+                            "%s: %s() conflicts with nesting\n",
+                            __func__, location);
+               errno = EINVAL;
+               return NULL;
+       }
+
+       ev = tevent_context_init_ops(mem_ctx,
+                                    &tevent_wrapper_glue_ops,
+                                    NULL);
+       if (ev == NULL) {
+               return NULL;
+       }
+
+       ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
+       if (ev->wrapper.glue == NULL) {
+               talloc_free(ev);
+               return NULL;
+       }
+
+       ev->wrapper.glue->wrap_ev = ev;
+       ev->wrapper.glue->main_ev = main_ev;
+       ev->wrapper.glue->ops = ops;
+       ev->wrapper.glue->private_state = talloc_size(ev->wrapper.glue, psize);
+       if (ev->wrapper.glue->private_state == NULL) {
+               talloc_free(ev);
+               return NULL;
+       }
+       talloc_set_name_const(ev->wrapper.glue->private_state, type);
+
+       DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
+
+       talloc_set_destructor(ev->wrapper.glue, tevent_wrapper_glue_destructor);
+
+       *ppstate = ev->wrapper.glue->private_state;
+       return ev;
+}
+
+_PRIVATE_
+struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
+{
+       if (ev == NULL) {
+               return NULL;
+       }
+
+       if (ev->wrapper.glue != NULL && ev->wrapper.glue->main_ev != NULL) {
+               return ev->wrapper.glue->main_ev;
+       }
+
+       return ev;
+}
+
+_PRIVATE_
+bool _tevent_context_before_use(struct tevent_context *ev,
+                               const char *location)
+{
+       if (ev->wrapper.glue == NULL) {
+               return true;
+       }
+
+       if (ev->wrapper.glue->main_ev == NULL) {
+               return false;
+       }
+
+       return ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
+                                                ev->wrapper.glue->private_state,
+                                                ev->wrapper.glue->main_ev,
+                                                location);
+}
+
+_PRIVATE_
+void _tevent_context_after_use(struct tevent_context *ev,
+                              const char *location)
+{
+       if (ev->wrapper.glue == NULL) {
+               return;
+       }
+
+       if (ev->wrapper.glue->main_ev == NULL) {
+               return;
+       }
+
+       ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
+                                        ev->wrapper.glue->private_state,
+                                        ev->wrapper.glue->main_ev,
+                                        location);
+}
+
+_PRIVATE_
+bool tevent_context_same_loop(struct tevent_context *ev1,
+                             struct tevent_context *ev2)
+{
+       struct tevent_context *main_ev1 = tevent_wrapper_main_ev(ev1);
+       struct tevent_context *main_ev2 = tevent_wrapper_main_ev(ev2);
+
+       if (main_ev1 == NULL) {
+               return false;
+       }
+
+       if (main_ev1 == main_ev2) {
+               return true;
+       }
+
+       return false;
+}
index 94d190f3b60555161dd7f3488b88881b92708aa8..2395ead9aa93b5b2a5dc8010067b2ae7a28f2b9b 100644 (file)
@@ -77,7 +77,7 @@ def build(bld):
     bld.RECURSE('lib/talloc')
 
     SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c
-             tevent_queue.c tevent_req.c
+             tevent_queue.c tevent_req.c tevent_wrapper.c
              tevent_poll.c tevent_threads.c
              tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c'''