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);
279 tevent_common_fd_disarm(fd
);
282 for (te
= main_ev
->timer_events
; te
; te
= tn
) {
285 if (te
->wrapper
!= glue
) {
290 te
->event_ctx
= NULL
;
292 if (main_ev
->last_zero_timer
== te
) {
293 main_ev
->last_zero_timer
= DLIST_PREV(te
);
295 DLIST_REMOVE(main_ev
->timer_events
, te
);
298 for (ie
= main_ev
->immediate_events
; ie
; ie
= in
) {
301 if (ie
->wrapper
!= glue
) {
306 ie
->event_ctx
= NULL
;
307 ie
->cancel_fn
= NULL
;
308 DLIST_REMOVE(main_ev
->immediate_events
, ie
);
311 for (se
= main_ev
->signal_events
; se
; se
= sn
) {
314 if (se
->wrapper
!= glue
) {
319 tevent_cleanup_pending_signal_handlers(se
);
325 struct tevent_context
*_tevent_context_wrapper_create(struct tevent_context
*main_ev
,
327 const struct tevent_wrapper_ops
*ops
,
331 const char *location
)
333 void **ppstate
= (void **)pstate
;
334 struct tevent_context
*ev
= NULL
;
336 if (main_ev
->wrapper
.glue
!= NULL
) {
338 * stacking of wrappers is not supported
340 tevent_debug(main_ev
->wrapper
.glue
->main_ev
, TEVENT_DEBUG_FATAL
,
341 "%s: %s() stacking not allowed\n",
347 if (main_ev
->nesting
.allowed
) {
349 * wrappers conflict with nesting
351 tevent_debug(main_ev
, TEVENT_DEBUG_FATAL
,
352 "%s: %s() conflicts with nesting\n",
358 ev
= talloc_zero(mem_ctx
, struct tevent_context
);
362 ev
->ops
= &tevent_wrapper_glue_ops
;
364 ev
->wrapper
.glue
= talloc_zero(ev
, struct tevent_wrapper_glue
);
365 if (ev
->wrapper
.glue
== NULL
) {
370 talloc_set_destructor(ev
, tevent_wrapper_context_destructor
);
372 ev
->wrapper
.glue
->wrap_ev
= ev
;
373 ev
->wrapper
.glue
->main_ev
= main_ev
;
374 ev
->wrapper
.glue
->ops
= ops
;
375 ev
->wrapper
.glue
->private_state
= talloc_zero_size(ev
->wrapper
.glue
, psize
);
376 if (ev
->wrapper
.glue
->private_state
== NULL
) {
380 talloc_set_name_const(ev
->wrapper
.glue
->private_state
, type
);
382 DLIST_ADD_END(main_ev
->wrapper
.list
, ev
->wrapper
.glue
);
384 *ppstate
= ev
->wrapper
.glue
->private_state
;
388 bool tevent_context_is_wrapper(struct tevent_context
*ev
)
390 if (ev
->wrapper
.glue
!= NULL
) {
398 struct tevent_context
*tevent_wrapper_main_ev(struct tevent_context
*ev
)
404 if (ev
->wrapper
.glue
== NULL
) {
408 return ev
->wrapper
.glue
->main_ev
;
412 * 32 stack elements should be more than enough
414 * e.g. Samba uses just 8 elements for [un]become_{root,user}()
416 #define TEVENT_WRAPPER_STACK_SIZE 32
418 static struct tevent_wrapper_stack
{
420 const struct tevent_wrapper_glue
*wrapper
;
421 } wrapper_stack
[TEVENT_WRAPPER_STACK_SIZE
];
423 static size_t wrapper_stack_idx
;
426 void tevent_wrapper_push_use_internal(struct tevent_context
*ev
,
427 struct tevent_wrapper_glue
*wrapper
)
430 * ev and wrapper need to belong together!
431 * It's also fine to only have a raw ev
434 if (unlikely(ev
->wrapper
.glue
!= wrapper
)) {
435 tevent_abort(ev
, "tevent_wrapper_push_use_internal() invalid arguments");
439 if (wrapper
!= NULL
) {
440 if (unlikely(wrapper
->busy
)) {
441 tevent_abort(ev
, "wrapper already busy!");
444 wrapper
->busy
= true;
447 if (unlikely(wrapper_stack_idx
>= TEVENT_WRAPPER_STACK_SIZE
)) {
448 tevent_abort(ev
, "TEVENT_WRAPPER_STACK_SIZE overflow");
452 wrapper_stack
[wrapper_stack_idx
] = (struct tevent_wrapper_stack
) {
460 void tevent_wrapper_pop_use_internal(const struct tevent_context
*__ev_ptr
,
461 struct tevent_wrapper_glue
*wrapper
)
463 struct tevent_context
*main_ev
= NULL
;
466 * Note that __ev_ptr might a a stale pointer and should not
467 * be touched, we just compare the pointer value in order
468 * to enforce the stack order.
471 if (wrapper
!= NULL
) {
472 main_ev
= wrapper
->main_ev
;
475 if (unlikely(wrapper_stack_idx
== 0)) {
476 tevent_abort(main_ev
, "tevent_wrapper stack already empty");
481 if (wrapper
!= NULL
) {
482 wrapper
->busy
= false;
485 if (wrapper_stack
[wrapper_stack_idx
].ev_ptr
!= __ev_ptr
) {
486 tevent_abort(main_ev
, "tevent_wrapper_pop_use mismatch ev!");
489 if (wrapper_stack
[wrapper_stack_idx
].wrapper
!= wrapper
) {
490 tevent_abort(main_ev
, "tevent_wrapper_pop_use mismatch wrap!");
494 if (wrapper
== NULL
) {
498 if (wrapper
->destroyed
) {
500 * Notice that we can't use TALLOC_FREE()
501 * here because wrapper is a talloc child
502 * of wrapper->wrap_ev.
504 talloc_free(wrapper
->wrap_ev
);
508 bool _tevent_context_push_use(struct tevent_context
*ev
,
509 const char *location
)
513 if (ev
->wrapper
.glue
== NULL
) {
514 tevent_wrapper_push_use_internal(ev
, NULL
);
518 if (ev
->wrapper
.glue
->main_ev
== NULL
) {
522 tevent_wrapper_push_use_internal(ev
, ev
->wrapper
.glue
);
523 ok
= ev
->wrapper
.glue
->ops
->before_use(ev
->wrapper
.glue
->wrap_ev
,
524 ev
->wrapper
.glue
->private_state
,
525 ev
->wrapper
.glue
->main_ev
,
528 tevent_wrapper_pop_use_internal(ev
, ev
->wrapper
.glue
);
535 void _tevent_context_pop_use(struct tevent_context
*ev
,
536 const char *location
)
538 tevent_wrapper_pop_use_internal(ev
, ev
->wrapper
.glue
);
540 if (ev
->wrapper
.glue
== NULL
) {
544 if (ev
->wrapper
.glue
->main_ev
== NULL
) {
548 ev
->wrapper
.glue
->ops
->after_use(ev
->wrapper
.glue
->wrap_ev
,
549 ev
->wrapper
.glue
->private_state
,
550 ev
->wrapper
.glue
->main_ev
,
554 bool tevent_context_same_loop(struct tevent_context
*ev1
,
555 struct tevent_context
*ev2
)
557 struct tevent_context
*main_ev1
= tevent_wrapper_main_ev(ev1
);
558 struct tevent_context
*main_ev2
= tevent_wrapper_main_ev(ev2
);
560 if (main_ev1
== NULL
) {
564 if (main_ev1
== main_ev2
) {