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 struct tevent_ops_list {
68 struct tevent_ops_list *next, *prev;
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 */
91 e = talloc(NULL, struct tevent_ops_list);
92 if (e == NULL) return false;
96 DLIST_ADD(tevent_backends, e);
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();
117 tevent_standard_init();
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);
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;
150 talloc_free(ev->pipe_fde);
151 close(ev->pipe_fds[0]);
152 close(ev->pipe_fds[1]);
156 for (fd = ev->fd_events; fd; fd = fn) {
158 fd->event_ctx = NULL;
159 DLIST_REMOVE(ev->fd_events, fd);
162 for (te = ev->timer_events; te; te = tn) {
164 te->event_ctx = NULL;
165 DLIST_REMOVE(ev->timer_events, te);
168 for (ie = ev->immediate_events; ie; ie = in) {
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) {
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 /* clean up nesting or we get an abort when nesting
189 * is not allowed. -- SSS */
190 ev->nesting.allowed = false;
191 ev->nesting.level = 0;
192 ev->nesting.hook_fn = NULL;
193 ev->nesting.hook_private = NULL;
199 create a event_context structure for a specific implemementation.
200 This must be the first events call, and all subsequent calls pass
201 this event_context as the first element. Event handlers also
202 receive this as their first argument.
204 This function is for allowing third-party-applications to hook in gluecode
205 to their own event loop code, so that they can make async usage of our client libs
207 NOTE: use tevent_context_init() inside of samba!
209 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
210 const struct tevent_ops *ops)
212 struct tevent_context *ev;
215 ev = talloc_zero(mem_ctx, struct tevent_context);
216 if (!ev) return NULL;
218 talloc_set_destructor(ev, tevent_common_context_destructor);
222 ret = ev->ops->context_init(ev);
232 create a event_context structure. This must be the first events
233 call, and all subsequent calls pass this event_context as the first
234 element. Event handlers also receive this as their first argument.
236 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
239 struct tevent_ops_list *e;
241 tevent_backend_init();
244 name = tevent_default_backend;
250 for (e=tevent_backends;e;e=e->next) {
251 if (strcmp(name, e->name) == 0) {
252 return tevent_context_init_ops(mem_ctx, e->ops);
260 create a event_context structure. This must be the first events
261 call, and all subsequent calls pass this event_context as the first
262 element. Event handlers also receive this as their first argument.
264 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
266 return tevent_context_init_byname(mem_ctx, NULL);
271 return NULL on failure (memory allocation error)
273 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
277 tevent_fd_handler_t handler,
279 const char *handler_name,
280 const char *location)
282 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
283 handler_name, location);
287 set a close function on the fd event
289 void tevent_fd_set_close_fn(struct tevent_fd *fde,
290 tevent_fd_close_fn_t close_fn)
293 if (!fde->event_ctx) return;
294 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
297 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
298 struct tevent_fd *fde,
305 void tevent_fd_set_auto_close(struct tevent_fd *fde)
307 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
311 return the fd event flags
313 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
316 if (!fde->event_ctx) return 0;
317 return fde->event_ctx->ops->get_fd_flags(fde);
321 set the fd event flags
323 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
326 if (!fde->event_ctx) return;
327 fde->event_ctx->ops->set_fd_flags(fde, flags);
330 bool tevent_signal_support(struct tevent_context *ev)
332 if (ev->ops->add_signal) {
338 static void (*tevent_abort_fn)(const char *reason);
340 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
342 tevent_abort_fn = abort_fn;
345 static void tevent_abort(struct tevent_context *ev, const char *reason)
347 tevent_debug(ev, TEVENT_DEBUG_FATAL,
348 "abort: %s\n", reason);
350 if (!tevent_abort_fn) {
354 tevent_abort_fn(reason);
359 return NULL on failure
361 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
363 struct timeval next_event,
364 tevent_timer_handler_t handler,
366 const char *handler_name,
367 const char *location)
369 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
370 handler_name, location);
374 allocate an immediate event
375 return NULL on failure (memory allocation error)
377 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
378 const char *location)
380 struct tevent_immediate *im;
382 im = talloc(mem_ctx, struct tevent_immediate);
383 if (im == NULL) return NULL;
387 im->event_ctx = NULL;
388 im->create_location = location;
390 im->private_data = NULL;
391 im->handler_name = NULL;
392 im->schedule_location = NULL;
393 im->cancel_fn = NULL;
394 im->additional_data = NULL;
400 schedule an immediate event
401 return NULL on failure
403 void _tevent_schedule_immediate(struct tevent_immediate *im,
404 struct tevent_context *ev,
405 tevent_immediate_handler_t handler,
407 const char *handler_name,
408 const char *location)
410 ev->ops->schedule_immediate(im, ev, handler, private_data,
411 handler_name, location);
417 sa_flags are flags to sigaction(2)
419 return NULL on failure
421 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
425 tevent_signal_handler_t handler,
427 const char *handler_name,
428 const char *location)
430 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
431 handler_name, location);
434 void tevent_loop_allow_nesting(struct tevent_context *ev)
436 ev->nesting.allowed = true;
439 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
440 tevent_nesting_hook hook,
443 if (ev->nesting.hook_fn &&
444 (ev->nesting.hook_fn != hook ||
445 ev->nesting.hook_private != private_data)) {
446 /* the way the nesting hook code is currently written
447 we cannot support two different nesting hooks at the
449 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
451 ev->nesting.hook_fn = hook;
452 ev->nesting.hook_private = private_data;
455 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
459 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
462 reason = "tevent_loop_once() nesting";
465 tevent_abort(ev, reason);
469 do a single event loop using the events defined in ev
471 int _tevent_loop_once(struct tevent_context *ev, const char *location)
474 void *nesting_stack_ptr = NULL;
478 if (ev->nesting.level > 1) {
479 if (!ev->nesting.allowed) {
480 tevent_abort_nesting(ev, location);
485 if (ev->nesting.level > 0) {
486 if (ev->nesting.hook_fn) {
488 ret2 = ev->nesting.hook_fn(ev,
489 ev->nesting.hook_private,
492 (void *)&nesting_stack_ptr,
501 ret = ev->ops->loop_once(ev, location);
503 if (ev->nesting.level > 0) {
504 if (ev->nesting.hook_fn) {
506 ret2 = ev->nesting.hook_fn(ev,
507 ev->nesting.hook_private,
510 (void *)&nesting_stack_ptr,
525 this is a performance optimization for the samba4 nested event loop problems
527 int _tevent_loop_until(struct tevent_context *ev,
528 bool (*finished)(void *private_data),
530 const char *location)
533 void *nesting_stack_ptr = NULL;
537 if (ev->nesting.level > 1) {
538 if (!ev->nesting.allowed) {
539 tevent_abort_nesting(ev, location);
544 if (ev->nesting.level > 0) {
545 if (ev->nesting.hook_fn) {
547 ret2 = ev->nesting.hook_fn(ev,
548 ev->nesting.hook_private,
551 (void *)&nesting_stack_ptr,
560 while (!finished(private_data)) {
561 ret = ev->ops->loop_once(ev, location);
567 if (ev->nesting.level > 0) {
568 if (ev->nesting.hook_fn) {
570 ret2 = ev->nesting.hook_fn(ev,
571 ev->nesting.hook_private,
574 (void *)&nesting_stack_ptr,
589 return on failure or (with 0) if all fd events are removed
591 int tevent_common_loop_wait(struct tevent_context *ev,
592 const char *location)
595 * loop as long as we have events pending
597 while (ev->fd_events ||
599 ev->immediate_events ||
602 ret = _tevent_loop_once(ev, location);
604 tevent_debug(ev, TEVENT_DEBUG_FATAL,
605 "_tevent_loop_once() failed: %d - %s\n",
606 ret, strerror(errno));
611 tevent_debug(ev, TEVENT_DEBUG_WARNING,
612 "tevent_common_loop_wait() out of events\n");
617 return on failure or (with 0) if all fd events are removed
619 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
621 return ev->ops->loop_wait(ev, location);
626 re-initialise a tevent context. This leaves you with the same
627 event context, but all events are wiped and the structure is
628 re-initialised. This is most useful after a fork()
630 zero is returned on success, non-zero on failure
632 int tevent_re_initialise(struct tevent_context *ev)
634 tevent_common_context_destructor(ev);
636 return ev->ops->context_init(ev);