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
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
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
61 #include "system/filesys.h"
62 #define TEVENT_DEPRECATED 1
64 #include "tevent_internal.h"
65 #include "tevent_util.h"
67 /* needed for the special ctdbd "track if time jumps unexpectedly */
70 struct tevent_ops_list {
71 struct tevent_ops_list *next, *prev;
73 const struct tevent_ops *ops;
76 /* list of registered event backends */
77 static struct tevent_ops_list *tevent_backends = NULL;
78 static char *tevent_default_backend = NULL;
81 register an events backend
83 bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
85 struct tevent_ops_list *e;
87 for (e = tevent_backends; e != NULL; e = e->next) {
88 if (0 == strcmp(e->name, name)) {
89 /* already registered, skip it */
94 e = talloc(talloc_autofree_context(), struct tevent_ops_list);
95 if (e == NULL) return false;
99 DLIST_ADD(tevent_backends, e);
105 set the default event backend
107 void tevent_set_default_backend(const char *backend)
109 talloc_free(tevent_default_backend);
110 tevent_default_backend = talloc_strdup(talloc_autofree_context(),
115 initialise backends if not already done
117 static void tevent_backend_init(void)
119 tevent_select_init();
120 tevent_standard_init();
127 list available backends
129 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
131 const char **list = NULL;
132 struct tevent_ops_list *e;
134 tevent_backend_init();
136 for (e=tevent_backends;e;e=e->next) {
137 list = ev_str_list_add(list, e->name);
140 talloc_steal(mem_ctx, list);
145 int tevent_common_context_destructor(struct tevent_context *ev)
147 struct tevent_fd *fd, *fn;
148 struct tevent_timer *te, *tn;
149 struct tevent_immediate *ie, *in;
150 struct tevent_signal *se, *sn;
153 talloc_free(ev->pipe_fde);
154 close(ev->pipe_fds[0]);
155 close(ev->pipe_fds[1]);
159 for (fd = ev->fd_events; fd; fd = fn) {
161 fd->event_ctx = NULL;
162 DLIST_REMOVE(ev->fd_events, fd);
165 for (te = ev->timer_events; te; te = tn) {
167 te->event_ctx = NULL;
168 DLIST_REMOVE(ev->timer_events, te);
171 for (ie = ev->immediate_events; ie; ie = in) {
173 ie->event_ctx = NULL;
174 ie->cancel_fn = NULL;
175 DLIST_REMOVE(ev->immediate_events, ie);
178 for (se = ev->signal_events; se; se = sn) {
180 se->event_ctx = NULL;
181 DLIST_REMOVE(ev->signal_events, se);
183 * This is important, Otherwise signals
184 * are handled twice in child. eg, SIGHUP.
185 * one added in parent, and another one in
186 * the child. -- BoYang
188 tevent_cleanup_pending_signal_handlers(se);
195 create a event_context structure for a specific implemementation.
196 This must be the first events call, and all subsequent calls pass
197 this event_context as the first element. Event handlers also
198 receive this as their first argument.
200 This function is for allowing third-party-applications to hook in gluecode
201 to their own event loop code, so that they can make async usage of our client libs
203 NOTE: use tevent_context_init() inside of samba!
205 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
206 const struct tevent_ops *ops)
208 struct tevent_context *ev;
211 ev = talloc_zero(mem_ctx, struct tevent_context);
212 if (!ev) return NULL;
214 talloc_set_destructor(ev, tevent_common_context_destructor);
218 ret = ev->ops->context_init(ev);
228 create a event_context structure. This must be the first events
229 call, and all subsequent calls pass this event_context as the first
230 element. Event handlers also receive this as their first argument.
232 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
235 struct tevent_ops_list *e;
237 tevent_backend_init();
240 name = tevent_default_backend;
246 for (e=tevent_backends;e;e=e->next) {
247 if (strcmp(name, e->name) == 0) {
248 return tevent_context_init_ops(mem_ctx, e->ops);
256 create a event_context structure. This must be the first events
257 call, and all subsequent calls pass this event_context as the first
258 element. Event handlers also receive this as their first argument.
260 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
262 return tevent_context_init_byname(mem_ctx, NULL);
267 return NULL on failure (memory allocation error)
269 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
273 tevent_fd_handler_t handler,
275 const char *handler_name,
276 const char *location)
278 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
279 handler_name, location);
283 set a close function on the fd event
285 void tevent_fd_set_close_fn(struct tevent_fd *fde,
286 tevent_fd_close_fn_t close_fn)
289 if (!fde->event_ctx) return;
290 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
293 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
294 struct tevent_fd *fde,
301 void tevent_fd_set_auto_close(struct tevent_fd *fde)
303 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
307 return the fd event flags
309 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
312 if (!fde->event_ctx) return 0;
313 return fde->event_ctx->ops->get_fd_flags(fde);
317 set the fd event flags
319 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
322 if (!fde->event_ctx) return;
323 fde->event_ctx->ops->set_fd_flags(fde, flags);
326 bool tevent_signal_support(struct tevent_context *ev)
328 if (ev->ops->add_signal) {
334 static void (*tevent_abort_fn)(const char *reason);
336 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
338 tevent_abort_fn = abort_fn;
341 static void tevent_abort(struct tevent_context *ev, const char *reason)
343 tevent_debug(ev, TEVENT_DEBUG_FATAL,
344 "abort: %s\n", reason);
346 if (!tevent_abort_fn) {
350 tevent_abort_fn(reason);
355 return NULL on failure
357 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
359 struct timeval next_event,
360 tevent_timer_handler_t handler,
362 const char *handler_name,
363 const char *location)
365 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
366 handler_name, location);
370 allocate an immediate event
371 return NULL on failure (memory allocation error)
373 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
374 const char *location)
376 struct tevent_immediate *im;
378 im = talloc(mem_ctx, struct tevent_immediate);
379 if (im == NULL) return NULL;
383 im->event_ctx = NULL;
384 im->create_location = location;
386 im->private_data = NULL;
387 im->handler_name = NULL;
388 im->schedule_location = NULL;
389 im->cancel_fn = NULL;
390 im->additional_data = NULL;
396 schedule an immediate event
397 return NULL on failure
399 void _tevent_schedule_immediate(struct tevent_immediate *im,
400 struct tevent_context *ev,
401 tevent_immediate_handler_t handler,
403 const char *handler_name,
404 const char *location)
406 ev->ops->schedule_immediate(im, ev, handler, private_data,
407 handler_name, location);
413 sa_flags are flags to sigaction(2)
415 return NULL on failure
417 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
421 tevent_signal_handler_t handler,
423 const char *handler_name,
424 const char *location)
426 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
427 handler_name, location);
430 void tevent_loop_allow_nesting(struct tevent_context *ev)
432 ev->nesting.allowed = true;
435 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
436 tevent_nesting_hook hook,
439 if (ev->nesting.hook_fn &&
440 (ev->nesting.hook_fn != hook ||
441 ev->nesting.hook_private != private_data)) {
442 /* the way the nesting hook code is currently written
443 we cannot support two different nesting hooks at the
445 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
447 ev->nesting.hook_fn = hook;
448 ev->nesting.hook_private = private_data;
451 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
455 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
458 reason = "tevent_loop_once() nesting";
461 tevent_abort(ev, reason);
465 do a single event loop using the events defined in ev
467 int _tevent_loop_once(struct tevent_context *ev, const char *location)
470 void *nesting_stack_ptr = NULL;
474 if (ev->nesting.level > 1) {
475 if (!ev->nesting.allowed) {
476 tevent_abort_nesting(ev, location);
481 if (ev->nesting.level > 0) {
482 if (ev->nesting.hook_fn) {
484 ret2 = ev->nesting.hook_fn(ev,
485 ev->nesting.hook_private,
488 (void *)&nesting_stack_ptr,
497 ret = ev->ops->loop_once(ev, location);
499 if (ev->nesting.level > 0) {
500 if (ev->nesting.hook_fn) {
502 ret2 = ev->nesting.hook_fn(ev,
503 ev->nesting.hook_private,
506 (void *)&nesting_stack_ptr,
521 this is a performance optimization for the samba4 nested event loop problems
523 int _tevent_loop_until(struct tevent_context *ev,
524 bool (*finished)(void *private_data),
526 const char *location)
529 void *nesting_stack_ptr = NULL;
533 if (ev->nesting.level > 1) {
534 if (!ev->nesting.allowed) {
535 tevent_abort_nesting(ev, location);
540 if (ev->nesting.level > 0) {
541 if (ev->nesting.hook_fn) {
543 ret2 = ev->nesting.hook_fn(ev,
544 ev->nesting.hook_private,
547 (void *)&nesting_stack_ptr,
556 while (!finished(private_data)) {
557 ret = ev->ops->loop_once(ev, location);
563 if (ev->nesting.level > 0) {
564 if (ev->nesting.hook_fn) {
566 ret2 = ev->nesting.hook_fn(ev,
567 ev->nesting.hook_private,
570 (void *)&nesting_stack_ptr,
585 extern pid_t ctdbd_pid;
588 return on failure or (with 0) if all fd events are removed
590 int tevent_common_loop_wait(struct tevent_context *ev,
591 const char *location)
597 * loop as long as we have events pending
599 while (ev->fd_events ||
601 ev->immediate_events ||
604 ret = _tevent_loop_once(ev, location);
606 tevent_debug(ev, TEVENT_DEBUG_FATAL,
607 "_tevent_loop_once() failed: %d - %s\n",
608 ret, strerror(errno));
611 if (getpid() == ctdbd_pid) {
615 tevent_debug(ev, TEVENT_DEBUG_FATAL, __location__ " ERROR Time skipped backward by %d seconds\n", (int)(t-new_t));
617 /* We assume here that we get at least one event every 3 seconds */
619 tevent_debug(ev, TEVENT_DEBUG_FATAL, __location__ " ERROR Time jumped forward by %d seconds\n", (int)(new_t-t));
626 tevent_debug(ev, TEVENT_DEBUG_WARNING,
627 "tevent_common_loop_wait() out of events\n");
632 return on failure or (with 0) if all fd events are removed
634 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
636 return ev->ops->loop_wait(ev, location);
641 re-initialise a tevent context. This leaves you with the same
642 event context, but all events are wiped and the structure is
643 re-initialised. This is most useful after a fork()
645 zero is returned on success, non-zero on failure
647 int tevent_re_initialise(struct tevent_context *ev)
649 tevent_common_context_destructor(ev);
651 return ev->ops->context_init(ev);