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)
123 tevent_select_init();
125 tevent_poll_mt_init();
126 #if defined(HAVE_EPOLL)
128 #elif defined(HAVE_SOLARIS_PORTS)
132 tevent_standard_init();
135 _PRIVATE_
const struct tevent_ops
*tevent_find_ops_byname(const char *name
)
137 struct tevent_ops_list
*e
;
139 tevent_backend_init();
142 name
= tevent_default_backend
;
148 for (e
= tevent_backends
; e
!= NULL
; e
= e
->next
) {
149 if (0 == strcmp(e
->name
, name
)) {
158 list available backends
160 const char **tevent_backend_list(TALLOC_CTX
*mem_ctx
)
162 const char **list
= NULL
;
163 struct tevent_ops_list
*e
;
165 tevent_backend_init();
167 for (e
=tevent_backends
;e
;e
=e
->next
) {
168 list
= ev_str_list_add(list
, e
->name
);
171 talloc_steal(mem_ctx
, list
);
176 int tevent_common_context_destructor(struct tevent_context
*ev
)
178 struct tevent_fd
*fd
, *fn
;
179 struct tevent_timer
*te
, *tn
;
180 struct tevent_immediate
*ie
, *in
;
181 struct tevent_signal
*se
, *sn
;
184 talloc_free(ev
->pipe_fde
);
185 close(ev
->pipe_fds
[0]);
186 close(ev
->pipe_fds
[1]);
190 for (fd
= ev
->fd_events
; fd
; fd
= fn
) {
192 fd
->event_ctx
= NULL
;
193 DLIST_REMOVE(ev
->fd_events
, fd
);
196 ev
->last_zero_timer
= NULL
;
197 for (te
= ev
->timer_events
; te
; te
= tn
) {
199 te
->event_ctx
= NULL
;
200 DLIST_REMOVE(ev
->timer_events
, te
);
203 for (ie
= ev
->immediate_events
; ie
; ie
= in
) {
205 ie
->event_ctx
= NULL
;
206 ie
->cancel_fn
= NULL
;
207 DLIST_REMOVE(ev
->immediate_events
, ie
);
210 for (se
= ev
->signal_events
; se
; se
= sn
) {
212 se
->event_ctx
= NULL
;
213 DLIST_REMOVE(ev
->signal_events
, se
);
215 * This is important, Otherwise signals
216 * are handled twice in child. eg, SIGHUP.
217 * one added in parent, and another one in
218 * the child. -- BoYang
220 tevent_cleanup_pending_signal_handlers(se
);
223 /* removing nesting hook or we get an abort when nesting is
224 * not allowed. -- SSS
225 * Note that we need to leave the allowed flag at its current
226 * value, otherwise the use in tevent_re_initialise() will
227 * leave the event context with allowed forced to false, which
228 * will break users that expect nesting to be allowed
230 ev
->nesting
.level
= 0;
231 ev
->nesting
.hook_fn
= NULL
;
232 ev
->nesting
.hook_private
= NULL
;
238 create a event_context structure for a specific implemementation.
239 This must be the first events call, and all subsequent calls pass
240 this event_context as the first element. Event handlers also
241 receive this as their first argument.
243 This function is for allowing third-party-applications to hook in gluecode
244 to their own event loop code, so that they can make async usage of our client libs
246 NOTE: use tevent_context_init() inside of samba!
248 struct tevent_context
*tevent_context_init_ops(TALLOC_CTX
*mem_ctx
,
249 const struct tevent_ops
*ops
,
250 void *additional_data
)
252 struct tevent_context
*ev
;
255 ev
= talloc_zero(mem_ctx
, struct tevent_context
);
256 if (!ev
) return NULL
;
258 talloc_set_destructor(ev
, tevent_common_context_destructor
);
261 ev
->additional_data
= additional_data
;
263 ret
= ev
->ops
->context_init(ev
);
273 create a event_context structure. This must be the first events
274 call, and all subsequent calls pass this event_context as the first
275 element. Event handlers also receive this as their first argument.
277 struct tevent_context
*tevent_context_init_byname(TALLOC_CTX
*mem_ctx
,
280 const struct tevent_ops
*ops
;
282 ops
= tevent_find_ops_byname(name
);
287 return tevent_context_init_ops(mem_ctx
, ops
, NULL
);
292 create a event_context structure. This must be the first events
293 call, and all subsequent calls pass this event_context as the first
294 element. Event handlers also receive this as their first argument.
296 struct tevent_context
*tevent_context_init(TALLOC_CTX
*mem_ctx
)
298 return tevent_context_init_byname(mem_ctx
, NULL
);
303 return NULL on failure (memory allocation error)
305 struct tevent_fd
*_tevent_add_fd(struct tevent_context
*ev
,
309 tevent_fd_handler_t handler
,
311 const char *handler_name
,
312 const char *location
)
314 return ev
->ops
->add_fd(ev
, mem_ctx
, fd
, flags
, handler
, private_data
,
315 handler_name
, location
);
319 set a close function on the fd event
321 void tevent_fd_set_close_fn(struct tevent_fd
*fde
,
322 tevent_fd_close_fn_t close_fn
)
325 if (!fde
->event_ctx
) return;
326 fde
->event_ctx
->ops
->set_fd_close_fn(fde
, close_fn
);
329 static void tevent_fd_auto_close_fn(struct tevent_context
*ev
,
330 struct tevent_fd
*fde
,
337 void tevent_fd_set_auto_close(struct tevent_fd
*fde
)
339 tevent_fd_set_close_fn(fde
, tevent_fd_auto_close_fn
);
343 return the fd event flags
345 uint16_t tevent_fd_get_flags(struct tevent_fd
*fde
)
348 if (!fde
->event_ctx
) return 0;
349 return fde
->event_ctx
->ops
->get_fd_flags(fde
);
353 set the fd event flags
355 void tevent_fd_set_flags(struct tevent_fd
*fde
, uint16_t flags
)
358 if (!fde
->event_ctx
) return;
359 fde
->event_ctx
->ops
->set_fd_flags(fde
, flags
);
362 bool tevent_signal_support(struct tevent_context
*ev
)
364 if (ev
->ops
->add_signal
) {
370 static void (*tevent_abort_fn
)(const char *reason
);
372 void tevent_set_abort_fn(void (*abort_fn
)(const char *reason
))
374 tevent_abort_fn
= abort_fn
;
377 static void tevent_abort(struct tevent_context
*ev
, const char *reason
)
379 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
380 "abort: %s\n", reason
);
382 if (!tevent_abort_fn
) {
386 tevent_abort_fn(reason
);
391 return NULL on failure
393 struct tevent_timer
*_tevent_add_timer(struct tevent_context
*ev
,
395 struct timeval next_event
,
396 tevent_timer_handler_t handler
,
398 const char *handler_name
,
399 const char *location
)
401 return ev
->ops
->add_timer(ev
, mem_ctx
, next_event
, handler
, private_data
,
402 handler_name
, location
);
406 allocate an immediate event
407 return NULL on failure (memory allocation error)
409 struct tevent_immediate
*_tevent_create_immediate(TALLOC_CTX
*mem_ctx
,
410 const char *location
)
412 struct tevent_immediate
*im
;
414 im
= talloc(mem_ctx
, struct tevent_immediate
);
415 if (im
== NULL
) return NULL
;
419 im
->event_ctx
= NULL
;
420 im
->create_location
= location
;
422 im
->private_data
= NULL
;
423 im
->handler_name
= NULL
;
424 im
->schedule_location
= NULL
;
425 im
->cancel_fn
= NULL
;
426 im
->additional_data
= NULL
;
432 schedule an immediate event
434 void _tevent_schedule_immediate(struct tevent_immediate
*im
,
435 struct tevent_context
*ev
,
436 tevent_immediate_handler_t handler
,
438 const char *handler_name
,
439 const char *location
)
441 ev
->ops
->schedule_immediate(im
, ev
, handler
, private_data
,
442 handler_name
, location
);
448 sa_flags are flags to sigaction(2)
450 return NULL on failure
452 struct tevent_signal
*_tevent_add_signal(struct tevent_context
*ev
,
456 tevent_signal_handler_t handler
,
458 const char *handler_name
,
459 const char *location
)
461 return ev
->ops
->add_signal(ev
, mem_ctx
, signum
, sa_flags
, handler
, private_data
,
462 handler_name
, location
);
465 void tevent_loop_allow_nesting(struct tevent_context
*ev
)
467 ev
->nesting
.allowed
= true;
470 void tevent_loop_set_nesting_hook(struct tevent_context
*ev
,
471 tevent_nesting_hook hook
,
474 if (ev
->nesting
.hook_fn
&&
475 (ev
->nesting
.hook_fn
!= hook
||
476 ev
->nesting
.hook_private
!= private_data
)) {
477 /* the way the nesting hook code is currently written
478 we cannot support two different nesting hooks at the
480 tevent_abort(ev
, "tevent: Violation of nesting hook rules\n");
482 ev
->nesting
.hook_fn
= hook
;
483 ev
->nesting
.hook_private
= private_data
;
486 static void tevent_abort_nesting(struct tevent_context
*ev
, const char *location
)
490 reason
= talloc_asprintf(NULL
, "tevent_loop_once() nesting at %s",
493 reason
= "tevent_loop_once() nesting";
496 tevent_abort(ev
, reason
);
500 do a single event loop using the events defined in ev
502 int _tevent_loop_once(struct tevent_context
*ev
, const char *location
)
505 void *nesting_stack_ptr
= NULL
;
509 if (ev
->nesting
.level
> 1) {
510 if (!ev
->nesting
.allowed
) {
511 tevent_abort_nesting(ev
, location
);
516 if (ev
->nesting
.level
> 0) {
517 if (ev
->nesting
.hook_fn
) {
519 ret2
= ev
->nesting
.hook_fn(ev
,
520 ev
->nesting
.hook_private
,
523 (void *)&nesting_stack_ptr
,
532 tevent_trace_point_callback(ev
, TEVENT_TRACE_BEFORE_LOOP_ONCE
);
533 ret
= ev
->ops
->loop_once(ev
, location
);
534 tevent_trace_point_callback(ev
, TEVENT_TRACE_AFTER_LOOP_ONCE
);
536 if (ev
->nesting
.level
> 0) {
537 if (ev
->nesting
.hook_fn
) {
539 ret2
= ev
->nesting
.hook_fn(ev
,
540 ev
->nesting
.hook_private
,
543 (void *)&nesting_stack_ptr
,
558 this is a performance optimization for the samba4 nested event loop problems
560 int _tevent_loop_until(struct tevent_context
*ev
,
561 bool (*finished
)(void *private_data
),
563 const char *location
)
566 void *nesting_stack_ptr
= NULL
;
570 if (ev
->nesting
.level
> 1) {
571 if (!ev
->nesting
.allowed
) {
572 tevent_abort_nesting(ev
, location
);
577 if (ev
->nesting
.level
> 0) {
578 if (ev
->nesting
.hook_fn
) {
580 ret2
= ev
->nesting
.hook_fn(ev
,
581 ev
->nesting
.hook_private
,
584 (void *)&nesting_stack_ptr
,
593 while (!finished(private_data
)) {
594 tevent_trace_point_callback(ev
, TEVENT_TRACE_BEFORE_LOOP_ONCE
);
595 ret
= ev
->ops
->loop_once(ev
, location
);
596 tevent_trace_point_callback(ev
, TEVENT_TRACE_AFTER_LOOP_ONCE
);
602 if (ev
->nesting
.level
> 0) {
603 if (ev
->nesting
.hook_fn
) {
605 ret2
= ev
->nesting
.hook_fn(ev
,
606 ev
->nesting
.hook_private
,
609 (void *)&nesting_stack_ptr
,
624 return on failure or (with 0) if all fd events are removed
626 int tevent_common_loop_wait(struct tevent_context
*ev
,
627 const char *location
)
630 * loop as long as we have events pending
632 while (ev
->fd_events
||
634 ev
->immediate_events
||
637 ret
= _tevent_loop_once(ev
, location
);
639 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
640 "_tevent_loop_once() failed: %d - %s\n",
641 ret
, strerror(errno
));
646 tevent_debug(ev
, TEVENT_DEBUG_WARNING
,
647 "tevent_common_loop_wait() out of events\n");
652 return on failure or (with 0) if all fd events are removed
654 int _tevent_loop_wait(struct tevent_context
*ev
, const char *location
)
656 return ev
->ops
->loop_wait(ev
, location
);
661 re-initialise a tevent context. This leaves you with the same
662 event context, but all events are wiped and the structure is
663 re-initialised. This is most useful after a fork()
665 zero is returned on success, non-zero on failure
667 int tevent_re_initialise(struct tevent_context
*ev
)
669 tevent_common_context_destructor(ev
);
671 return ev
->ops
->context_init(ev
);