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(talloc_autofree_context(), 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(talloc_autofree_context(),
112 initialise backends if not already done
114 static void tevent_backend_init(void)
116 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
);
185 create a event_context structure for a specific implemementation.
186 This must be the first events call, and all subsequent calls pass
187 this event_context as the first element. Event handlers also
188 receive this as their first argument.
190 This function is for allowing third-party-applications to hook in gluecode
191 to their own event loop code, so that they can make async usage of our client libs
193 NOTE: use tevent_context_init() inside of samba!
195 static struct tevent_context
*tevent_context_init_ops(TALLOC_CTX
*mem_ctx
,
196 const struct tevent_ops
*ops
)
198 struct tevent_context
*ev
;
201 ev
= talloc_zero(mem_ctx
, struct tevent_context
);
202 if (!ev
) return NULL
;
204 talloc_set_destructor(ev
, tevent_common_context_destructor
);
208 ret
= ev
->ops
->context_init(ev
);
218 create a event_context structure. This must be the first events
219 call, and all subsequent calls pass this event_context as the first
220 element. Event handlers also receive this as their first argument.
222 struct tevent_context
*tevent_context_init_byname(TALLOC_CTX
*mem_ctx
,
225 struct tevent_ops_list
*e
;
227 tevent_backend_init();
230 name
= tevent_default_backend
;
236 for (e
=tevent_backends
;e
;e
=e
->next
) {
237 if (strcmp(name
, e
->name
) == 0) {
238 return tevent_context_init_ops(mem_ctx
, e
->ops
);
246 create a event_context structure. This must be the first events
247 call, and all subsequent calls pass this event_context as the first
248 element. Event handlers also receive this as their first argument.
250 struct tevent_context
*tevent_context_init(TALLOC_CTX
*mem_ctx
)
252 return tevent_context_init_byname(mem_ctx
, NULL
);
257 return NULL on failure (memory allocation error)
259 if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
260 the returned fd_event context is freed
262 struct tevent_fd
*_tevent_add_fd(struct tevent_context
*ev
,
266 tevent_fd_handler_t handler
,
268 const char *handler_name
,
269 const char *location
)
271 return ev
->ops
->add_fd(ev
, mem_ctx
, fd
, flags
, handler
, private_data
,
272 handler_name
, location
);
276 set a close function on the fd event
278 void tevent_fd_set_close_fn(struct tevent_fd
*fde
,
279 tevent_fd_close_fn_t close_fn
)
282 if (!fde
->event_ctx
) return;
283 fde
->event_ctx
->ops
->set_fd_close_fn(fde
, close_fn
);
286 static void tevent_fd_auto_close_fn(struct tevent_context
*ev
,
287 struct tevent_fd
*fde
,
294 void tevent_fd_set_auto_close(struct tevent_fd
*fde
)
296 tevent_fd_set_close_fn(fde
, tevent_fd_auto_close_fn
);
300 return the fd event flags
302 uint16_t tevent_fd_get_flags(struct tevent_fd
*fde
)
305 if (!fde
->event_ctx
) return 0;
306 return fde
->event_ctx
->ops
->get_fd_flags(fde
);
310 set the fd event flags
312 void tevent_fd_set_flags(struct tevent_fd
*fde
, uint16_t flags
)
315 if (!fde
->event_ctx
) return;
316 fde
->event_ctx
->ops
->set_fd_flags(fde
, flags
);
319 bool tevent_signal_support(struct tevent_context
*ev
)
321 if (ev
->ops
->add_signal
) {
327 static void (*tevent_abort_fn
)(const char *reason
);
329 void tevent_set_abort_fn(void (*abort_fn
)(const char *reason
))
331 tevent_abort_fn
= abort_fn
;
334 static void tevent_abort(struct tevent_context
*ev
, const char *reason
)
336 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
337 "abort: %s\n", reason
);
339 if (!tevent_abort_fn
) {
343 tevent_abort_fn(reason
);
348 return NULL on failure
350 struct tevent_timer
*_tevent_add_timer(struct tevent_context
*ev
,
352 struct timeval next_event
,
353 tevent_timer_handler_t handler
,
355 const char *handler_name
,
356 const char *location
)
358 return ev
->ops
->add_timer(ev
, mem_ctx
, next_event
, handler
, private_data
,
359 handler_name
, location
);
363 allocate an immediate event
364 return NULL on failure (memory allocation error)
366 struct tevent_immediate
*_tevent_create_immediate(TALLOC_CTX
*mem_ctx
,
367 const char *location
)
369 struct tevent_immediate
*im
;
371 im
= talloc(mem_ctx
, struct tevent_immediate
);
372 if (im
== NULL
) return NULL
;
376 im
->event_ctx
= NULL
;
377 im
->create_location
= location
;
379 im
->private_data
= NULL
;
380 im
->handler_name
= NULL
;
381 im
->schedule_location
= NULL
;
382 im
->cancel_fn
= NULL
;
383 im
->additional_data
= NULL
;
389 schedule an immediate event
390 return NULL on failure
392 void _tevent_schedule_immediate(struct tevent_immediate
*im
,
393 struct tevent_context
*ev
,
394 tevent_immediate_handler_t handler
,
396 const char *handler_name
,
397 const char *location
)
399 ev
->ops
->schedule_immediate(im
, ev
, handler
, private_data
,
400 handler_name
, location
);
406 sa_flags are flags to sigaction(2)
408 return NULL on failure
410 struct tevent_signal
*_tevent_add_signal(struct tevent_context
*ev
,
414 tevent_signal_handler_t handler
,
416 const char *handler_name
,
417 const char *location
)
419 return ev
->ops
->add_signal(ev
, mem_ctx
, signum
, sa_flags
, handler
, private_data
,
420 handler_name
, location
);
423 void tevent_loop_allow_nesting(struct tevent_context
*ev
)
425 ev
->nesting
.allowed
= true;
428 void tevent_loop_set_nesting_hook(struct tevent_context
*ev
,
429 tevent_nesting_hook hook
,
432 if (ev
->nesting
.hook_fn
&&
433 (ev
->nesting
.hook_fn
!= hook
||
434 ev
->nesting
.hook_private
!= private_data
)) {
435 /* the way the nesting hook code is currently written
436 we cannot support two different nesting hooks at the
438 tevent_abort(ev
, "tevent: Violation of nesting hook rules\n");
440 ev
->nesting
.hook_fn
= hook
;
441 ev
->nesting
.hook_private
= private_data
;
444 static void tevent_abort_nesting(struct tevent_context
*ev
, const char *location
)
448 reason
= talloc_asprintf(NULL
, "tevent_loop_once() nesting at %s",
451 reason
= "tevent_loop_once() nesting";
454 tevent_abort(ev
, reason
);
458 do a single event loop using the events defined in ev
460 int _tevent_loop_once(struct tevent_context
*ev
, const char *location
)
463 void *nesting_stack_ptr
= NULL
;
467 if (ev
->nesting
.level
> 1) {
468 if (!ev
->nesting
.allowed
) {
469 tevent_abort_nesting(ev
, location
);
474 if (ev
->nesting
.level
> 0) {
475 if (ev
->nesting
.hook_fn
) {
477 ret2
= ev
->nesting
.hook_fn(ev
,
478 ev
->nesting
.hook_private
,
481 (void *)&nesting_stack_ptr
,
490 ret
= ev
->ops
->loop_once(ev
, location
);
492 if (ev
->nesting
.level
> 0) {
493 if (ev
->nesting
.hook_fn
) {
495 ret2
= ev
->nesting
.hook_fn(ev
,
496 ev
->nesting
.hook_private
,
499 (void *)&nesting_stack_ptr
,
514 this is a performance optimization for the samba4 nested event loop problems
516 int _tevent_loop_until(struct tevent_context
*ev
,
517 bool (*finished
)(void *private_data
),
519 const char *location
)
522 void *nesting_stack_ptr
= NULL
;
526 if (ev
->nesting
.level
> 1) {
527 if (!ev
->nesting
.allowed
) {
528 tevent_abort_nesting(ev
, location
);
533 if (ev
->nesting
.level
> 0) {
534 if (ev
->nesting
.hook_fn
) {
536 ret2
= ev
->nesting
.hook_fn(ev
,
537 ev
->nesting
.hook_private
,
540 (void *)&nesting_stack_ptr
,
549 while (!finished(private_data
)) {
550 ret
= ev
->ops
->loop_once(ev
, location
);
556 if (ev
->nesting
.level
> 0) {
557 if (ev
->nesting
.hook_fn
) {
559 ret2
= ev
->nesting
.hook_fn(ev
,
560 ev
->nesting
.hook_private
,
563 (void *)&nesting_stack_ptr
,
578 return on failure or (with 0) if all fd events are removed
580 int tevent_common_loop_wait(struct tevent_context
*ev
,
581 const char *location
)
584 * loop as long as we have events pending
586 while (ev
->fd_events
||
588 ev
->immediate_events
||
591 ret
= _tevent_loop_once(ev
, location
);
593 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
594 "_tevent_loop_once() failed: %d - %s\n",
595 ret
, strerror(errno
));
600 tevent_debug(ev
, TEVENT_DEBUG_WARNING
,
601 "tevent_common_loop_wait() out of events\n");
606 return on failure or (with 0) if all fd events are removed
608 int _tevent_loop_wait(struct tevent_context
*ev
, const char *location
)
610 return ev
->ops
->loop_wait(ev
, location
);