VERSION: Disable git snapshots for the 4.0.24 release.
[Samba.git] / lib / tevent / tevent.c
blobbe0afd453bb4d5e9018cafbb6c413c3f6dbf1578
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 ev->last_zero_timer = NULL;
194 for (te = ev->timer_events; te; te = tn) {
195 tn = te->next;
196 te->event_ctx = NULL;
197 DLIST_REMOVE(ev->timer_events, te);
200 for (ie = ev->immediate_events; ie; ie = in) {
201 in = ie->next;
202 ie->event_ctx = NULL;
203 ie->cancel_fn = NULL;
204 DLIST_REMOVE(ev->immediate_events, ie);
207 for (se = ev->signal_events; se; se = sn) {
208 sn = se->next;
209 se->event_ctx = NULL;
210 DLIST_REMOVE(ev->signal_events, se);
212 * This is important, Otherwise signals
213 * are handled twice in child. eg, SIGHUP.
214 * one added in parent, and another one in
215 * the child. -- BoYang
217 tevent_cleanup_pending_signal_handlers(se);
220 /* removing nesting hook or we get an abort when nesting is
221 * not allowed. -- SSS
222 * Note that we need to leave the allowed flag at its current
223 * value, otherwise the use in tevent_re_initialise() will
224 * leave the event context with allowed forced to false, which
225 * will break users that expect nesting to be allowed
227 ev->nesting.level = 0;
228 ev->nesting.hook_fn = NULL;
229 ev->nesting.hook_private = NULL;
231 return 0;
235 create a event_context structure for a specific implemementation.
236 This must be the first events call, and all subsequent calls pass
237 this event_context as the first element. Event handlers also
238 receive this as their first argument.
240 This function is for allowing third-party-applications to hook in gluecode
241 to their own event loop code, so that they can make async usage of our client libs
243 NOTE: use tevent_context_init() inside of samba!
245 struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
246 const struct tevent_ops *ops,
247 void *additional_data)
249 struct tevent_context *ev;
250 int ret;
252 ev = talloc_zero(mem_ctx, struct tevent_context);
253 if (!ev) return NULL;
255 talloc_set_destructor(ev, tevent_common_context_destructor);
257 ev->ops = ops;
258 ev->additional_data = additional_data;
260 ret = ev->ops->context_init(ev);
261 if (ret != 0) {
262 talloc_free(ev);
263 return NULL;
266 return ev;
270 create a event_context structure. This must be the first events
271 call, and all subsequent calls pass this event_context as the first
272 element. Event handlers also receive this as their first argument.
274 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
275 const char *name)
277 const struct tevent_ops *ops;
279 ops = tevent_find_ops_byname(name);
280 if (ops == NULL) {
281 return NULL;
284 return tevent_context_init_ops(mem_ctx, ops, NULL);
289 create a event_context structure. This must be the first events
290 call, and all subsequent calls pass this event_context as the first
291 element. Event handlers also receive this as their first argument.
293 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
295 return tevent_context_init_byname(mem_ctx, NULL);
299 add a fd based event
300 return NULL on failure (memory allocation error)
302 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
303 TALLOC_CTX *mem_ctx,
304 int fd,
305 uint16_t flags,
306 tevent_fd_handler_t handler,
307 void *private_data,
308 const char *handler_name,
309 const char *location)
311 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
312 handler_name, location);
316 set a close function on the fd event
318 void tevent_fd_set_close_fn(struct tevent_fd *fde,
319 tevent_fd_close_fn_t close_fn)
321 if (!fde) return;
322 if (!fde->event_ctx) return;
323 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
326 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
327 struct tevent_fd *fde,
328 int fd,
329 void *private_data)
331 close(fd);
334 void tevent_fd_set_auto_close(struct tevent_fd *fde)
336 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
340 return the fd event flags
342 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
344 if (!fde) return 0;
345 if (!fde->event_ctx) return 0;
346 return fde->event_ctx->ops->get_fd_flags(fde);
350 set the fd event flags
352 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
354 if (!fde) return;
355 if (!fde->event_ctx) return;
356 fde->event_ctx->ops->set_fd_flags(fde, flags);
359 bool tevent_signal_support(struct tevent_context *ev)
361 if (ev->ops->add_signal) {
362 return true;
364 return false;
367 static void (*tevent_abort_fn)(const char *reason);
369 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
371 tevent_abort_fn = abort_fn;
374 static void tevent_abort(struct tevent_context *ev, const char *reason)
376 tevent_debug(ev, TEVENT_DEBUG_FATAL,
377 "abort: %s\n", reason);
379 if (!tevent_abort_fn) {
380 abort();
383 tevent_abort_fn(reason);
387 add a timer event
388 return NULL on failure
390 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
391 TALLOC_CTX *mem_ctx,
392 struct timeval next_event,
393 tevent_timer_handler_t handler,
394 void *private_data,
395 const char *handler_name,
396 const char *location)
398 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
399 handler_name, location);
403 allocate an immediate event
404 return NULL on failure (memory allocation error)
406 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
407 const char *location)
409 struct tevent_immediate *im;
411 im = talloc(mem_ctx, struct tevent_immediate);
412 if (im == NULL) return NULL;
414 im->prev = NULL;
415 im->next = NULL;
416 im->event_ctx = NULL;
417 im->create_location = location;
418 im->handler = NULL;
419 im->private_data = NULL;
420 im->handler_name = NULL;
421 im->schedule_location = NULL;
422 im->cancel_fn = NULL;
423 im->additional_data = NULL;
425 return im;
429 schedule an immediate event
431 void _tevent_schedule_immediate(struct tevent_immediate *im,
432 struct tevent_context *ev,
433 tevent_immediate_handler_t handler,
434 void *private_data,
435 const char *handler_name,
436 const char *location)
438 ev->ops->schedule_immediate(im, ev, handler, private_data,
439 handler_name, location);
443 add a signal event
445 sa_flags are flags to sigaction(2)
447 return NULL on failure
449 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
450 TALLOC_CTX *mem_ctx,
451 int signum,
452 int sa_flags,
453 tevent_signal_handler_t handler,
454 void *private_data,
455 const char *handler_name,
456 const char *location)
458 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
459 handler_name, location);
462 void tevent_loop_allow_nesting(struct tevent_context *ev)
464 ev->nesting.allowed = true;
467 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
468 tevent_nesting_hook hook,
469 void *private_data)
471 if (ev->nesting.hook_fn &&
472 (ev->nesting.hook_fn != hook ||
473 ev->nesting.hook_private != private_data)) {
474 /* the way the nesting hook code is currently written
475 we cannot support two different nesting hooks at the
476 same time. */
477 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
479 ev->nesting.hook_fn = hook;
480 ev->nesting.hook_private = private_data;
483 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
485 const char *reason;
487 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
488 location);
489 if (!reason) {
490 reason = "tevent_loop_once() nesting";
493 tevent_abort(ev, reason);
497 do a single event loop using the events defined in ev
499 int _tevent_loop_once(struct tevent_context *ev, const char *location)
501 int ret;
502 void *nesting_stack_ptr = NULL;
504 ev->nesting.level++;
506 if (ev->nesting.level > 1) {
507 if (!ev->nesting.allowed) {
508 tevent_abort_nesting(ev, location);
509 errno = ELOOP;
510 return -1;
513 if (ev->nesting.level > 0) {
514 if (ev->nesting.hook_fn) {
515 int ret2;
516 ret2 = ev->nesting.hook_fn(ev,
517 ev->nesting.hook_private,
518 ev->nesting.level,
519 true,
520 (void *)&nesting_stack_ptr,
521 location);
522 if (ret2 != 0) {
523 ret = ret2;
524 goto done;
529 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
530 ret = ev->ops->loop_once(ev, location);
531 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
533 if (ev->nesting.level > 0) {
534 if (ev->nesting.hook_fn) {
535 int ret2;
536 ret2 = ev->nesting.hook_fn(ev,
537 ev->nesting.hook_private,
538 ev->nesting.level,
539 false,
540 (void *)&nesting_stack_ptr,
541 location);
542 if (ret2 != 0) {
543 ret = ret2;
544 goto done;
549 done:
550 ev->nesting.level--;
551 return ret;
555 this is a performance optimization for the samba4 nested event loop problems
557 int _tevent_loop_until(struct tevent_context *ev,
558 bool (*finished)(void *private_data),
559 void *private_data,
560 const char *location)
562 int ret = 0;
563 void *nesting_stack_ptr = NULL;
565 ev->nesting.level++;
567 if (ev->nesting.level > 1) {
568 if (!ev->nesting.allowed) {
569 tevent_abort_nesting(ev, location);
570 errno = ELOOP;
571 return -1;
574 if (ev->nesting.level > 0) {
575 if (ev->nesting.hook_fn) {
576 int ret2;
577 ret2 = ev->nesting.hook_fn(ev,
578 ev->nesting.hook_private,
579 ev->nesting.level,
580 true,
581 (void *)&nesting_stack_ptr,
582 location);
583 if (ret2 != 0) {
584 ret = ret2;
585 goto done;
590 while (!finished(private_data)) {
591 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
592 ret = ev->ops->loop_once(ev, location);
593 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
594 if (ret != 0) {
595 break;
599 if (ev->nesting.level > 0) {
600 if (ev->nesting.hook_fn) {
601 int ret2;
602 ret2 = ev->nesting.hook_fn(ev,
603 ev->nesting.hook_private,
604 ev->nesting.level,
605 false,
606 (void *)&nesting_stack_ptr,
607 location);
608 if (ret2 != 0) {
609 ret = ret2;
610 goto done;
615 done:
616 ev->nesting.level--;
617 return ret;
621 return on failure or (with 0) if all fd events are removed
623 int tevent_common_loop_wait(struct tevent_context *ev,
624 const char *location)
627 * loop as long as we have events pending
629 while (ev->fd_events ||
630 ev->timer_events ||
631 ev->immediate_events ||
632 ev->signal_events) {
633 int ret;
634 ret = _tevent_loop_once(ev, location);
635 if (ret != 0) {
636 tevent_debug(ev, TEVENT_DEBUG_FATAL,
637 "_tevent_loop_once() failed: %d - %s\n",
638 ret, strerror(errno));
639 return ret;
643 tevent_debug(ev, TEVENT_DEBUG_WARNING,
644 "tevent_common_loop_wait() out of events\n");
645 return 0;
649 return on failure or (with 0) if all fd events are removed
651 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
653 return ev->ops->loop_wait(ev, location);
658 re-initialise a tevent context. This leaves you with the same
659 event context, but all events are wiped and the structure is
660 re-initialised. This is most useful after a fork()
662 zero is returned on success, non-zero on failure
664 int tevent_re_initialise(struct tevent_context *ev)
666 tevent_common_context_destructor(ev);
668 return ev->ops->context_init(ev);