lib/util Make UTIL_LDB conditional on an s4 build
[Samba.git] / lib / tevent / tevent.c
blob4849bc162f44b50fa2a26d0fe86fa75da8796f32
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_standard_init();
117 #ifdef HAVE_EPOLL
118 tevent_epoll_init();
119 #endif
123 list available backends
125 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
127 const char **list = NULL;
128 struct tevent_ops_list *e;
130 tevent_backend_init();
132 for (e=tevent_backends;e;e=e->next) {
133 list = ev_str_list_add(list, e->name);
136 talloc_steal(mem_ctx, list);
138 return list;
141 int tevent_common_context_destructor(struct tevent_context *ev)
143 struct tevent_fd *fd, *fn;
144 struct tevent_timer *te, *tn;
145 struct tevent_immediate *ie, *in;
146 struct tevent_signal *se, *sn;
148 if (ev->pipe_fde) {
149 talloc_free(ev->pipe_fde);
150 close(ev->pipe_fds[0]);
151 close(ev->pipe_fds[1]);
152 ev->pipe_fde = NULL;
155 for (fd = ev->fd_events; fd; fd = fn) {
156 fn = fd->next;
157 fd->event_ctx = NULL;
158 DLIST_REMOVE(ev->fd_events, fd);
161 for (te = ev->timer_events; te; te = tn) {
162 tn = te->next;
163 te->event_ctx = NULL;
164 DLIST_REMOVE(ev->timer_events, te);
167 for (ie = ev->immediate_events; ie; ie = in) {
168 in = ie->next;
169 ie->event_ctx = NULL;
170 ie->cancel_fn = NULL;
171 DLIST_REMOVE(ev->immediate_events, ie);
174 for (se = ev->signal_events; se; se = sn) {
175 sn = se->next;
176 se->event_ctx = NULL;
177 DLIST_REMOVE(ev->signal_events, se);
179 * This is important, Otherwise signals
180 * are handled twice in child. eg, SIGHUP.
181 * one added in parent, and another one in
182 * the child. -- BoYang
184 tevent_cleanup_pending_signal_handlers(se);
187 return 0;
191 create a event_context structure for a specific implemementation.
192 This must be the first events call, and all subsequent calls pass
193 this event_context as the first element. Event handlers also
194 receive this as their first argument.
196 This function is for allowing third-party-applications to hook in gluecode
197 to their own event loop code, so that they can make async usage of our client libs
199 NOTE: use tevent_context_init() inside of samba!
201 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
202 const struct tevent_ops *ops)
204 struct tevent_context *ev;
205 int ret;
207 ev = talloc_zero(mem_ctx, struct tevent_context);
208 if (!ev) return NULL;
210 talloc_set_destructor(ev, tevent_common_context_destructor);
212 ev->ops = ops;
214 ret = ev->ops->context_init(ev);
215 if (ret != 0) {
216 talloc_free(ev);
217 return NULL;
220 return ev;
224 create a event_context structure. This must be the first events
225 call, and all subsequent calls pass this event_context as the first
226 element. Event handlers also receive this as their first argument.
228 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
229 const char *name)
231 struct tevent_ops_list *e;
233 tevent_backend_init();
235 if (name == NULL) {
236 name = tevent_default_backend;
238 if (name == NULL) {
239 name = "standard";
242 for (e=tevent_backends;e;e=e->next) {
243 if (strcmp(name, e->name) == 0) {
244 return tevent_context_init_ops(mem_ctx, e->ops);
247 return NULL;
252 create a event_context structure. This must be the first events
253 call, and all subsequent calls pass this event_context as the first
254 element. Event handlers also receive this as their first argument.
256 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
258 return tevent_context_init_byname(mem_ctx, NULL);
262 add a fd based event
263 return NULL on failure (memory allocation error)
265 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
266 TALLOC_CTX *mem_ctx,
267 int fd,
268 uint16_t flags,
269 tevent_fd_handler_t handler,
270 void *private_data,
271 const char *handler_name,
272 const char *location)
274 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
275 handler_name, location);
279 set a close function on the fd event
281 void tevent_fd_set_close_fn(struct tevent_fd *fde,
282 tevent_fd_close_fn_t close_fn)
284 if (!fde) return;
285 if (!fde->event_ctx) return;
286 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
289 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
290 struct tevent_fd *fde,
291 int fd,
292 void *private_data)
294 close(fd);
297 void tevent_fd_set_auto_close(struct tevent_fd *fde)
299 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
303 return the fd event flags
305 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
307 if (!fde) return 0;
308 if (!fde->event_ctx) return 0;
309 return fde->event_ctx->ops->get_fd_flags(fde);
313 set the fd event flags
315 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
317 if (!fde) return;
318 if (!fde->event_ctx) return;
319 fde->event_ctx->ops->set_fd_flags(fde, flags);
322 bool tevent_signal_support(struct tevent_context *ev)
324 if (ev->ops->add_signal) {
325 return true;
327 return false;
330 static void (*tevent_abort_fn)(const char *reason);
332 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
334 tevent_abort_fn = abort_fn;
337 static void tevent_abort(struct tevent_context *ev, const char *reason)
339 tevent_debug(ev, TEVENT_DEBUG_FATAL,
340 "abort: %s\n", reason);
342 if (!tevent_abort_fn) {
343 abort();
346 tevent_abort_fn(reason);
350 add a timer event
351 return NULL on failure
353 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
354 TALLOC_CTX *mem_ctx,
355 struct timeval next_event,
356 tevent_timer_handler_t handler,
357 void *private_data,
358 const char *handler_name,
359 const char *location)
361 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
362 handler_name, location);
366 allocate an immediate event
367 return NULL on failure (memory allocation error)
369 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
370 const char *location)
372 struct tevent_immediate *im;
374 im = talloc(mem_ctx, struct tevent_immediate);
375 if (im == NULL) return NULL;
377 im->prev = NULL;
378 im->next = NULL;
379 im->event_ctx = NULL;
380 im->create_location = location;
381 im->handler = NULL;
382 im->private_data = NULL;
383 im->handler_name = NULL;
384 im->schedule_location = NULL;
385 im->cancel_fn = NULL;
386 im->additional_data = NULL;
388 return im;
392 schedule an immediate event
393 return NULL on failure
395 void _tevent_schedule_immediate(struct tevent_immediate *im,
396 struct tevent_context *ev,
397 tevent_immediate_handler_t handler,
398 void *private_data,
399 const char *handler_name,
400 const char *location)
402 ev->ops->schedule_immediate(im, ev, handler, private_data,
403 handler_name, location);
407 add a signal event
409 sa_flags are flags to sigaction(2)
411 return NULL on failure
413 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
414 TALLOC_CTX *mem_ctx,
415 int signum,
416 int sa_flags,
417 tevent_signal_handler_t handler,
418 void *private_data,
419 const char *handler_name,
420 const char *location)
422 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
423 handler_name, location);
426 void tevent_loop_allow_nesting(struct tevent_context *ev)
428 ev->nesting.allowed = true;
431 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
432 tevent_nesting_hook hook,
433 void *private_data)
435 if (ev->nesting.hook_fn &&
436 (ev->nesting.hook_fn != hook ||
437 ev->nesting.hook_private != private_data)) {
438 /* the way the nesting hook code is currently written
439 we cannot support two different nesting hooks at the
440 same time. */
441 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
443 ev->nesting.hook_fn = hook;
444 ev->nesting.hook_private = private_data;
447 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
449 const char *reason;
451 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
452 location);
453 if (!reason) {
454 reason = "tevent_loop_once() nesting";
457 tevent_abort(ev, reason);
461 do a single event loop using the events defined in ev
463 int _tevent_loop_once(struct tevent_context *ev, const char *location)
465 int ret;
466 void *nesting_stack_ptr = NULL;
468 ev->nesting.level++;
470 if (ev->nesting.level > 1) {
471 if (!ev->nesting.allowed) {
472 tevent_abort_nesting(ev, location);
473 errno = ELOOP;
474 return -1;
477 if (ev->nesting.level > 0) {
478 if (ev->nesting.hook_fn) {
479 int ret2;
480 ret2 = ev->nesting.hook_fn(ev,
481 ev->nesting.hook_private,
482 ev->nesting.level,
483 true,
484 (void *)&nesting_stack_ptr,
485 location);
486 if (ret2 != 0) {
487 ret = ret2;
488 goto done;
493 ret = ev->ops->loop_once(ev, location);
495 if (ev->nesting.level > 0) {
496 if (ev->nesting.hook_fn) {
497 int ret2;
498 ret2 = ev->nesting.hook_fn(ev,
499 ev->nesting.hook_private,
500 ev->nesting.level,
501 false,
502 (void *)&nesting_stack_ptr,
503 location);
504 if (ret2 != 0) {
505 ret = ret2;
506 goto done;
511 done:
512 ev->nesting.level--;
513 return ret;
517 this is a performance optimization for the samba4 nested event loop problems
519 int _tevent_loop_until(struct tevent_context *ev,
520 bool (*finished)(void *private_data),
521 void *private_data,
522 const char *location)
524 int ret = 0;
525 void *nesting_stack_ptr = NULL;
527 ev->nesting.level++;
529 if (ev->nesting.level > 1) {
530 if (!ev->nesting.allowed) {
531 tevent_abort_nesting(ev, location);
532 errno = ELOOP;
533 return -1;
536 if (ev->nesting.level > 0) {
537 if (ev->nesting.hook_fn) {
538 int ret2;
539 ret2 = ev->nesting.hook_fn(ev,
540 ev->nesting.hook_private,
541 ev->nesting.level,
542 true,
543 (void *)&nesting_stack_ptr,
544 location);
545 if (ret2 != 0) {
546 ret = ret2;
547 goto done;
552 while (!finished(private_data)) {
553 ret = ev->ops->loop_once(ev, location);
554 if (ret != 0) {
555 break;
559 if (ev->nesting.level > 0) {
560 if (ev->nesting.hook_fn) {
561 int ret2;
562 ret2 = ev->nesting.hook_fn(ev,
563 ev->nesting.hook_private,
564 ev->nesting.level,
565 false,
566 (void *)&nesting_stack_ptr,
567 location);
568 if (ret2 != 0) {
569 ret = ret2;
570 goto done;
575 done:
576 ev->nesting.level--;
577 return ret;
581 return on failure or (with 0) if all fd events are removed
583 int tevent_common_loop_wait(struct tevent_context *ev,
584 const char *location)
587 * loop as long as we have events pending
589 while (ev->fd_events ||
590 ev->timer_events ||
591 ev->immediate_events ||
592 ev->signal_events) {
593 int ret;
594 ret = _tevent_loop_once(ev, location);
595 if (ret != 0) {
596 tevent_debug(ev, TEVENT_DEBUG_FATAL,
597 "_tevent_loop_once() failed: %d - %s\n",
598 ret, strerror(errno));
599 return ret;
603 tevent_debug(ev, TEVENT_DEBUG_WARNING,
604 "tevent_common_loop_wait() out of events\n");
605 return 0;
609 return on failure or (with 0) if all fd events are removed
611 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
613 return ev->ops->loop_wait(ev, location);
618 re-initialise a tevent context. This leaves you with the same
619 event context, but all events are wiped and the structure is
620 re-initialised. This is most useful after a fork()
622 zero is returned on success, non-zero on failure
624 int tevent_re_initialise(struct tevent_context *ev)
626 tevent_common_context_destructor(ev);
628 return ev->ops->context_init(ev);