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"
28 #define TEVENT_DEPRECATED 1
30 #include "tevent_internal.h"
31 #include "tevent_util.h"
33 static int tevent_wrapper_glue_context_init(struct tevent_context
*ev
)
35 tevent_abort(ev
, "tevent_wrapper_glue_context_init() called");
40 static struct tevent_fd
*tevent_wrapper_glue_add_fd(struct tevent_context
*ev
,
42 int fd
, uint16_t flags
,
43 tevent_fd_handler_t handler
,
45 const char *handler_name
,
48 struct tevent_wrapper_glue
*glue
= ev
->wrapper
.glue
;
49 struct tevent_fd
*fde
= NULL
;
51 if (glue
->destroyed
) {
52 tevent_abort(ev
, "add_fd wrapper use after free");
56 if (glue
->main_ev
== NULL
) {
61 fde
= _tevent_add_fd(glue
->main_ev
, mem_ctx
, fd
, flags
,
62 handler
, private_data
,
63 handler_name
, location
);
73 static struct tevent_timer
*tevent_wrapper_glue_add_timer(struct tevent_context
*ev
,
75 struct timeval next_event
,
76 tevent_timer_handler_t handler
,
78 const char *handler_name
,
81 struct tevent_wrapper_glue
*glue
= ev
->wrapper
.glue
;
82 struct tevent_timer
*te
= NULL
;
84 if (glue
->destroyed
) {
85 tevent_abort(ev
, "add_timer wrapper use after free");
89 if (glue
->main_ev
== NULL
) {
94 te
= _tevent_add_timer(glue
->main_ev
, mem_ctx
, next_event
,
95 handler
, private_data
,
96 handler_name
, location
);
106 static void tevent_wrapper_glue_schedule_immediate(struct tevent_immediate
*im
,
107 struct tevent_context
*ev
,
108 tevent_immediate_handler_t handler
,
110 const char *handler_name
,
111 const char *location
)
113 struct tevent_wrapper_glue
*glue
= ev
->wrapper
.glue
;
115 if (glue
->destroyed
) {
116 tevent_abort(ev
, "scheduke_immediate wrapper use after free");
120 if (glue
->main_ev
== NULL
) {
121 tevent_abort(ev
, location
);
126 _tevent_schedule_immediate(im
, glue
->main_ev
,
127 handler
, private_data
,
128 handler_name
, location
);
135 static struct tevent_signal
*tevent_wrapper_glue_add_signal(struct tevent_context
*ev
,
137 int signum
, int sa_flags
,
138 tevent_signal_handler_t handler
,
140 const char *handler_name
,
141 const char *location
)
143 struct tevent_wrapper_glue
*glue
= ev
->wrapper
.glue
;
144 struct tevent_signal
*se
= NULL
;
146 if (glue
->destroyed
) {
147 tevent_abort(ev
, "add_signal wrapper use after free");
151 if (glue
->main_ev
== NULL
) {
156 se
= _tevent_add_signal(glue
->main_ev
, mem_ctx
,
158 handler
, private_data
,
159 handler_name
, location
);
169 static int tevent_wrapper_glue_loop_once(struct tevent_context
*ev
, const char *location
)
171 tevent_abort(ev
, "tevent_wrapper_glue_loop_once() called");
176 static int tevent_wrapper_glue_loop_wait(struct tevent_context
*ev
, const char *location
)
178 tevent_abort(ev
, "tevent_wrapper_glue_loop_wait() called");
183 static const struct tevent_ops tevent_wrapper_glue_ops
= {
184 .context_init
= tevent_wrapper_glue_context_init
,
185 .add_fd
= tevent_wrapper_glue_add_fd
,
186 .set_fd_close_fn
= tevent_common_fd_set_close_fn
,
187 .get_fd_flags
= tevent_common_fd_get_flags
,
188 .set_fd_flags
= tevent_common_fd_set_flags
,
189 .add_timer
= tevent_wrapper_glue_add_timer
,
190 .schedule_immediate
= tevent_wrapper_glue_schedule_immediate
,
191 .add_signal
= tevent_wrapper_glue_add_signal
,
192 .loop_once
= tevent_wrapper_glue_loop_once
,
193 .loop_wait
= tevent_wrapper_glue_loop_wait
,
196 static int tevent_wrapper_context_destructor(struct tevent_context
*wrap_ev
)
198 struct tevent_wrapper_glue
*glue
= wrap_ev
->wrapper
.glue
;
199 struct tevent_context
*main_ev
= NULL
;
200 struct tevent_fd
*fd
= NULL
, *fn
= NULL
;
201 struct tevent_timer
*te
= NULL
, *tn
= NULL
;
202 struct tevent_immediate
*ie
= NULL
, *in
= NULL
;
203 struct tevent_signal
*se
= NULL
, *sn
= NULL
;
205 struct tevent_threaded_context
*tctx
= NULL
, *tctxn
= NULL
;
209 tevent_abort(wrap_ev
,
210 "tevent_wrapper_context_destructor() active on main");
211 /* static checker support, return below is never reached */
215 if (glue
->destroyed
&& glue
->busy
) {
216 tevent_common_check_double_free(wrap_ev
,
217 "tevent_context wrapper double free");
219 glue
->destroyed
= true;
225 main_ev
= glue
->main_ev
;
226 if (main_ev
== NULL
) {
230 tevent_debug(wrap_ev
, TEVENT_DEBUG_TRACE
,
231 "Destroying wrapper context %p \"%s\"\n",
232 wrap_ev
, talloc_get_name(glue
->private_state
));
234 glue
->main_ev
= NULL
;
235 DLIST_REMOVE(main_ev
->wrapper
.list
, glue
);
238 for (tctx
= main_ev
->threaded_contexts
; tctx
!= NULL
; tctx
= tctxn
) {
243 if (tctx
->event_ctx
!= glue
->wrap_ev
) {
247 ret
= pthread_mutex_lock(&tctx
->event_ctx_mutex
);
253 * Indicate to the thread that the tevent_context is
254 * gone. The counterpart of this is in
255 * _tevent_threaded_schedule_immediate, there we read
256 * this under the threaded_context's mutex.
259 tctx
->event_ctx
= NULL
;
261 ret
= pthread_mutex_unlock(&tctx
->event_ctx_mutex
);
266 DLIST_REMOVE(main_ev
->threaded_contexts
, tctx
);
270 for (fd
= main_ev
->fd_events
; fd
; fd
= fn
) {
273 if (fd
->wrapper
!= glue
) {
277 tevent_fd_set_flags(fd
, 0);
280 fd
->event_ctx
= NULL
;
281 DLIST_REMOVE(main_ev
->fd_events
, fd
);
284 for (te
= main_ev
->timer_events
; te
; te
= tn
) {
287 if (te
->wrapper
!= glue
) {
292 te
->event_ctx
= NULL
;
294 if (main_ev
->last_zero_timer
== te
) {
295 main_ev
->last_zero_timer
= DLIST_PREV(te
);
297 DLIST_REMOVE(main_ev
->timer_events
, te
);
300 for (ie
= main_ev
->immediate_events
; ie
; ie
= in
) {
303 if (ie
->wrapper
!= glue
) {
308 ie
->event_ctx
= NULL
;
309 ie
->cancel_fn
= NULL
;
310 DLIST_REMOVE(main_ev
->immediate_events
, ie
);
313 for (se
= main_ev
->signal_events
; se
; se
= sn
) {
316 if (se
->wrapper
!= glue
) {
321 tevent_cleanup_pending_signal_handlers(se
);
327 struct tevent_context
*_tevent_context_wrapper_create(struct tevent_context
*main_ev
,
329 const struct tevent_wrapper_ops
*ops
,
333 const char *location
)
335 void **ppstate
= (void **)pstate
;
336 struct tevent_context
*ev
= NULL
;
338 if (main_ev
->wrapper
.glue
!= NULL
) {
340 * stacking of wrappers is not supported
342 tevent_debug(main_ev
->wrapper
.glue
->main_ev
, TEVENT_DEBUG_FATAL
,
343 "%s: %s() stacking not allowed\n",
349 if (main_ev
->nesting
.allowed
) {
351 * wrappers conflict with nesting
353 tevent_debug(main_ev
, TEVENT_DEBUG_FATAL
,
354 "%s: %s() conflicts with nesting\n",
360 ev
= talloc_zero(mem_ctx
, struct tevent_context
);
364 ev
->ops
= &tevent_wrapper_glue_ops
;
366 ev
->wrapper
.glue
= talloc_zero(ev
, struct tevent_wrapper_glue
);
367 if (ev
->wrapper
.glue
== NULL
) {
372 talloc_set_destructor(ev
, tevent_wrapper_context_destructor
);
374 ev
->wrapper
.glue
->wrap_ev
= ev
;
375 ev
->wrapper
.glue
->main_ev
= main_ev
;
376 ev
->wrapper
.glue
->ops
= ops
;
377 ev
->wrapper
.glue
->private_state
= talloc_zero_size(ev
->wrapper
.glue
, psize
);
378 if (ev
->wrapper
.glue
->private_state
== NULL
) {
382 talloc_set_name_const(ev
->wrapper
.glue
->private_state
, type
);
384 DLIST_ADD_END(main_ev
->wrapper
.list
, ev
->wrapper
.glue
);
386 *ppstate
= ev
->wrapper
.glue
->private_state
;
390 bool tevent_context_is_wrapper(struct tevent_context
*ev
)
392 if (ev
->wrapper
.glue
!= NULL
) {
400 struct tevent_context
*tevent_wrapper_main_ev(struct tevent_context
*ev
)
406 if (ev
->wrapper
.glue
== NULL
) {
410 return ev
->wrapper
.glue
->main_ev
;
414 * 32 stack elements should be more than enough
416 * e.g. Samba uses just 8 elements for [un]become_{root,user}()
418 #define TEVENT_WRAPPER_STACK_SIZE 32
420 static struct tevent_wrapper_stack
{
422 const struct tevent_wrapper_glue
*wrapper
;
423 } wrapper_stack
[TEVENT_WRAPPER_STACK_SIZE
];
425 static size_t wrapper_stack_idx
;
428 void tevent_wrapper_push_use_internal(struct tevent_context
*ev
,
429 struct tevent_wrapper_glue
*wrapper
)
432 * ev and wrapper need to belong together!
433 * It's also fine to only have a raw ev
436 if (unlikely(ev
->wrapper
.glue
!= wrapper
)) {
437 tevent_abort(ev
, "tevent_wrapper_push_use_internal() invalid arguments");
441 if (wrapper
!= NULL
) {
442 if (unlikely(wrapper
->busy
)) {
443 tevent_abort(ev
, "wrapper already busy!");
446 wrapper
->busy
= true;
449 if (unlikely(wrapper_stack_idx
>= TEVENT_WRAPPER_STACK_SIZE
)) {
450 tevent_abort(ev
, "TEVENT_WRAPPER_STACK_SIZE overflow");
454 wrapper_stack
[wrapper_stack_idx
] = (struct tevent_wrapper_stack
) {
462 void tevent_wrapper_pop_use_internal(const struct tevent_context
*__ev_ptr
,
463 struct tevent_wrapper_glue
*wrapper
)
465 struct tevent_context
*main_ev
= NULL
;
468 * Note that __ev_ptr might a a stale pointer and should not
469 * be touched, we just compare the pointer value in order
470 * to enforce the stack order.
473 if (wrapper
!= NULL
) {
474 main_ev
= wrapper
->main_ev
;
477 if (unlikely(wrapper_stack_idx
== 0)) {
478 tevent_abort(main_ev
, "tevent_wrapper stack already empty");
483 if (wrapper
!= NULL
) {
484 wrapper
->busy
= false;
487 if (wrapper_stack
[wrapper_stack_idx
].ev_ptr
!= __ev_ptr
) {
488 tevent_abort(main_ev
, "tevent_wrapper_pop_use mismatch ev!");
491 if (wrapper_stack
[wrapper_stack_idx
].wrapper
!= wrapper
) {
492 tevent_abort(main_ev
, "tevent_wrapper_pop_use mismatch wrap!");
496 if (wrapper
== NULL
) {
500 if (wrapper
->destroyed
) {
502 * Notice that we can't use TALLOC_FREE()
503 * here because wrapper is a talloc child
504 * of wrapper->wrap_ev.
506 talloc_free(wrapper
->wrap_ev
);
510 bool _tevent_context_push_use(struct tevent_context
*ev
,
511 const char *location
)
515 if (ev
->wrapper
.glue
== NULL
) {
516 tevent_wrapper_push_use_internal(ev
, NULL
);
520 if (ev
->wrapper
.glue
->main_ev
== NULL
) {
524 tevent_wrapper_push_use_internal(ev
, ev
->wrapper
.glue
);
525 ok
= ev
->wrapper
.glue
->ops
->before_use(ev
->wrapper
.glue
->wrap_ev
,
526 ev
->wrapper
.glue
->private_state
,
527 ev
->wrapper
.glue
->main_ev
,
530 tevent_wrapper_pop_use_internal(ev
, ev
->wrapper
.glue
);
537 void _tevent_context_pop_use(struct tevent_context
*ev
,
538 const char *location
)
540 tevent_wrapper_pop_use_internal(ev
, ev
->wrapper
.glue
);
542 if (ev
->wrapper
.glue
== NULL
) {
546 if (ev
->wrapper
.glue
->main_ev
== NULL
) {
550 ev
->wrapper
.glue
->ops
->after_use(ev
->wrapper
.glue
->wrap_ev
,
551 ev
->wrapper
.glue
->private_state
,
552 ev
->wrapper
.glue
->main_ev
,
556 bool tevent_context_same_loop(struct tevent_context
*ev1
,
557 struct tevent_context
*ev2
)
559 struct tevent_context
*main_ev1
= tevent_wrapper_main_ev(ev1
);
560 struct tevent_context
*main_ev2
= tevent_wrapper_main_ev(ev2
);
562 if (main_ev1
== NULL
) {
566 if (main_ev1
== main_ev2
) {