tevent: make sure tevent_backend_init() only runs once
[Samba/gebeck_regimport.git] / lib / tevent / tevent.c
blob669b778eb5d721f3fd3444205ff05c71956e2f0c
1 /*
2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) Stefan Metzmacher 2009
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 PLEASE READ THIS BEFORE MODIFYING!
28 This module is a general abstraction for the main select loop and
29 event handling. Do not ever put any localised hacks in here, instead
30 register one of the possible event types and implement that event
31 somewhere else.
33 There are 2 types of event handling that are handled in this module:
35 1) a file descriptor becoming readable or writeable. This is mostly
36 used for network sockets, but can be used for any type of file
37 descriptor. You may only register one handler for each file
38 descriptor/io combination or you will get unpredictable results
39 (this means that you can have a handler for read events, and a
40 separate handler for write events, but not two handlers that are
41 both handling read events)
43 2) a timed event. You can register an event that happens at a
44 specific time. You can register as many of these as you
45 like. They are single shot - add a new timed event in the event
46 handler to get another event.
48 To setup a set of events you first need to create a event_context
49 structure using the function tevent_context_init(); This returns a
50 'struct tevent_context' that you use in all subsequent calls.
52 After that you can add/remove events that you are interested in
53 using tevent_add_*() and talloc_free()
55 Finally, you call tevent_loop_wait_once() to block waiting for one of the
56 events to occor or tevent_loop_wait() which will loop
57 forever.
60 #include "replace.h"
61 #include "system/filesys.h"
62 #define TEVENT_DEPRECATED 1
63 #include "tevent.h"
64 #include "tevent_internal.h"
65 #include "tevent_util.h"
67 struct tevent_ops_list {
68 struct tevent_ops_list *next, *prev;
69 const char *name;
70 const struct tevent_ops *ops;
73 /* list of registered event backends */
74 static struct tevent_ops_list *tevent_backends = NULL;
75 static char *tevent_default_backend = NULL;
78 register an events backend
80 bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
82 struct tevent_ops_list *e;
84 for (e = tevent_backends; e != NULL; e = e->next) {
85 if (0 == strcmp(e->name, name)) {
86 /* already registered, skip it */
87 return true;
91 e = talloc(NULL, struct tevent_ops_list);
92 if (e == NULL) return false;
94 e->name = name;
95 e->ops = ops;
96 DLIST_ADD(tevent_backends, e);
98 return true;
102 set the default event backend
104 void tevent_set_default_backend(const char *backend)
106 talloc_free(tevent_default_backend);
107 tevent_default_backend = talloc_strdup(NULL, backend);
111 initialise backends if not already done
113 static void tevent_backend_init(void)
115 static bool done;
117 if (done) {
118 return;
121 done = true;
123 tevent_select_init();
124 tevent_poll_init();
125 tevent_poll_mt_init();
126 #ifdef HAVE_EPOLL
127 tevent_epoll_init();
128 #endif
129 tevent_standard_init();
132 _PRIVATE_ const struct tevent_ops *tevent_find_ops_byname(const char *name)
134 struct tevent_ops_list *e;
136 tevent_backend_init();
138 if (name == NULL) {
139 name = tevent_default_backend;
141 if (name == NULL) {
142 name = "standard";
145 for (e = tevent_backends; e != NULL; e = e->next) {
146 if (0 == strcmp(e->name, name)) {
147 return e->ops;
151 return NULL;
155 list available backends
157 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
159 const char **list = NULL;
160 struct tevent_ops_list *e;
162 tevent_backend_init();
164 for (e=tevent_backends;e;e=e->next) {
165 list = ev_str_list_add(list, e->name);
168 talloc_steal(mem_ctx, list);
170 return list;
173 int tevent_common_context_destructor(struct tevent_context *ev)
175 struct tevent_fd *fd, *fn;
176 struct tevent_timer *te, *tn;
177 struct tevent_immediate *ie, *in;
178 struct tevent_signal *se, *sn;
180 if (ev->pipe_fde) {
181 talloc_free(ev->pipe_fde);
182 close(ev->pipe_fds[0]);
183 close(ev->pipe_fds[1]);
184 ev->pipe_fde = NULL;
187 for (fd = ev->fd_events; fd; fd = fn) {
188 fn = fd->next;
189 fd->event_ctx = NULL;
190 DLIST_REMOVE(ev->fd_events, fd);
193 for (te = ev->timer_events; te; te = tn) {
194 tn = te->next;
195 te->event_ctx = NULL;
196 DLIST_REMOVE(ev->timer_events, te);
199 for (ie = ev->immediate_events; ie; ie = in) {
200 in = ie->next;
201 ie->event_ctx = NULL;
202 ie->cancel_fn = NULL;
203 DLIST_REMOVE(ev->immediate_events, ie);
206 for (se = ev->signal_events; se; se = sn) {
207 sn = se->next;
208 se->event_ctx = NULL;
209 DLIST_REMOVE(ev->signal_events, se);
211 * This is important, Otherwise signals
212 * are handled twice in child. eg, SIGHUP.
213 * one added in parent, and another one in
214 * the child. -- BoYang
216 tevent_cleanup_pending_signal_handlers(se);
219 /* removing nesting hook or we get an abort when nesting is
220 * not allowed. -- SSS
221 * Note that we need to leave the allowed flag at its current
222 * value, otherwise the use in tevent_re_initialise() will
223 * leave the event context with allowed forced to false, which
224 * will break users that expect nesting to be allowed
226 ev->nesting.level = 0;
227 ev->nesting.hook_fn = NULL;
228 ev->nesting.hook_private = NULL;
230 return 0;
234 create a event_context structure for a specific implemementation.
235 This must be the first events call, and all subsequent calls pass
236 this event_context as the first element. Event handlers also
237 receive this as their first argument.
239 This function is for allowing third-party-applications to hook in gluecode
240 to their own event loop code, so that they can make async usage of our client libs
242 NOTE: use tevent_context_init() inside of samba!
244 struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
245 const struct tevent_ops *ops,
246 void *additional_data)
248 struct tevent_context *ev;
249 int ret;
251 ev = talloc_zero(mem_ctx, struct tevent_context);
252 if (!ev) return NULL;
254 talloc_set_destructor(ev, tevent_common_context_destructor);
256 ev->ops = ops;
257 ev->additional_data = additional_data;
259 ret = ev->ops->context_init(ev);
260 if (ret != 0) {
261 talloc_free(ev);
262 return NULL;
265 return ev;
269 create a event_context structure. This must be the first events
270 call, and all subsequent calls pass this event_context as the first
271 element. Event handlers also receive this as their first argument.
273 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
274 const char *name)
276 struct tevent_ops_list *e;
278 tevent_backend_init();
280 if (name == NULL) {
281 name = tevent_default_backend;
283 if (name == NULL) {
284 name = "standard";
287 for (e=tevent_backends;e;e=e->next) {
288 if (strcmp(name, e->name) == 0) {
289 return tevent_context_init_ops(mem_ctx, e->ops, NULL);
292 return NULL;
297 create a event_context structure. This must be the first events
298 call, and all subsequent calls pass this event_context as the first
299 element. Event handlers also receive this as their first argument.
301 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
303 return tevent_context_init_byname(mem_ctx, NULL);
307 add a fd based event
308 return NULL on failure (memory allocation error)
310 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
311 TALLOC_CTX *mem_ctx,
312 int fd,
313 uint16_t flags,
314 tevent_fd_handler_t handler,
315 void *private_data,
316 const char *handler_name,
317 const char *location)
319 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
320 handler_name, location);
324 set a close function on the fd event
326 void tevent_fd_set_close_fn(struct tevent_fd *fde,
327 tevent_fd_close_fn_t close_fn)
329 if (!fde) return;
330 if (!fde->event_ctx) return;
331 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
334 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
335 struct tevent_fd *fde,
336 int fd,
337 void *private_data)
339 close(fd);
342 void tevent_fd_set_auto_close(struct tevent_fd *fde)
344 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
348 return the fd event flags
350 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
352 if (!fde) return 0;
353 if (!fde->event_ctx) return 0;
354 return fde->event_ctx->ops->get_fd_flags(fde);
358 set the fd event flags
360 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
362 if (!fde) return;
363 if (!fde->event_ctx) return;
364 fde->event_ctx->ops->set_fd_flags(fde, flags);
367 bool tevent_signal_support(struct tevent_context *ev)
369 if (ev->ops->add_signal) {
370 return true;
372 return false;
375 static void (*tevent_abort_fn)(const char *reason);
377 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
379 tevent_abort_fn = abort_fn;
382 static void tevent_abort(struct tevent_context *ev, const char *reason)
384 tevent_debug(ev, TEVENT_DEBUG_FATAL,
385 "abort: %s\n", reason);
387 if (!tevent_abort_fn) {
388 abort();
391 tevent_abort_fn(reason);
395 add a timer event
396 return NULL on failure
398 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
399 TALLOC_CTX *mem_ctx,
400 struct timeval next_event,
401 tevent_timer_handler_t handler,
402 void *private_data,
403 const char *handler_name,
404 const char *location)
406 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
407 handler_name, location);
411 allocate an immediate event
412 return NULL on failure (memory allocation error)
414 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
415 const char *location)
417 struct tevent_immediate *im;
419 im = talloc(mem_ctx, struct tevent_immediate);
420 if (im == NULL) return NULL;
422 im->prev = NULL;
423 im->next = NULL;
424 im->event_ctx = NULL;
425 im->create_location = location;
426 im->handler = NULL;
427 im->private_data = NULL;
428 im->handler_name = NULL;
429 im->schedule_location = NULL;
430 im->cancel_fn = NULL;
431 im->additional_data = NULL;
433 return im;
437 schedule an immediate event
439 void _tevent_schedule_immediate(struct tevent_immediate *im,
440 struct tevent_context *ev,
441 tevent_immediate_handler_t handler,
442 void *private_data,
443 const char *handler_name,
444 const char *location)
446 ev->ops->schedule_immediate(im, ev, handler, private_data,
447 handler_name, location);
451 add a signal event
453 sa_flags are flags to sigaction(2)
455 return NULL on failure
457 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
458 TALLOC_CTX *mem_ctx,
459 int signum,
460 int sa_flags,
461 tevent_signal_handler_t handler,
462 void *private_data,
463 const char *handler_name,
464 const char *location)
466 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
467 handler_name, location);
470 void tevent_loop_allow_nesting(struct tevent_context *ev)
472 ev->nesting.allowed = true;
475 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
476 tevent_nesting_hook hook,
477 void *private_data)
479 if (ev->nesting.hook_fn &&
480 (ev->nesting.hook_fn != hook ||
481 ev->nesting.hook_private != private_data)) {
482 /* the way the nesting hook code is currently written
483 we cannot support two different nesting hooks at the
484 same time. */
485 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
487 ev->nesting.hook_fn = hook;
488 ev->nesting.hook_private = private_data;
491 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
493 const char *reason;
495 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
496 location);
497 if (!reason) {
498 reason = "tevent_loop_once() nesting";
501 tevent_abort(ev, reason);
505 do a single event loop using the events defined in ev
507 int _tevent_loop_once(struct tevent_context *ev, const char *location)
509 int ret;
510 void *nesting_stack_ptr = NULL;
512 ev->nesting.level++;
514 if (ev->nesting.level > 1) {
515 if (!ev->nesting.allowed) {
516 tevent_abort_nesting(ev, location);
517 errno = ELOOP;
518 return -1;
521 if (ev->nesting.level > 0) {
522 if (ev->nesting.hook_fn) {
523 int ret2;
524 ret2 = ev->nesting.hook_fn(ev,
525 ev->nesting.hook_private,
526 ev->nesting.level,
527 true,
528 (void *)&nesting_stack_ptr,
529 location);
530 if (ret2 != 0) {
531 ret = ret2;
532 goto done;
537 ret = ev->ops->loop_once(ev, location);
539 if (ev->nesting.level > 0) {
540 if (ev->nesting.hook_fn) {
541 int ret2;
542 ret2 = ev->nesting.hook_fn(ev,
543 ev->nesting.hook_private,
544 ev->nesting.level,
545 false,
546 (void *)&nesting_stack_ptr,
547 location);
548 if (ret2 != 0) {
549 ret = ret2;
550 goto done;
555 done:
556 ev->nesting.level--;
557 return ret;
561 this is a performance optimization for the samba4 nested event loop problems
563 int _tevent_loop_until(struct tevent_context *ev,
564 bool (*finished)(void *private_data),
565 void *private_data,
566 const char *location)
568 int ret = 0;
569 void *nesting_stack_ptr = NULL;
571 ev->nesting.level++;
573 if (ev->nesting.level > 1) {
574 if (!ev->nesting.allowed) {
575 tevent_abort_nesting(ev, location);
576 errno = ELOOP;
577 return -1;
580 if (ev->nesting.level > 0) {
581 if (ev->nesting.hook_fn) {
582 int ret2;
583 ret2 = ev->nesting.hook_fn(ev,
584 ev->nesting.hook_private,
585 ev->nesting.level,
586 true,
587 (void *)&nesting_stack_ptr,
588 location);
589 if (ret2 != 0) {
590 ret = ret2;
591 goto done;
596 while (!finished(private_data)) {
597 ret = ev->ops->loop_once(ev, location);
598 if (ret != 0) {
599 break;
603 if (ev->nesting.level > 0) {
604 if (ev->nesting.hook_fn) {
605 int ret2;
606 ret2 = ev->nesting.hook_fn(ev,
607 ev->nesting.hook_private,
608 ev->nesting.level,
609 false,
610 (void *)&nesting_stack_ptr,
611 location);
612 if (ret2 != 0) {
613 ret = ret2;
614 goto done;
619 done:
620 ev->nesting.level--;
621 return ret;
625 return on failure or (with 0) if all fd events are removed
627 int tevent_common_loop_wait(struct tevent_context *ev,
628 const char *location)
631 * loop as long as we have events pending
633 while (ev->fd_events ||
634 ev->timer_events ||
635 ev->immediate_events ||
636 ev->signal_events) {
637 int ret;
638 ret = _tevent_loop_once(ev, location);
639 if (ret != 0) {
640 tevent_debug(ev, TEVENT_DEBUG_FATAL,
641 "_tevent_loop_once() failed: %d - %s\n",
642 ret, strerror(errno));
643 return ret;
647 tevent_debug(ev, TEVENT_DEBUG_WARNING,
648 "tevent_common_loop_wait() out of events\n");
649 return 0;
653 return on failure or (with 0) if all fd events are removed
655 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
657 return ev->ops->loop_wait(ev, location);
662 re-initialise a tevent context. This leaves you with the same
663 event context, but all events are wiped and the structure is
664 re-initialised. This is most useful after a fork()
666 zero is returned on success, non-zero on failure
668 int tevent_re_initialise(struct tevent_context *ev)
670 tevent_common_context_destructor(ev);
672 return ev->ops->context_init(ev);