ctdb-recoverd: Flatten update_flags_on_all_nodes()
[Samba.git] / lib / tevent / tevent_wrapper.c
bloba0e915f67532ecd67f2ee26b2fc6c0e8d3963668
1 /*
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
8 ** under the LGPL
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/>.
24 #include "replace.h"
25 #ifdef HAVE_PTHREAD
26 #include "system/threads.h"
27 #endif
28 #define TEVENT_DEPRECATED 1
29 #include "tevent.h"
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");
36 errno = ENOSYS;
37 return -1;
40 static struct tevent_fd *tevent_wrapper_glue_add_fd(struct tevent_context *ev,
41 TALLOC_CTX *mem_ctx,
42 int fd, uint16_t flags,
43 tevent_fd_handler_t handler,
44 void *private_data,
45 const char *handler_name,
46 const char *location)
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");
53 return NULL;
56 if (glue->main_ev == NULL) {
57 errno = EINVAL;
58 return NULL;
61 fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
62 handler, private_data,
63 handler_name, location);
64 if (fde == NULL) {
65 return NULL;
68 fde->wrapper = glue;
70 return fde;
73 static struct tevent_timer *tevent_wrapper_glue_add_timer(struct tevent_context *ev,
74 TALLOC_CTX *mem_ctx,
75 struct timeval next_event,
76 tevent_timer_handler_t handler,
77 void *private_data,
78 const char *handler_name,
79 const char *location)
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");
86 return NULL;
89 if (glue->main_ev == NULL) {
90 errno = EINVAL;
91 return NULL;
94 te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
95 handler, private_data,
96 handler_name, location);
97 if (te == NULL) {
98 return NULL;
101 te->wrapper = glue;
103 return te;
106 static void tevent_wrapper_glue_schedule_immediate(struct tevent_immediate *im,
107 struct tevent_context *ev,
108 tevent_immediate_handler_t handler,
109 void *private_data,
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");
117 return;
120 if (glue->main_ev == NULL) {
121 tevent_abort(ev, location);
122 errno = EINVAL;
123 return;
126 _tevent_schedule_immediate(im, glue->main_ev,
127 handler, private_data,
128 handler_name, location);
130 im->wrapper = glue;
132 return;
135 static struct tevent_signal *tevent_wrapper_glue_add_signal(struct tevent_context *ev,
136 TALLOC_CTX *mem_ctx,
137 int signum, int sa_flags,
138 tevent_signal_handler_t handler,
139 void *private_data,
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");
148 return NULL;
151 if (glue->main_ev == NULL) {
152 errno = EINVAL;
153 return NULL;
156 se = _tevent_add_signal(glue->main_ev, mem_ctx,
157 signum, sa_flags,
158 handler, private_data,
159 handler_name, location);
160 if (se == NULL) {
161 return NULL;
164 se->wrapper = glue;
166 return se;
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");
172 errno = ENOSYS;
173 return -1;
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");
179 errno = ENOSYS;
180 return -1;
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;
204 #ifdef HAVE_PTHREAD
205 struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
206 #endif
208 if (glue == NULL) {
209 tevent_abort(wrap_ev,
210 "tevent_wrapper_context_destructor() active on main");
211 /* static checker support, return below is never reached */
212 return -1;
215 if (glue->destroyed && glue->busy) {
216 tevent_common_check_double_free(wrap_ev,
217 "tevent_context wrapper double free");
219 glue->destroyed = true;
221 if (glue->busy) {
222 return -1;
225 main_ev = glue->main_ev;
226 if (main_ev == NULL) {
227 return 0;
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);
237 #ifdef HAVE_PTHREAD
238 for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
239 int ret;
241 tctxn = tctx->next;
243 if (tctx->event_ctx != glue->wrap_ev) {
244 continue;
247 ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
248 if (ret != 0) {
249 abort();
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);
262 if (ret != 0) {
263 abort();
266 DLIST_REMOVE(main_ev->threaded_contexts, tctx);
268 #endif
270 for (fd = main_ev->fd_events; fd; fd = fn) {
271 fn = fd->next;
273 if (fd->wrapper != glue) {
274 continue;
277 tevent_fd_set_flags(fd, 0);
279 fd->wrapper = NULL;
280 fd->event_ctx = NULL;
281 DLIST_REMOVE(main_ev->fd_events, fd);
284 for (te = main_ev->timer_events; te; te = tn) {
285 tn = te->next;
287 if (te->wrapper != glue) {
288 continue;
291 te->wrapper = NULL;
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) {
301 in = ie->next;
303 if (ie->wrapper != glue) {
304 continue;
307 ie->wrapper = NULL;
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) {
314 sn = se->next;
316 if (se->wrapper != glue) {
317 continue;
320 se->wrapper = NULL;
321 tevent_cleanup_pending_signal_handlers(se);
324 return 0;
327 struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
328 TALLOC_CTX *mem_ctx,
329 const struct tevent_wrapper_ops *ops,
330 void *pstate,
331 size_t psize,
332 const char *type,
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",
344 __func__, location);
345 errno = EINVAL;
346 return NULL;
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",
355 __func__, location);
356 errno = EINVAL;
357 return NULL;
360 ev = talloc_zero(mem_ctx, struct tevent_context);
361 if (ev == NULL) {
362 return NULL;
364 ev->ops = &tevent_wrapper_glue_ops;
366 ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
367 if (ev->wrapper.glue == NULL) {
368 talloc_free(ev);
369 return 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) {
379 talloc_free(ev);
380 return 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;
387 return ev;
390 bool tevent_context_is_wrapper(struct tevent_context *ev)
392 if (ev->wrapper.glue != NULL) {
393 return true;
396 return false;
399 _PRIVATE_
400 struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
402 if (ev == NULL) {
403 return NULL;
406 if (ev->wrapper.glue == NULL) {
407 return ev;
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 {
421 const void *ev_ptr;
422 const struct tevent_wrapper_glue *wrapper;
423 } wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
425 static size_t wrapper_stack_idx;
427 _PRIVATE_
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
434 * without a wrapper.
436 if (unlikely(ev->wrapper.glue != wrapper)) {
437 tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
438 return;
441 if (wrapper != NULL) {
442 if (unlikely(wrapper->busy)) {
443 tevent_abort(ev, "wrapper already busy!");
444 return;
446 wrapper->busy = true;
449 if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
450 tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
451 return;
454 wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
455 .ev_ptr = ev,
456 .wrapper = wrapper,
458 wrapper_stack_idx++;
461 _PRIVATE_
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");
479 return;
481 wrapper_stack_idx--;
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!");
489 return;
491 if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
492 tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
493 return;
496 if (wrapper == NULL) {
497 return;
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)
513 bool ok;
515 if (ev->wrapper.glue == NULL) {
516 tevent_wrapper_push_use_internal(ev, NULL);
517 return true;
520 if (ev->wrapper.glue->main_ev == NULL) {
521 return false;
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,
528 location);
529 if (!ok) {
530 tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
531 return false;
534 return true;
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) {
543 return;
546 if (ev->wrapper.glue->main_ev == NULL) {
547 return;
550 ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
551 ev->wrapper.glue->private_state,
552 ev->wrapper.glue->main_ev,
553 location);
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) {
563 return false;
566 if (main_ev1 == main_ev2) {
567 return true;
570 return false;