2 Infrastructure for event context wrappers
4 Copyright (C) Stefan Metzmacher 2014
6 ** NOTE! The following LGPL license applies to the tevent
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 #include "system/threads.h"
29 #include "tevent_internal.h"
30 #include "tevent_util.h"
32 static int tevent_wrapper_glue_context_init(struct tevent_context *ev)
34 tevent_abort(ev, "tevent_wrapper_glue_context_init() called");
39 static struct tevent_fd *tevent_wrapper_glue_add_fd(struct tevent_context *ev,
41 int fd, uint16_t flags,
42 tevent_fd_handler_t handler,
44 const char *handler_name,
47 struct tevent_wrapper_glue *glue = ev->wrapper.glue;
48 struct tevent_fd *fde = NULL;
50 if (glue->destroyed) {
51 tevent_abort(ev, "add_fd wrapper use after free");
55 if (glue->main_ev == NULL) {
60 fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
61 handler, private_data,
62 handler_name, location);
72 static struct tevent_timer *tevent_wrapper_glue_add_timer(struct tevent_context *ev,
74 struct timeval next_event,
75 tevent_timer_handler_t handler,
77 const char *handler_name,
80 struct tevent_wrapper_glue *glue = ev->wrapper.glue;
81 struct tevent_timer *te = NULL;
83 if (glue->destroyed) {
84 tevent_abort(ev, "add_timer wrapper use after free");
88 if (glue->main_ev == NULL) {
93 te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
94 handler, private_data,
95 handler_name, location);
105 static void tevent_wrapper_glue_schedule_immediate(struct tevent_immediate *im,
106 struct tevent_context *ev,
107 tevent_immediate_handler_t handler,
109 const char *handler_name,
110 const char *location)
112 struct tevent_wrapper_glue *glue = ev->wrapper.glue;
114 if (glue->destroyed) {
115 tevent_abort(ev, "scheduke_immediate wrapper use after free");
119 if (glue->main_ev == NULL) {
120 tevent_abort(ev, location);
125 _tevent_schedule_immediate(im, glue->main_ev,
126 handler, private_data,
127 handler_name, location);
134 static struct tevent_signal *tevent_wrapper_glue_add_signal(struct tevent_context *ev,
136 int signum, int sa_flags,
137 tevent_signal_handler_t handler,
139 const char *handler_name,
140 const char *location)
142 struct tevent_wrapper_glue *glue = ev->wrapper.glue;
143 struct tevent_signal *se = NULL;
145 if (glue->destroyed) {
146 tevent_abort(ev, "add_signal wrapper use after free");
150 if (glue->main_ev == NULL) {
155 se = _tevent_add_signal(glue->main_ev, mem_ctx,
157 handler, private_data,
158 handler_name, location);
168 static int tevent_wrapper_glue_loop_once(struct tevent_context *ev, const char *location)
170 tevent_abort(ev, "tevent_wrapper_glue_loop_once() called");
175 static int tevent_wrapper_glue_loop_wait(struct tevent_context *ev, const char *location)
177 tevent_abort(ev, "tevent_wrapper_glue_loop_wait() called");
182 static const struct tevent_ops tevent_wrapper_glue_ops = {
183 .context_init = tevent_wrapper_glue_context_init,
184 .add_fd = tevent_wrapper_glue_add_fd,
185 .set_fd_close_fn = tevent_common_fd_set_close_fn,
186 .get_fd_flags = tevent_common_fd_get_flags,
187 .set_fd_flags = tevent_common_fd_set_flags,
188 .add_timer = tevent_wrapper_glue_add_timer,
189 .schedule_immediate = tevent_wrapper_glue_schedule_immediate,
190 .add_signal = tevent_wrapper_glue_add_signal,
191 .loop_once = tevent_wrapper_glue_loop_once,
192 .loop_wait = tevent_wrapper_glue_loop_wait,
195 static int tevent_wrapper_context_destructor(struct tevent_context *wrap_ev)
197 struct tevent_wrapper_glue *glue = wrap_ev->wrapper.glue;
198 struct tevent_context *main_ev = NULL;
199 struct tevent_fd *fd = NULL, *fn = NULL;
200 struct tevent_timer *te = NULL, *tn = NULL;
201 struct tevent_immediate *ie = NULL, *in = NULL;
202 struct tevent_signal *se = NULL, *sn = NULL;
204 struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
208 tevent_abort(wrap_ev,
209 "tevent_wrapper_context_destructor() active on main");
212 if (glue->destroyed && glue->busy) {
213 tevent_common_check_double_free(wrap_ev,
214 "tevent_context wrapper double free");
216 glue->destroyed = true;
222 main_ev = glue->main_ev;
223 if (main_ev == NULL) {
227 tevent_debug(wrap_ev, TEVENT_DEBUG_TRACE,
228 "Destroying wrapper context %p \"%s\"\n",
229 wrap_ev, talloc_get_name(glue->private_state));
231 glue->main_ev = NULL;
232 DLIST_REMOVE(main_ev->wrapper.list, glue);
235 for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
240 if (tctx->event_ctx != glue->wrap_ev) {
244 ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
250 * Indicate to the thread that the tevent_context is
251 * gone. The counterpart of this is in
252 * _tevent_threaded_schedule_immediate, there we read
253 * this under the threaded_context's mutex.
256 tctx->event_ctx = NULL;
258 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
263 DLIST_REMOVE(main_ev->threaded_contexts, tctx);
267 for (fd = main_ev->fd_events; fd; fd = fn) {
270 if (fd->wrapper != glue) {
274 tevent_fd_set_flags(fd, 0);
277 fd->event_ctx = NULL;
278 DLIST_REMOVE(main_ev->fd_events, fd);
281 for (te = main_ev->timer_events; te; te = tn) {
284 if (te->wrapper != glue) {
289 te->event_ctx = NULL;
291 if (main_ev->last_zero_timer == te) {
292 main_ev->last_zero_timer = DLIST_PREV(te);
294 DLIST_REMOVE(main_ev->timer_events, te);
297 for (ie = main_ev->immediate_events; ie; ie = in) {
300 if (ie->wrapper != glue) {
305 ie->event_ctx = NULL;
306 ie->cancel_fn = NULL;
307 DLIST_REMOVE(main_ev->immediate_events, ie);
310 for (se = main_ev->signal_events; se; se = sn) {
313 if (se->wrapper != glue) {
318 tevent_cleanup_pending_signal_handlers(se);
324 struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
326 const struct tevent_wrapper_ops *ops,
330 const char *location)
332 void **ppstate = (void **)pstate;
333 struct tevent_context *ev = NULL;
335 if (main_ev->wrapper.glue != NULL) {
337 * stacking of wrappers is not supported
339 tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
340 "%s: %s() stacking not allowed\n",
346 if (main_ev->nesting.allowed) {
348 * wrappers conflict with nesting
350 tevent_debug(main_ev, TEVENT_DEBUG_FATAL,
351 "%s: %s() conflicts with nesting\n",
357 ev = talloc_zero(mem_ctx, struct tevent_context);
361 ev->ops = &tevent_wrapper_glue_ops;
363 ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
364 if (ev->wrapper.glue == NULL) {
369 talloc_set_destructor(ev, tevent_wrapper_context_destructor);
371 ev->wrapper.glue->wrap_ev = ev;
372 ev->wrapper.glue->main_ev = main_ev;
373 ev->wrapper.glue->ops = ops;
374 ev->wrapper.glue->private_state = talloc_size(ev->wrapper.glue, psize);
375 if (ev->wrapper.glue->private_state == NULL) {
379 talloc_set_name_const(ev->wrapper.glue->private_state, type);
381 DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
383 *ppstate = ev->wrapper.glue->private_state;
387 bool tevent_context_is_wrapper(struct tevent_context *ev)
389 if (ev->wrapper.glue != NULL) {
397 struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
403 if (ev->wrapper.glue == NULL) {
407 return ev->wrapper.glue->main_ev;
411 * 32 stack elements should be more than enough
413 * e.g. Samba uses just 8 elements for [un]become_{root,user}()
415 #define TEVENT_WRAPPER_STACK_SIZE 32
417 static struct tevent_wrapper_stack {
419 const struct tevent_wrapper_glue *wrapper;
420 } wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
422 static size_t wrapper_stack_idx;
425 void tevent_wrapper_push_use_internal(struct tevent_context *ev,
426 struct tevent_wrapper_glue *wrapper)
429 * ev and wrapper need to belong together!
430 * It's also fine to only have a raw ev
433 if (unlikely(ev->wrapper.glue != wrapper)) {
434 tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
438 if (wrapper != NULL) {
439 if (unlikely(wrapper->busy)) {
440 tevent_abort(ev, "wrapper already busy!");
443 wrapper->busy = true;
446 if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
447 tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
451 wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
459 void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
460 struct tevent_wrapper_glue *wrapper)
462 struct tevent_context *main_ev = NULL;
465 * Note that __ev_ptr might a a stale pointer and should not
466 * be touched, we just compare the pointer value in order
467 * to enforce the stack order.
470 if (wrapper != NULL) {
471 main_ev = wrapper->main_ev;
474 if (unlikely(wrapper_stack_idx == 0)) {
475 tevent_abort(main_ev, "tevent_wrapper stack already empty");
480 if (wrapper != NULL) {
481 wrapper->busy = false;
484 if (wrapper_stack[wrapper_stack_idx].ev_ptr != __ev_ptr) {
485 tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch ev!");
488 if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
489 tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
493 if (wrapper == NULL) {
497 if (wrapper->destroyed) {
499 * Notice that we can't use TALLOC_FREE()
500 * here because wrapper is a talloc child
501 * of wrapper->wrap_ev.
503 talloc_free(wrapper->wrap_ev);
507 bool _tevent_context_push_use(struct tevent_context *ev,
508 const char *location)
512 if (ev->wrapper.glue == NULL) {
513 tevent_wrapper_push_use_internal(ev, NULL);
517 if (ev->wrapper.glue->main_ev == NULL) {
521 tevent_wrapper_push_use_internal(ev, ev->wrapper.glue);
522 ok = ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
523 ev->wrapper.glue->private_state,
524 ev->wrapper.glue->main_ev,
527 tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
534 void _tevent_context_pop_use(struct tevent_context *ev,
535 const char *location)
537 tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
539 if (ev->wrapper.glue == NULL) {
543 if (ev->wrapper.glue->main_ev == NULL) {
547 ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
548 ev->wrapper.glue->private_state,
549 ev->wrapper.glue->main_ev,
553 bool tevent_context_same_loop(struct tevent_context *ev1,
554 struct tevent_context *ev2)
556 struct tevent_context *main_ev1 = tevent_wrapper_main_ev(ev1);
557 struct tevent_context *main_ev2 = tevent_wrapper_main_ev(ev2);
559 if (main_ev1 == NULL) {
563 if (main_ev1 == main_ev2) {