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
->wrapper
.glue
->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
) {