summaryrefslogtreecommitdiff
path: root/lib/tevent
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tevent')
-rw-r--r--lib/tevent/ABI/tevent-0.9.36.sigs5
-rw-r--r--lib/tevent/tevent.c30
-rw-r--r--lib/tevent/tevent.h260
-rw-r--r--lib/tevent/tevent_debug.c16
-rw-r--r--lib/tevent/tevent_epoll.c8
-rw-r--r--lib/tevent/tevent_fd.c29
-rw-r--r--lib/tevent/tevent_immediate.c27
-rw-r--r--lib/tevent/tevent_internal.h35
-rw-r--r--lib/tevent/tevent_poll.c2
-rw-r--r--lib/tevent/tevent_signal.c32
-rw-r--r--lib/tevent/tevent_threads.c42
-rw-r--r--lib/tevent/tevent_timed.c32
-rw-r--r--lib/tevent/tevent_wrapper.c568
-rw-r--r--lib/tevent/wscript2
14 files changed, 1069 insertions, 19 deletions
diff --git a/lib/tevent/ABI/tevent-0.9.36.sigs b/lib/tevent/ABI/tevent-0.9.36.sigs
index 443bb7cb6c9..ddb2c03b65c 100644
--- a/lib/tevent/ABI/tevent-0.9.36.sigs
+++ b/lib/tevent/ABI/tevent-0.9.36.sigs
@@ -1,6 +1,9 @@
_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_context_pop_use: void (struct tevent_context *, const char *)
+_tevent_context_push_use: bool (struct tevent_context *, const char *)
+_tevent_context_wrapper_create: struct tevent_context *(struct tevent_context *, TALLOC_CTX *, const struct tevent_wrapper_ops *, void *, size_t, const char *, const char *)
_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
_tevent_loop_once: int (struct tevent_context *, const char *)
_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
@@ -47,6 +50,8 @@ tevent_common_wakeup_init: int (struct tevent_context *)
tevent_context_init: struct tevent_context *(TALLOC_CTX *)
tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_context_is_wrapper: bool (struct tevent_context *)
+tevent_context_same_loop: bool (struct tevent_context *, struct tevent_context *)
tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
tevent_fd_get_flags: uint16_t (struct tevent_fd *)
tevent_fd_set_auto_close: void (struct tevent_fd *)
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index de0436df373..dbec1821e41 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -298,10 +298,17 @@ 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;
+#endif
+
+ if (ev->wrapper.glue != NULL) {
+ tevent_abort(ev,
+ "tevent_common_context_destructor() active on wrapper");
+ }
+#ifdef HAVE_PTHREAD
ret = pthread_mutex_lock(&tevent_contexts_mutex);
if (ret != 0) {
abort();
@@ -345,10 +352,18 @@ 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) {
fn = fd->next;
+ fd->wrapper = NULL;
fd->event_ctx = NULL;
DLIST_REMOVE(ev->fd_events, fd);
}
@@ -356,12 +371,14 @@ int tevent_common_context_destructor(struct tevent_context *ev)
ev->last_zero_timer = NULL;
for (te = ev->timer_events; te; te = tn) {
tn = te->next;
+ te->wrapper = NULL;
te->event_ctx = NULL;
DLIST_REMOVE(ev->timer_events, te);
}
for (ie = ev->immediate_events; ie; ie = in) {
in = ie->next;
+ ie->wrapper = NULL;
ie->event_ctx = NULL;
ie->cancel_fn = NULL;
DLIST_REMOVE(ev->immediate_events, ie);
@@ -369,6 +386,7 @@ int tevent_common_context_destructor(struct tevent_context *ev)
for (se = ev->signal_events; se; se = sn) {
sn = se->next;
+ se->wrapper = NULL;
se->event_ctx = NULL;
DLIST_REMOVE(ev->signal_events, se);
/*
@@ -675,6 +693,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;
}
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 0e2e806ee5c..d34a03093f3 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -429,6 +429,12 @@ int _tevent_loop_wait(struct tevent_context *ev, const char *location);
*
* @param[in] fde File descriptor event on which to set the destructor
* @param[in] close_fn Destructor to execute when fde is freed
+ *
+ * @note That the close_fn() on tevent_fd is *NOT* wrapped on contexts
+ * created by tevent_context_wrapper_create()!
+ *
+ * @see tevent_fd_set_close_fn
+ * @see tevent_context_wrapper_create
*/
void tevent_fd_set_close_fn(struct tevent_fd *fde,
tevent_fd_close_fn_t close_fn);
@@ -439,6 +445,8 @@ void tevent_fd_set_close_fn(struct tevent_fd *fde,
* This function calls close(fd) internally.
*
* @param[in] fde File descriptor event to auto-close
+ *
+ * @see tevent_fd_set_close_fn
*/
void tevent_fd_set_auto_close(struct tevent_fd *fde);
@@ -1968,6 +1976,258 @@ 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.
+ *
+ * @note That the close_fn() on tevent_fd is *NOT* wrapped!
+ *
+ * @see tevent_context_wrapper_create
+ * @see tevent_fd_set_auto_close
+ * @{
+ */
+
+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.
+ *
+ * @note Available as of tevent 0.9.37
+ */
+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
+
+/**
+ * @brief Check if the event context is a wrapper event context.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @return Is a wrapper (true), otherwise (false).
+ *
+ * @see tevent_context_wrapper_create()
+ *
+ * @note Available as of tevent 0.9.37
+ */
+bool tevent_context_is_wrapper(struct tevent_context *ev);
+
+#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.
+ *
+ * tevent_context_push_use() must always be used in combination
+ * with tevent_context_pop_use().
+ *
+ * There is a global stack of currently active/busy wrapper event contexts.
+ * Each wrapper can only appear once on that global stack!
+ * The stack size is limited to 32 elements, which should be enough
+ * for all useful scenarios.
+ *
+ * In addition to an explicit tevent_context_push_use() also
+ * the invocation of an immediate, timer or fd handler implicitly
+ * pushes the wrapper on the stack.
+ *
+ * Therefore there are some strict constraints for the usage of
+ * tevent_context_push_use():
+ * - It must not be called from within an event handler
+ * that already acts on the wrapper.
+ * - tevent_context_pop_use() must be called before
+ * leaving the code block that called tevent_context_push_use().
+ * - The caller is responsible ensure the correct stack ordering
+ * - Any violation of these constraints results in calling
+ * the abort handler of the given tevent context.
+ *
+ * Calling tevent_context_push_use() on a raw event context
+ * still consumes an element on the stack, but it's otherwise
+ * a no-op.
+ *
+ * If tevent_context_push_use() returns false, it means
+ * that the wrapper's before_use() hook returned this failure,
+ * in that case you must not call tevent_context_pop_use() as
+ * the wrapper is not pushed onto the stack.
+ *
+ * @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_pop_use
+ *
+ * @note Available as of tevent 0.9.37
+ */
+bool tevent_context_push_use(struct tevent_context *ev);
+#else
+bool _tevent_context_push_use(struct tevent_context *ev,
+ const char *location);
+#define tevent_context_push_use(ev) \
+ _tevent_context_push_use(ev, __location__)
+#endif
+
+#ifdef DOXYGEN
+/**
+ * @brief Release the environment of a (wrapper) event context.
+ *
+ * The wrapper event context might undo something like impersonation.
+ *
+ * This must be called after a succesful tevent_context_push_use().
+ * Any ordering violation results in calling
+ * the abort handler of the given tevent context.
+ *
+ * This basically calls the wrapper's after_use() hook.
+ *
+ * @param[in] ev The event context to work on.
+ *
+ * @note This is only needed if wrapper event contexts are in use.
+ *
+ * @see tevent_context_push_use
+ *
+ * @note Available as of tevent 0.9.37
+ */
+void tevent_context_pop_use(struct tevent_context *ev);
+#else
+void _tevent_context_pop_use(struct tevent_context *ev,
+ const char *location);
+#define tevent_context_pop_use(ev) \
+ _tevent_context_pop_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
+ *
+ * @note Available as of tevent 0.9.37
+ */
+bool tevent_context_same_loop(struct tevent_context *ev1,
+ struct tevent_context *ev2);
+
+/* @} */
+
+/**
* @defgroup tevent_compat The tevent compatibility functions
* @ingroup tevent
*
diff --git a/lib/tevent/tevent_debug.c b/lib/tevent/tevent_debug.c
index 31da7b96836..0a57639076e 100644
--- a/lib/tevent/tevent_debug.c
+++ b/lib/tevent/tevent_debug.c
@@ -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;
}
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 5f7ef5d83d1..9cbe505c98a 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -323,8 +323,10 @@ static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
"add_fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
add_fde, mpx_fde, add_fde->fd);
DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->wrapper = NULL;
mpx_fde->event_ctx = NULL;
DLIST_REMOVE(epoll_ev->ev->fd_events, add_fde);
+ add_fde->wrapper = NULL;
add_fde->event_ctx = NULL;
return 0;
} else if (ret != 0) {
@@ -387,9 +389,11 @@ static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_
"fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
fde, mpx_fde, fde->fd);
DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
if (mpx_fde != NULL) {
DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->wrapper = NULL;
mpx_fde->event_ctx = NULL;
}
return;
@@ -462,9 +466,11 @@ static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_
"fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
fde, mpx_fde, fde->fd);
DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
if (mpx_fde != NULL) {
DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->wrapper = NULL;
mpx_fde->event_ctx = NULL;
}
return;
@@ -511,9 +517,11 @@ static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_
"fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
fde, mpx_fde, fde->fd);
DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
if (mpx_fde != NULL) {
DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->wrapper = NULL;
mpx_fde->event_ctx = NULL;
}
return;
diff --git a/lib/tevent/tevent_fd.c b/lib/tevent/tevent_fd.c
index 7859cbb00ef..b92c45f1ddd 100644
--- a/lib/tevent/tevent_fd.c
+++ b/lib/tevent/tevent_fd.c
@@ -51,6 +51,7 @@ done:
if (fde->busy) {
return -1;
}
+ fde->wrapper = NULL;
return 0;
}
@@ -109,6 +110,8 @@ void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
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;
}
@@ -118,7 +121,31 @@ 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) {
+ handler_ev = fde->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, fde->wrapper);
+ 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);
+ }
+ 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);
+ tevent_wrapper_pop_use_internal(handler_ev, fde->wrapper);
+ }
fde->busy = false;
if (fde->destroyed) {
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
index 0649d1eacf2..ef7d8a566c0 100644
--- a/lib/tevent/tevent_immediate.c
+++ b/lib/tevent/tevent_immediate.c
@@ -100,6 +100,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
{
const char *create_location = im->create_location;
bool busy = im->busy;
+ struct tevent_wrapper_glue *glue = im->wrapper;
tevent_common_immediate_cancel(im);
@@ -109,6 +110,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
*im = (struct tevent_immediate) {
.event_ctx = ev,
+ .wrapper = glue,
.handler = handler,
.private_data = private_data,
.handler_name = handler_name,
@@ -128,6 +130,7 @@ void tevent_common_schedule_immediate(struct tevent_immediate *im,
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;
@@ -147,7 +150,29 @@ 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) {
+ handler_ev = cur.wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, cur.wrapper);
+ 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);
+ }
+ 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);
+ tevent_wrapper_pop_use_internal(handler_ev, cur.wrapper);
+ }
im->busy = false;
if (im->destroyed) {
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 1183b9f7f83..17c195816fa 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -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,25 @@ 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;
+ bool busy;
+ bool destroyed;
+ const struct tevent_wrapper_ops *ops;
+ void *private_state;
+};
+
+void tevent_wrapper_push_use_internal(struct tevent_context *ev,
+ struct tevent_wrapper_glue *wrapper);
+void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
+ struct tevent_wrapper_glue *wrapper);
+
bool tevent_standard_init(void);
bool tevent_poll_init(void);
bool tevent_poll_event_add_fd_internal(struct tevent_context *ev,
diff --git a/lib/tevent/tevent_poll.c b/lib/tevent/tevent_poll.c
index 74c418ca421..f4c6c2dbe80 100644
--- a/lib/tevent/tevent_poll.c
+++ b/lib/tevent/tevent_poll.c
@@ -535,6 +535,7 @@ static int poll_event_loop_poll(struct tevent_context *ev,
poll_ev->fdes[idx] = NULL;
poll_ev->deleted = true;
DLIST_REMOVE(ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
continue;
}
@@ -586,6 +587,7 @@ static int poll_event_loop_poll(struct tevent_context *ev,
poll_ev->deleted = true;
if (fde != NULL) {
DLIST_REMOVE(ev->fd_events, fde);
+ fde->wrapper = NULL;
fde->event_ctx = NULL;
}
}
diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index a787f97b964..5ca0b8d2ab1 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -216,6 +216,7 @@ done:
if (se->busy) {
return -1;
}
+ se->wrapper = NULL;
return 0;
}
@@ -338,6 +339,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 +351,35 @@ 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) {
+ handler_ev = se->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, se->wrapper);
+ 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);
+ }
+ 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);
+ tevent_wrapper_pop_use_internal(handler_ev, se->wrapper);
+ }
se->busy = false;
#ifdef SA_RESETHAND
diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c
index 5d4e0c42676..21a9b686ba9 100644
--- a/lib/tevent/tevent_threads.c
+++ b/lib/tevent/tevent_threads.c
@@ -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,8 @@ 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;
+ struct tevent_wrapper_glue *glue = tctx->event_ctx->wrapper.glue;
int ret, wakeup_fd;
ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
@@ -466,9 +481,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 +502,11 @@ 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,
+ .wrapper = glue,
.handler = handler,
.private_data = private_data,
.handler_name = handler_name,
@@ -506,15 +522,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();
}
diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c
index cb948d4ba29..b521f096c48 100644
--- a/lib/tevent/tevent_timed.c
+++ b/lib/tevent/tevent_timed.c
@@ -157,6 +157,7 @@ done:
if (te->busy) {
return -1;
}
+ te->wrapper = NULL;
return 0;
}
@@ -319,6 +320,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;
}
@@ -349,13 +352,40 @@ 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) {
+ handler_ev = te->wrapper->wrap_ev;
+
+ tevent_wrapper_push_use_internal(handler_ev, te->wrapper);
+ 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);
+ }
+ 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);
+ tevent_wrapper_pop_use_internal(handler_ev, te->wrapper);
+ }
te->busy = false;
tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
"Ending timer event %p \"%s\"\n",
te, te->handler_name);
+ te->wrapper = NULL;
te->event_ctx = NULL;
talloc_set_destructor(te, NULL);
TALLOC_FREE(te);
diff --git a/lib/tevent/tevent_wrapper.c b/lib/tevent/tevent_wrapper.c
new file mode 100644
index 00000000000..05c4c06968a
--- /dev/null
+++ b/lib/tevent/tevent_wrapper.c
@@ -0,0 +1,568 @@
+/*
+ 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)
+{
+ tevent_abort(ev, "tevent_wrapper_glue_context_init() called");
+ errno = ENOSYS;
+ return -1;
+}
+
+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 = NULL;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "add_fd wrapper use after free");
+ return NULL;
+ }
+
+ 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 = NULL;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "add_timer wrapper use after free");
+ return NULL;
+ }
+
+ 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->destroyed) {
+ tevent_abort(ev, "scheduke_immediate wrapper use after free");
+ return;
+ }
+
+ 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 = NULL;
+
+ if (glue->destroyed) {
+ tevent_abort(ev, "add_signal wrapper use after free");
+ return NULL;
+ }
+
+ 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_context_destructor(struct tevent_context *wrap_ev)
+{
+ struct tevent_wrapper_glue *glue = wrap_ev->wrapper.glue;
+ struct tevent_context *main_ev = NULL;
+ struct tevent_fd *fd = NULL, *fn = NULL;
+ struct tevent_timer *te = NULL, *tn = NULL;
+ struct tevent_immediate *ie = NULL, *in = NULL;
+ struct tevent_signal *se = NULL, *sn = NULL;
+#ifdef HAVE_PTHREAD
+ struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
+#endif
+
+ if (glue == NULL) {
+ tevent_abort(wrap_ev,
+ "tevent_wrapper_context_destructor() active on main");
+ }
+
+ if (glue->destroyed && glue->busy) {
+ tevent_common_check_double_free(wrap_ev,
+ "tevent_context wrapper double free");
+ }
+ glue->destroyed = true;
+
+ if (glue->busy) {
+ return -1;
+ }
+
+ main_ev = glue->main_ev;
+ if (main_ev == NULL) {
+ return 0;
+ }
+
+ tevent_debug(wrap_ev, TEVENT_DEBUG_TRACE,
+ "Destroying wrapper context %p \"%s\"\n",
+ wrap_ev, talloc_get_name(glue->private_state));
+
+ 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->wrapper = NULL;
+ 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->wrapper = NULL;
+ 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->wrapper = NULL;
+ 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;
+ }
+
+ se->wrapper = NULL;
+ tevent_cleanup_pending_signal_handlers(se);
+ }
+
+ return 0;
+}
+
+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 = NULL;
+
+ 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 = talloc_zero(mem_ctx, struct tevent_context);
+ if (ev == NULL) {
+ return NULL;
+ }
+ ev->ops = &tevent_wrapper_glue_ops;
+
+ ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
+ if (ev->wrapper.glue == NULL) {
+ talloc_free(ev);
+ return NULL;
+ }
+
+ talloc_set_destructor(ev, tevent_wrapper_context_destructor);
+
+ 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);
+
+ *ppstate = ev->wrapper.glue->private_state;
+ return ev;
+}
+
+bool tevent_context_is_wrapper(struct tevent_context *ev)
+{
+ if (ev->wrapper.glue != NULL) {
+ return true;
+ }
+
+ return false;
+}
+
+_PRIVATE_
+struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
+{
+ if (ev == NULL) {
+ return NULL;
+ }
+
+ if (ev->wrapper.glue == NULL) {
+ return ev;
+ }
+
+ return ev->wrapper.glue->main_ev;
+}
+
+/*
+ * 32 stack elements should be more than enough
+ *
+ * e.g. Samba uses just 8 elements for [un]become_{root,user}()
+ */
+#define TEVENT_WRAPPER_STACK_SIZE 32
+
+static struct tevent_wrapper_stack {
+ const void *ev_ptr;
+ const struct tevent_wrapper_glue *wrapper;
+} wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
+
+static size_t wrapper_stack_idx;
+
+_PRIVATE_
+void tevent_wrapper_push_use_internal(struct tevent_context *ev,
+ struct tevent_wrapper_glue *wrapper)
+{
+ /*
+ * ev and wrapper need to belong together!
+ * It's also fine to only have a raw ev
+ * without a wrapper.
+ */
+ if (unlikely(ev->wrapper.glue != wrapper)) {
+ tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
+ return;
+ }
+
+ if (wrapper != NULL) {
+ if (unlikely(wrapper->busy)) {
+ tevent_abort(ev, "wrapper already busy!");
+ return;
+ }
+ wrapper->busy = true;
+ }
+
+ if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
+ tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
+ return;
+ }
+
+ wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
+ .ev_ptr = ev,
+ .wrapper = wrapper,
+ };
+ wrapper_stack_idx++;
+}
+
+_PRIVATE_
+void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
+ struct tevent_wrapper_glue *wrapper)
+{
+ struct tevent_context *main_ev = NULL;
+
+ /*
+ * Note that __ev_ptr might a a stale pointer and should not
+ * be touched, we just compare the pointer value in order
+ * to enforce the stack order.
+ */
+
+ if (wrapper != NULL) {
+ main_ev = wrapper->main_ev;
+ }
+
+ if (unlikely(wrapper_stack_idx == 0)) {
+ tevent_abort(main_ev, "tevent_wrapper stack already empty");
+ return;
+ }
+ wrapper_stack_idx--;
+
+ if (wrapper != NULL) {
+ wrapper->busy = false;
+ }
+
+ if (wrapper_stack[wrapper_stack_idx].ev_ptr != __ev_ptr) {
+ tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch ev!");
+ return;
+ }
+ if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
+ tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
+ return;
+ }
+
+ if (wrapper == NULL) {
+ return;
+ }
+
+ if (wrapper->destroyed) {
+ /*
+ * Notice that we can't use TALLOC_FREE()
+ * here because wrapper is a talloc child
+ * of wrapper->wrap_ev.
+ */
+ talloc_free(wrapper->wrap_ev);
+ }
+}
+
+bool _tevent_context_push_use(struct tevent_context *ev,
+ const char *location)
+{
+ bool ok;
+
+ if (ev->wrapper.glue == NULL) {
+ tevent_wrapper_push_use_internal(ev, NULL);
+ return true;
+ }
+
+ if (ev->wrapper.glue->main_ev == NULL) {
+ return false;
+ }
+
+ tevent_wrapper_push_use_internal(ev, ev->wrapper.glue);
+ ok = ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
+ ev->wrapper.glue->private_state,
+ ev->wrapper.glue->main_ev,
+ location);
+ if (!ok) {
+ tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
+ return false;
+ }
+
+ return true;
+}
+
+void _tevent_context_pop_use(struct tevent_context *ev,
+ const char *location)
+{
+ tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
+
+ 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);
+}
+
+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;
+}
diff --git a/lib/tevent/wscript b/lib/tevent/wscript
index 94d190f3b60..2395ead9aa9 100644
--- a/lib/tevent/wscript
+++ b/lib/tevent/wscript
@@ -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'''