s3:winbindd: call process_set_title() for locator child
[Samba.git] / lib / tevent / tevent_wrapper.c
blob3870d4fbb43a8f00a34e34730ead28ea589dafb5
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 tevent_common_fd_disarm(fd);
282 for (te = main_ev->timer_events; te; te = tn) {
283 tn = te->next;
285 if (te->wrapper != glue) {
286 continue;
289 te->wrapper = NULL;
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) {
299 in = ie->next;
301 if (ie->wrapper != glue) {
302 continue;
305 ie->wrapper = NULL;
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) {
312 sn = se->next;
314 if (se->wrapper != glue) {
315 continue;
318 se->wrapper = NULL;
319 tevent_cleanup_pending_signal_handlers(se);
322 return 0;
325 struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
326 TALLOC_CTX *mem_ctx,
327 const struct tevent_wrapper_ops *ops,
328 void *pstate,
329 size_t psize,
330 const char *type,
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",
342 __func__, location);
343 errno = EINVAL;
344 return NULL;
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",
353 __func__, location);
354 errno = EINVAL;
355 return NULL;
358 ev = talloc_zero(mem_ctx, struct tevent_context);
359 if (ev == NULL) {
360 return NULL;
362 ev->ops = &tevent_wrapper_glue_ops;
364 ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
365 if (ev->wrapper.glue == NULL) {
366 talloc_free(ev);
367 return 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) {
377 talloc_free(ev);
378 return 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;
385 return ev;
388 bool tevent_context_is_wrapper(struct tevent_context *ev)
390 if (ev->wrapper.glue != NULL) {
391 return true;
394 return false;
397 _PRIVATE_
398 struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
400 if (ev == NULL) {
401 return NULL;
404 if (ev->wrapper.glue == NULL) {
405 return ev;
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 {
419 const void *ev_ptr;
420 const struct tevent_wrapper_glue *wrapper;
421 } wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
423 static size_t wrapper_stack_idx;
425 _PRIVATE_
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
432 * without a wrapper.
434 if (unlikely(ev->wrapper.glue != wrapper)) {
435 tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
436 return;
439 if (wrapper != NULL) {
440 if (unlikely(wrapper->busy)) {
441 tevent_abort(ev, "wrapper already busy!");
442 return;
444 wrapper->busy = true;
447 if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
448 tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
449 return;
452 wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
453 .ev_ptr = ev,
454 .wrapper = wrapper,
456 wrapper_stack_idx++;
459 _PRIVATE_
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");
477 return;
479 wrapper_stack_idx--;
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!");
487 return;
489 if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
490 tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
491 return;
494 if (wrapper == NULL) {
495 return;
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)
511 bool ok;
513 if (ev->wrapper.glue == NULL) {
514 tevent_wrapper_push_use_internal(ev, NULL);
515 return true;
518 if (ev->wrapper.glue->main_ev == NULL) {
519 return false;
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,
526 location);
527 if (!ok) {
528 tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
529 return false;
532 return true;
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) {
541 return;
544 if (ev->wrapper.glue->main_ev == NULL) {
545 return;
548 ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
549 ev->wrapper.glue->private_state,
550 ev->wrapper.glue->main_ev,
551 location);
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) {
561 return false;
564 if (main_ev1 == main_ev2) {
565 return true;
568 return false;