tevent: expose tevent_context_init_ops
[Samba/gebeck_regimport.git] / lib / tevent / tevent.c
blob61ffc7edaa5683e03f4d57c20eb6d5d58e077b30
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 tevent_select_init();
116 tevent_poll_init();
117 tevent_standard_init();
118 #ifdef HAVE_EPOLL
119 tevent_epoll_init();
120 #endif
124 list available backends
126 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
128 const char **list = NULL;
129 struct tevent_ops_list *e;
131 tevent_backend_init();
133 for (e=tevent_backends;e;e=e->next) {
134 list = ev_str_list_add(list, e->name);
137 talloc_steal(mem_ctx, list);
139 return list;
142 int tevent_common_context_destructor(struct tevent_context *ev)
144 struct tevent_fd *fd, *fn;
145 struct tevent_timer *te, *tn;
146 struct tevent_immediate *ie, *in;
147 struct tevent_signal *se, *sn;
149 if (ev->pipe_fde) {
150 talloc_free(ev->pipe_fde);
151 close(ev->pipe_fds[0]);
152 close(ev->pipe_fds[1]);
153 ev->pipe_fde = NULL;
156 for (fd = ev->fd_events; fd; fd = fn) {
157 fn = fd->next;
158 fd->event_ctx = NULL;
159 DLIST_REMOVE(ev->fd_events, fd);
162 for (te = ev->timer_events; te; te = tn) {
163 tn = te->next;
164 te->event_ctx = NULL;
165 DLIST_REMOVE(ev->timer_events, te);
168 for (ie = ev->immediate_events; ie; ie = in) {
169 in = ie->next;
170 ie->event_ctx = NULL;
171 ie->cancel_fn = NULL;
172 DLIST_REMOVE(ev->immediate_events, ie);
175 for (se = ev->signal_events; se; se = sn) {
176 sn = se->next;
177 se->event_ctx = NULL;
178 DLIST_REMOVE(ev->signal_events, se);
180 * This is important, Otherwise signals
181 * are handled twice in child. eg, SIGHUP.
182 * one added in parent, and another one in
183 * the child. -- BoYang
185 tevent_cleanup_pending_signal_handlers(se);
188 /* removing nesting hook or we get an abort when nesting is
189 * not allowed. -- SSS
190 * Note that we need to leave the allowed flag at its current
191 * value, otherwise the use in tevent_re_initialise() will
192 * leave the event context with allowed forced to false, which
193 * will break users that expect nesting to be allowed
195 ev->nesting.level = 0;
196 ev->nesting.hook_fn = NULL;
197 ev->nesting.hook_private = NULL;
199 return 0;
203 create a event_context structure for a specific implemementation.
204 This must be the first events call, and all subsequent calls pass
205 this event_context as the first element. Event handlers also
206 receive this as their first argument.
208 This function is for allowing third-party-applications to hook in gluecode
209 to their own event loop code, so that they can make async usage of our client libs
211 NOTE: use tevent_context_init() inside of samba!
213 struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
214 const struct tevent_ops *ops,
215 void *additional_data)
217 struct tevent_context *ev;
218 int ret;
220 ev = talloc_zero(mem_ctx, struct tevent_context);
221 if (!ev) return NULL;
223 talloc_set_destructor(ev, tevent_common_context_destructor);
225 ev->ops = ops;
226 ev->additional_data = additional_data;
228 ret = ev->ops->context_init(ev);
229 if (ret != 0) {
230 talloc_free(ev);
231 return NULL;
234 return ev;
238 create a event_context structure. This must be the first events
239 call, and all subsequent calls pass this event_context as the first
240 element. Event handlers also receive this as their first argument.
242 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
243 const char *name)
245 struct tevent_ops_list *e;
247 tevent_backend_init();
249 if (name == NULL) {
250 name = tevent_default_backend;
252 if (name == NULL) {
253 name = "standard";
256 for (e=tevent_backends;e;e=e->next) {
257 if (strcmp(name, e->name) == 0) {
258 return tevent_context_init_ops(mem_ctx, e->ops, NULL);
261 return NULL;
266 create a event_context structure. This must be the first events
267 call, and all subsequent calls pass this event_context as the first
268 element. Event handlers also receive this as their first argument.
270 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
272 return tevent_context_init_byname(mem_ctx, NULL);
276 add a fd based event
277 return NULL on failure (memory allocation error)
279 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
280 TALLOC_CTX *mem_ctx,
281 int fd,
282 uint16_t flags,
283 tevent_fd_handler_t handler,
284 void *private_data,
285 const char *handler_name,
286 const char *location)
288 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
289 handler_name, location);
293 set a close function on the fd event
295 void tevent_fd_set_close_fn(struct tevent_fd *fde,
296 tevent_fd_close_fn_t close_fn)
298 if (!fde) return;
299 if (!fde->event_ctx) return;
300 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
303 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
304 struct tevent_fd *fde,
305 int fd,
306 void *private_data)
308 close(fd);
311 void tevent_fd_set_auto_close(struct tevent_fd *fde)
313 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
317 return the fd event flags
319 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
321 if (!fde) return 0;
322 if (!fde->event_ctx) return 0;
323 return fde->event_ctx->ops->get_fd_flags(fde);
327 set the fd event flags
329 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
331 if (!fde) return;
332 if (!fde->event_ctx) return;
333 fde->event_ctx->ops->set_fd_flags(fde, flags);
336 bool tevent_signal_support(struct tevent_context *ev)
338 if (ev->ops->add_signal) {
339 return true;
341 return false;
344 static void (*tevent_abort_fn)(const char *reason);
346 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
348 tevent_abort_fn = abort_fn;
351 static void tevent_abort(struct tevent_context *ev, const char *reason)
353 tevent_debug(ev, TEVENT_DEBUG_FATAL,
354 "abort: %s\n", reason);
356 if (!tevent_abort_fn) {
357 abort();
360 tevent_abort_fn(reason);
364 add a timer event
365 return NULL on failure
367 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
368 TALLOC_CTX *mem_ctx,
369 struct timeval next_event,
370 tevent_timer_handler_t handler,
371 void *private_data,
372 const char *handler_name,
373 const char *location)
375 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
376 handler_name, location);
380 allocate an immediate event
381 return NULL on failure (memory allocation error)
383 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
384 const char *location)
386 struct tevent_immediate *im;
388 im = talloc(mem_ctx, struct tevent_immediate);
389 if (im == NULL) return NULL;
391 im->prev = NULL;
392 im->next = NULL;
393 im->event_ctx = NULL;
394 im->create_location = location;
395 im->handler = NULL;
396 im->private_data = NULL;
397 im->handler_name = NULL;
398 im->schedule_location = NULL;
399 im->cancel_fn = NULL;
400 im->additional_data = NULL;
402 return im;
406 schedule an immediate event
408 void _tevent_schedule_immediate(struct tevent_immediate *im,
409 struct tevent_context *ev,
410 tevent_immediate_handler_t handler,
411 void *private_data,
412 const char *handler_name,
413 const char *location)
415 ev->ops->schedule_immediate(im, ev, handler, private_data,
416 handler_name, location);
420 add a signal event
422 sa_flags are flags to sigaction(2)
424 return NULL on failure
426 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
427 TALLOC_CTX *mem_ctx,
428 int signum,
429 int sa_flags,
430 tevent_signal_handler_t handler,
431 void *private_data,
432 const char *handler_name,
433 const char *location)
435 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
436 handler_name, location);
439 void tevent_loop_allow_nesting(struct tevent_context *ev)
441 ev->nesting.allowed = true;
444 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
445 tevent_nesting_hook hook,
446 void *private_data)
448 if (ev->nesting.hook_fn &&
449 (ev->nesting.hook_fn != hook ||
450 ev->nesting.hook_private != private_data)) {
451 /* the way the nesting hook code is currently written
452 we cannot support two different nesting hooks at the
453 same time. */
454 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
456 ev->nesting.hook_fn = hook;
457 ev->nesting.hook_private = private_data;
460 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
462 const char *reason;
464 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
465 location);
466 if (!reason) {
467 reason = "tevent_loop_once() nesting";
470 tevent_abort(ev, reason);
474 do a single event loop using the events defined in ev
476 int _tevent_loop_once(struct tevent_context *ev, const char *location)
478 int ret;
479 void *nesting_stack_ptr = NULL;
481 ev->nesting.level++;
483 if (ev->nesting.level > 1) {
484 if (!ev->nesting.allowed) {
485 tevent_abort_nesting(ev, location);
486 errno = ELOOP;
487 return -1;
490 if (ev->nesting.level > 0) {
491 if (ev->nesting.hook_fn) {
492 int ret2;
493 ret2 = ev->nesting.hook_fn(ev,
494 ev->nesting.hook_private,
495 ev->nesting.level,
496 true,
497 (void *)&nesting_stack_ptr,
498 location);
499 if (ret2 != 0) {
500 ret = ret2;
501 goto done;
506 ret = ev->ops->loop_once(ev, location);
508 if (ev->nesting.level > 0) {
509 if (ev->nesting.hook_fn) {
510 int ret2;
511 ret2 = ev->nesting.hook_fn(ev,
512 ev->nesting.hook_private,
513 ev->nesting.level,
514 false,
515 (void *)&nesting_stack_ptr,
516 location);
517 if (ret2 != 0) {
518 ret = ret2;
519 goto done;
524 done:
525 ev->nesting.level--;
526 return ret;
530 this is a performance optimization for the samba4 nested event loop problems
532 int _tevent_loop_until(struct tevent_context *ev,
533 bool (*finished)(void *private_data),
534 void *private_data,
535 const char *location)
537 int ret = 0;
538 void *nesting_stack_ptr = NULL;
540 ev->nesting.level++;
542 if (ev->nesting.level > 1) {
543 if (!ev->nesting.allowed) {
544 tevent_abort_nesting(ev, location);
545 errno = ELOOP;
546 return -1;
549 if (ev->nesting.level > 0) {
550 if (ev->nesting.hook_fn) {
551 int ret2;
552 ret2 = ev->nesting.hook_fn(ev,
553 ev->nesting.hook_private,
554 ev->nesting.level,
555 true,
556 (void *)&nesting_stack_ptr,
557 location);
558 if (ret2 != 0) {
559 ret = ret2;
560 goto done;
565 while (!finished(private_data)) {
566 ret = ev->ops->loop_once(ev, location);
567 if (ret != 0) {
568 break;
572 if (ev->nesting.level > 0) {
573 if (ev->nesting.hook_fn) {
574 int ret2;
575 ret2 = ev->nesting.hook_fn(ev,
576 ev->nesting.hook_private,
577 ev->nesting.level,
578 false,
579 (void *)&nesting_stack_ptr,
580 location);
581 if (ret2 != 0) {
582 ret = ret2;
583 goto done;
588 done:
589 ev->nesting.level--;
590 return ret;
594 return on failure or (with 0) if all fd events are removed
596 int tevent_common_loop_wait(struct tevent_context *ev,
597 const char *location)
600 * loop as long as we have events pending
602 while (ev->fd_events ||
603 ev->timer_events ||
604 ev->immediate_events ||
605 ev->signal_events) {
606 int ret;
607 ret = _tevent_loop_once(ev, location);
608 if (ret != 0) {
609 tevent_debug(ev, TEVENT_DEBUG_FATAL,
610 "_tevent_loop_once() failed: %d - %s\n",
611 ret, strerror(errno));
612 return ret;
616 tevent_debug(ev, TEVENT_DEBUG_WARNING,
617 "tevent_common_loop_wait() out of events\n");
618 return 0;
622 return on failure or (with 0) if all fd events are removed
624 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
626 return ev->ops->loop_wait(ev, location);
631 re-initialise a tevent context. This leaves you with the same
632 event context, but all events are wiped and the structure is
633 re-initialised. This is most useful after a fork()
635 zero is returned on success, non-zero on failure
637 int tevent_re_initialise(struct tevent_context *ev)
639 tevent_common_context_destructor(ev);
641 return ev->ops->context_init(ev);