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);
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);
192
create a event_context structure for a specific implemementation.
193
This must be the first events call, and all subsequent calls pass
194
this event_context as the first element. Event handlers also
195
receive this as their first argument.
197
This function is for allowing third-party-applications to hook in gluecode
198
to their own event loop code, so that they can make async usage of our client libs
200
NOTE: use tevent_context_init() inside of samba!
202
static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
203
const struct tevent_ops *ops)
205
struct tevent_context *ev;
208
ev = talloc_zero(mem_ctx, struct tevent_context);
209
if (!ev) return NULL;
211
talloc_set_destructor(ev, tevent_common_context_destructor);
215
ret = ev->ops->context_init(ev);
225
create a event_context structure. This must be the first events
226
call, and all subsequent calls pass this event_context as the first
227
element. Event handlers also receive this as their first argument.
229
struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
232
struct tevent_ops_list *e;
234
tevent_backend_init();
237
name = tevent_default_backend;
243
for (e=tevent_backends;e;e=e->next) {
244
if (strcmp(name, e->name) == 0) {
245
return tevent_context_init_ops(mem_ctx, e->ops);
253
create a event_context structure. This must be the first events
254
call, and all subsequent calls pass this event_context as the first
255
element. Event handlers also receive this as their first argument.
257
struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
259
return tevent_context_init_byname(mem_ctx, NULL);
264
return NULL on failure (memory allocation error)
266
if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
267
the returned fd_event context is freed
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
return on failure or (with 0) if all fd events are removed
587
int tevent_common_loop_wait(struct tevent_context *ev,
588
const char *location)
591
* loop as long as we have events pending
593
while (ev->fd_events ||
595
ev->immediate_events ||
598
ret = _tevent_loop_once(ev, location);
600
tevent_debug(ev, TEVENT_DEBUG_FATAL,
601
"_tevent_loop_once() failed: %d - %s\n",
602
ret, strerror(errno));
607
tevent_debug(ev, TEVENT_DEBUG_WARNING,
608
"tevent_common_loop_wait() out of events\n");
613
return on failure or (with 0) if all fd events are removed
615
int _tevent_loop_wait(struct tevent_context *ev, const char *location)
617
return ev->ops->loop_wait(ev, location);