dsdb:repl_meta_data: allow CONTROL_DBCHECK_FIX_LINK_DN_NAME to by pass rename
[Samba.git] / lib / tevent / tevent_wrapper.c
blob05c4c06968aae944f3584e4ba478febe898e0564
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 #include "tevent.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");
35 errno = ENOSYS;
36 return -1;
39 static struct tevent_fd *tevent_wrapper_glue_add_fd(struct tevent_context *ev,
40 TALLOC_CTX *mem_ctx,
41 int fd, uint16_t flags,
42 tevent_fd_handler_t handler,
43 void *private_data,
44 const char *handler_name,
45 const char *location)
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");
52 return NULL;
55 if (glue->main_ev == NULL) {
56 errno = EINVAL;
57 return NULL;
60 fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
61 handler, private_data,
62 handler_name, location);
63 if (fde == NULL) {
64 return NULL;
67 fde->wrapper = glue;
69 return fde;
72 static struct tevent_timer *tevent_wrapper_glue_add_timer(struct tevent_context *ev,
73 TALLOC_CTX *mem_ctx,
74 struct timeval next_event,
75 tevent_timer_handler_t handler,
76 void *private_data,
77 const char *handler_name,
78 const char *location)
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");
85 return NULL;
88 if (glue->main_ev == NULL) {
89 errno = EINVAL;
90 return NULL;
93 te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
94 handler, private_data,
95 handler_name, location);
96 if (te == NULL) {
97 return NULL;
100 te->wrapper = glue;
102 return te;
105 static void tevent_wrapper_glue_schedule_immediate(struct tevent_immediate *im,
106 struct tevent_context *ev,
107 tevent_immediate_handler_t handler,
108 void *private_data,
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");
116 return;
119 if (glue->main_ev == NULL) {
120 tevent_abort(ev, location);
121 errno = EINVAL;
122 return;
125 _tevent_schedule_immediate(im, glue->main_ev,
126 handler, private_data,
127 handler_name, location);
129 im->wrapper = glue;
131 return;
134 static struct tevent_signal *tevent_wrapper_glue_add_signal(struct tevent_context *ev,
135 TALLOC_CTX *mem_ctx,
136 int signum, int sa_flags,
137 tevent_signal_handler_t handler,
138 void *private_data,
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");
147 return NULL;
150 if (glue->main_ev == NULL) {
151 errno = EINVAL;
152 return NULL;
155 se = _tevent_add_signal(glue->main_ev, mem_ctx,
156 signum, sa_flags,
157 handler, private_data,
158 handler_name, location);
159 if (se == NULL) {
160 return NULL;
163 se->wrapper = glue;
165 return se;
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");
171 errno = ENOSYS;
172 return -1;
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");
178 errno = ENOSYS;
179 return -1;
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;
203 #ifdef HAVE_PTHREAD
204 struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
205 #endif
207 if (glue == 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;
218 if (glue->busy) {
219 return -1;
222 main_ev = glue->main_ev;
223 if (main_ev == NULL) {
224 return 0;
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);
234 #ifdef HAVE_PTHREAD
235 for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
236 int ret;
238 tctxn = tctx->next;
240 if (tctx->event_ctx != glue->wrap_ev) {
241 continue;
244 ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
245 if (ret != 0) {
246 abort();
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);
259 if (ret != 0) {
260 abort();
263 DLIST_REMOVE(main_ev->threaded_contexts, tctx);
265 #endif
267 for (fd = main_ev->fd_events; fd; fd = fn) {
268 fn = fd->next;
270 if (fd->wrapper != glue) {
271 continue;
274 tevent_fd_set_flags(fd, 0);
276 fd->wrapper = NULL;
277 fd->event_ctx = NULL;
278 DLIST_REMOVE(main_ev->fd_events, fd);
281 for (te = main_ev->timer_events; te; te = tn) {
282 tn = te->next;
284 if (te->wrapper != glue) {
285 continue;
288 te->wrapper = NULL;
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) {
298 in = ie->next;
300 if (ie->wrapper != glue) {
301 continue;
304 ie->wrapper = NULL;
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) {
311 sn = se->next;
313 if (se->wrapper != glue) {
314 continue;
317 se->wrapper = NULL;
318 tevent_cleanup_pending_signal_handlers(se);
321 return 0;
324 struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
325 TALLOC_CTX *mem_ctx,
326 const struct tevent_wrapper_ops *ops,
327 void *pstate,
328 size_t psize,
329 const char *type,
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",
341 __func__, location);
342 errno = EINVAL;
343 return NULL;
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",
352 __func__, location);
353 errno = EINVAL;
354 return NULL;
357 ev = talloc_zero(mem_ctx, struct tevent_context);
358 if (ev == NULL) {
359 return NULL;
361 ev->ops = &tevent_wrapper_glue_ops;
363 ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
364 if (ev->wrapper.glue == NULL) {
365 talloc_free(ev);
366 return 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) {
376 talloc_free(ev);
377 return 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;
384 return ev;
387 bool tevent_context_is_wrapper(struct tevent_context *ev)
389 if (ev->wrapper.glue != NULL) {
390 return true;
393 return false;
396 _PRIVATE_
397 struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
399 if (ev == NULL) {
400 return NULL;
403 if (ev->wrapper.glue == NULL) {
404 return ev;
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 {
418 const void *ev_ptr;
419 const struct tevent_wrapper_glue *wrapper;
420 } wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
422 static size_t wrapper_stack_idx;
424 _PRIVATE_
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
431 * without a wrapper.
433 if (unlikely(ev->wrapper.glue != wrapper)) {
434 tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
435 return;
438 if (wrapper != NULL) {
439 if (unlikely(wrapper->busy)) {
440 tevent_abort(ev, "wrapper already busy!");
441 return;
443 wrapper->busy = true;
446 if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
447 tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
448 return;
451 wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
452 .ev_ptr = ev,
453 .wrapper = wrapper,
455 wrapper_stack_idx++;
458 _PRIVATE_
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");
476 return;
478 wrapper_stack_idx--;
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!");
486 return;
488 if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
489 tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
490 return;
493 if (wrapper == NULL) {
494 return;
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)
510 bool ok;
512 if (ev->wrapper.glue == NULL) {
513 tevent_wrapper_push_use_internal(ev, NULL);
514 return true;
517 if (ev->wrapper.glue->main_ev == NULL) {
518 return false;
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,
525 location);
526 if (!ok) {
527 tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
528 return false;
531 return true;
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) {
540 return;
543 if (ev->wrapper.glue->main_ev == NULL) {
544 return;
547 ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
548 ev->wrapper.glue->private_state,
549 ev->wrapper.glue->main_ev,
550 location);
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) {
560 return false;
563 if (main_ev1 == main_ev2) {
564 return true;
567 return false;