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;
}
#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) {
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;
}
/* @} */
+/**
+ * @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
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;
if (!ev) {
return;
}
+ if (ev->wrapper.glue != NULL) {
+ ev = tevent_wrapper_main_ev(ev);
+ }
if (ev->debug_ops.debug == NULL) {
return;
}
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;
}
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;
}
}
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) {
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;
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);
struct tevent_fd {
struct tevent_fd *prev, *next;
struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
bool busy;
bool destroyed;
int 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;
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;
struct tevent_signal {
struct tevent_signal *prev, *next;
struct tevent_context *event_ctx;
+ struct tevent_wrapper_glue *wrapper;
bool busy;
bool destroyed;
int signum;
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
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,
int signum, int count, void *siginfo,
bool *removed)
{
+ struct tevent_context *handler_ev = se->event_ctx;
bool remove = false;
if (removed != NULL) {
}
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
#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;
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;
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);
}
/*
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;
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;
{
#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);
abort();
}
- ev = tctx->event_ctx;
-
- if (ev == NULL) {
+ if (tctx->event_ctx == NULL) {
/*
* Our event context is already gone.
*/
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,
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();
}
struct timeval current_time,
bool *removed)
{
+ struct tevent_context *handler_ev = te->event_ctx;
+
if (removed != NULL) {
*removed = false;
}
* 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,
--- /dev/null
+/*
+ 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;
+}
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'''