s3-smbldap: move ldap_open_with_timeout out of smb_ldap.h to ads where it lives.
[Samba/gebeck_regimport.git] / lib / tevent / tevent.c
bloba87865b41ac5d3d9e502b23e930800cd710db261
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 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
214 const struct tevent_ops *ops)
216 struct tevent_context *ev;
217 int ret;
219 ev = talloc_zero(mem_ctx, struct tevent_context);
220 if (!ev) return NULL;
222 talloc_set_destructor(ev, tevent_common_context_destructor);
224 ev->ops = ops;
226 ret = ev->ops->context_init(ev);
227 if (ret != 0) {
228 talloc_free(ev);
229 return NULL;
232 return ev;
236 create a event_context structure. This must be the first events
237 call, and all subsequent calls pass this event_context as the first
238 element. Event handlers also receive this as their first argument.
240 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
241 const char *name)
243 struct tevent_ops_list *e;
245 tevent_backend_init();
247 if (name == NULL) {
248 name = tevent_default_backend;
250 if (name == NULL) {
251 name = "standard";
254 for (e=tevent_backends;e;e=e->next) {
255 if (strcmp(name, e->name) == 0) {
256 return tevent_context_init_ops(mem_ctx, e->ops);
259 return NULL;
264 create a event_context structure. This must be the first events
265 call, and all subsequent calls pass this event_context as the first
266 element. Event handlers also receive this as their first argument.
268 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
270 return tevent_context_init_byname(mem_ctx, NULL);
274 add a fd based event
275 return NULL on failure (memory allocation error)
277 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
278 TALLOC_CTX *mem_ctx,
279 int fd,
280 uint16_t flags,
281 tevent_fd_handler_t handler,
282 void *private_data,
283 const char *handler_name,
284 const char *location)
286 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
287 handler_name, location);
291 set a close function on the fd event
293 void tevent_fd_set_close_fn(struct tevent_fd *fde,
294 tevent_fd_close_fn_t close_fn)
296 if (!fde) return;
297 if (!fde->event_ctx) return;
298 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
301 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
302 struct tevent_fd *fde,
303 int fd,
304 void *private_data)
306 close(fd);
309 void tevent_fd_set_auto_close(struct tevent_fd *fde)
311 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
315 return the fd event flags
317 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
319 if (!fde) return 0;
320 if (!fde->event_ctx) return 0;
321 return fde->event_ctx->ops->get_fd_flags(fde);
325 set the fd event flags
327 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
329 if (!fde) return;
330 if (!fde->event_ctx) return;
331 fde->event_ctx->ops->set_fd_flags(fde, flags);
334 bool tevent_signal_support(struct tevent_context *ev)
336 if (ev->ops->add_signal) {
337 return true;
339 return false;
342 static void (*tevent_abort_fn)(const char *reason);
344 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
346 tevent_abort_fn = abort_fn;
349 static void tevent_abort(struct tevent_context *ev, const char *reason)
351 tevent_debug(ev, TEVENT_DEBUG_FATAL,
352 "abort: %s\n", reason);
354 if (!tevent_abort_fn) {
355 abort();
358 tevent_abort_fn(reason);
362 add a timer event
363 return NULL on failure
365 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
366 TALLOC_CTX *mem_ctx,
367 struct timeval next_event,
368 tevent_timer_handler_t handler,
369 void *private_data,
370 const char *handler_name,
371 const char *location)
373 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
374 handler_name, location);
378 allocate an immediate event
379 return NULL on failure (memory allocation error)
381 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
382 const char *location)
384 struct tevent_immediate *im;
386 im = talloc(mem_ctx, struct tevent_immediate);
387 if (im == NULL) return NULL;
389 im->prev = NULL;
390 im->next = NULL;
391 im->event_ctx = NULL;
392 im->create_location = location;
393 im->handler = NULL;
394 im->private_data = NULL;
395 im->handler_name = NULL;
396 im->schedule_location = NULL;
397 im->cancel_fn = NULL;
398 im->additional_data = NULL;
400 return im;
404 schedule an immediate event
405 return NULL on failure
407 void _tevent_schedule_immediate(struct tevent_immediate *im,
408 struct tevent_context *ev,
409 tevent_immediate_handler_t handler,
410 void *private_data,
411 const char *handler_name,
412 const char *location)
414 ev->ops->schedule_immediate(im, ev, handler, private_data,
415 handler_name, location);
419 add a signal event
421 sa_flags are flags to sigaction(2)
423 return NULL on failure
425 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
426 TALLOC_CTX *mem_ctx,
427 int signum,
428 int sa_flags,
429 tevent_signal_handler_t handler,
430 void *private_data,
431 const char *handler_name,
432 const char *location)
434 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
435 handler_name, location);
438 void tevent_loop_allow_nesting(struct tevent_context *ev)
440 ev->nesting.allowed = true;
443 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
444 tevent_nesting_hook hook,
445 void *private_data)
447 if (ev->nesting.hook_fn &&
448 (ev->nesting.hook_fn != hook ||
449 ev->nesting.hook_private != private_data)) {
450 /* the way the nesting hook code is currently written
451 we cannot support two different nesting hooks at the
452 same time. */
453 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
455 ev->nesting.hook_fn = hook;
456 ev->nesting.hook_private = private_data;
459 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
461 const char *reason;
463 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
464 location);
465 if (!reason) {
466 reason = "tevent_loop_once() nesting";
469 tevent_abort(ev, reason);
473 do a single event loop using the events defined in ev
475 int _tevent_loop_once(struct tevent_context *ev, const char *location)
477 int ret;
478 void *nesting_stack_ptr = NULL;
480 ev->nesting.level++;
482 if (ev->nesting.level > 1) {
483 if (!ev->nesting.allowed) {
484 tevent_abort_nesting(ev, location);
485 errno = ELOOP;
486 return -1;
489 if (ev->nesting.level > 0) {
490 if (ev->nesting.hook_fn) {
491 int ret2;
492 ret2 = ev->nesting.hook_fn(ev,
493 ev->nesting.hook_private,
494 ev->nesting.level,
495 true,
496 (void *)&nesting_stack_ptr,
497 location);
498 if (ret2 != 0) {
499 ret = ret2;
500 goto done;
505 ret = ev->ops->loop_once(ev, location);
507 if (ev->nesting.level > 0) {
508 if (ev->nesting.hook_fn) {
509 int ret2;
510 ret2 = ev->nesting.hook_fn(ev,
511 ev->nesting.hook_private,
512 ev->nesting.level,
513 false,
514 (void *)&nesting_stack_ptr,
515 location);
516 if (ret2 != 0) {
517 ret = ret2;
518 goto done;
523 done:
524 ev->nesting.level--;
525 return ret;
529 this is a performance optimization for the samba4 nested event loop problems
531 int _tevent_loop_until(struct tevent_context *ev,
532 bool (*finished)(void *private_data),
533 void *private_data,
534 const char *location)
536 int ret = 0;
537 void *nesting_stack_ptr = NULL;
539 ev->nesting.level++;
541 if (ev->nesting.level > 1) {
542 if (!ev->nesting.allowed) {
543 tevent_abort_nesting(ev, location);
544 errno = ELOOP;
545 return -1;
548 if (ev->nesting.level > 0) {
549 if (ev->nesting.hook_fn) {
550 int ret2;
551 ret2 = ev->nesting.hook_fn(ev,
552 ev->nesting.hook_private,
553 ev->nesting.level,
554 true,
555 (void *)&nesting_stack_ptr,
556 location);
557 if (ret2 != 0) {
558 ret = ret2;
559 goto done;
564 while (!finished(private_data)) {
565 ret = ev->ops->loop_once(ev, location);
566 if (ret != 0) {
567 break;
571 if (ev->nesting.level > 0) {
572 if (ev->nesting.hook_fn) {
573 int ret2;
574 ret2 = ev->nesting.hook_fn(ev,
575 ev->nesting.hook_private,
576 ev->nesting.level,
577 false,
578 (void *)&nesting_stack_ptr,
579 location);
580 if (ret2 != 0) {
581 ret = ret2;
582 goto done;
587 done:
588 ev->nesting.level--;
589 return ret;
593 return on failure or (with 0) if all fd events are removed
595 int tevent_common_loop_wait(struct tevent_context *ev,
596 const char *location)
599 * loop as long as we have events pending
601 while (ev->fd_events ||
602 ev->timer_events ||
603 ev->immediate_events ||
604 ev->signal_events) {
605 int ret;
606 ret = _tevent_loop_once(ev, location);
607 if (ret != 0) {
608 tevent_debug(ev, TEVENT_DEBUG_FATAL,
609 "_tevent_loop_once() failed: %d - %s\n",
610 ret, strerror(errno));
611 return ret;
615 tevent_debug(ev, TEVENT_DEBUG_WARNING,
616 "tevent_common_loop_wait() out of events\n");
617 return 0;
621 return on failure or (with 0) if all fd events are removed
623 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
625 return ev->ops->loop_wait(ev, location);
630 re-initialise a tevent context. This leaves you with the same
631 event context, but all events are wiped and the structure is
632 re-initialised. This is most useful after a fork()
634 zero is returned on success, non-zero on failure
636 int tevent_re_initialise(struct tevent_context *ev)
638 tevent_common_context_destructor(ev);
640 return ev->ops->context_init(ev);