libcli:nbt move prototypes of lmhosts functions to libnbt.h
[Samba.git] / lib / tevent / tevent.c
blob56d0da39276ee3489b59b8d81ab495d601266903
1 /*
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
9 ** under the LGPL
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
31 somewhere else.
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
57 forever.
60 #include "replace.h"
61 #include "system/filesys.h"
62 #define TEVENT_DEPRECATED 1
63 #include "tevent.h"
64 #include "tevent_internal.h"
65 #include "tevent_util.h"
67 struct tevent_ops_list {
68 struct tevent_ops_list *next, *prev;
69 const char *name;
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 */
87 return true;
91 e = talloc(talloc_autofree_context(), struct tevent_ops_list);
92 if (e == NULL) return false;
94 e->name = name;
95 e->ops = ops;
96 DLIST_ADD(tevent_backends, e);
98 return true;
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(),
108 backend);
112 initialise backends if not already done
114 static void tevent_backend_init(void)
116 tevent_select_init();
117 tevent_standard_init();
118 #ifdef HAVE_EPOLL
119 tevent_epoll_init();
120 #endif
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);
139 return 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;
149 if (ev->pipe_fde) {
150 talloc_free(ev->pipe_fde);
151 close(ev->pipe_fds[0]);
152 close(ev->pipe_fds[1]);
153 ev->pipe_fde = NULL;
156 for (fd = ev->fd_events; fd; fd = fn) {
157 fn = fd->next;
158 fd->event_ctx = NULL;
159 DLIST_REMOVE(ev->fd_events, fd);
162 for (te = ev->timer_events; te; te = tn) {
163 tn = te->next;
164 te->event_ctx = NULL;
165 DLIST_REMOVE(ev->timer_events, te);
168 for (ie = ev->immediate_events; ie; ie = in) {
169 in = ie->next;
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) {
176 sn = se->next;
177 se->event_ctx = NULL;
178 DLIST_REMOVE(ev->signal_events, se);
181 return 0;
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;
199 int ret;
201 ev = talloc_zero(mem_ctx, struct tevent_context);
202 if (!ev) return NULL;
204 talloc_set_destructor(ev, tevent_common_context_destructor);
206 ev->ops = ops;
208 ret = ev->ops->context_init(ev);
209 if (ret != 0) {
210 talloc_free(ev);
211 return NULL;
214 return 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,
223 const char *name)
225 struct tevent_ops_list *e;
227 tevent_backend_init();
229 if (name == NULL) {
230 name = tevent_default_backend;
232 if (name == NULL) {
233 name = "standard";
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);
241 return NULL;
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);
256 add a fd based event
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,
263 TALLOC_CTX *mem_ctx,
264 int fd,
265 uint16_t flags,
266 tevent_fd_handler_t handler,
267 void *private_data,
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)
281 if (!fde) return;
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,
288 int fd,
289 void *private_data)
291 close(fd);
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)
304 if (!fde) return 0;
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)
314 if (!fde) return;
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) {
322 return true;
324 return false;
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) {
340 abort();
343 tevent_abort_fn(reason);
347 add a timer event
348 return NULL on failure
350 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
351 TALLOC_CTX *mem_ctx,
352 struct timeval next_event,
353 tevent_timer_handler_t handler,
354 void *private_data,
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;
374 im->prev = NULL;
375 im->next = NULL;
376 im->event_ctx = NULL;
377 im->create_location = location;
378 im->handler = NULL;
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;
385 return im;
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,
395 void *private_data,
396 const char *handler_name,
397 const char *location)
399 ev->ops->schedule_immediate(im, ev, handler, private_data,
400 handler_name, location);
404 add a signal event
406 sa_flags are flags to sigaction(2)
408 return NULL on failure
410 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
411 TALLOC_CTX *mem_ctx,
412 int signum,
413 int sa_flags,
414 tevent_signal_handler_t handler,
415 void *private_data,
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,
430 void *private_data)
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
437 same time. */
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)
446 const char *reason;
448 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
449 location);
450 if (!reason) {
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)
462 int ret;
463 void *nesting_stack_ptr = NULL;
465 ev->nesting.level++;
467 if (ev->nesting.level > 1) {
468 if (!ev->nesting.allowed) {
469 tevent_abort_nesting(ev, location);
470 errno = ELOOP;
471 return -1;
474 if (ev->nesting.level > 0) {
475 if (ev->nesting.hook_fn) {
476 int ret2;
477 ret2 = ev->nesting.hook_fn(ev,
478 ev->nesting.hook_private,
479 ev->nesting.level,
480 true,
481 (void *)&nesting_stack_ptr,
482 location);
483 if (ret2 != 0) {
484 ret = ret2;
485 goto done;
490 ret = ev->ops->loop_once(ev, location);
492 if (ev->nesting.level > 0) {
493 if (ev->nesting.hook_fn) {
494 int ret2;
495 ret2 = ev->nesting.hook_fn(ev,
496 ev->nesting.hook_private,
497 ev->nesting.level,
498 false,
499 (void *)&nesting_stack_ptr,
500 location);
501 if (ret2 != 0) {
502 ret = ret2;
503 goto done;
508 done:
509 ev->nesting.level--;
510 return ret;
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),
518 void *private_data,
519 const char *location)
521 int ret = 0;
522 void *nesting_stack_ptr = NULL;
524 ev->nesting.level++;
526 if (ev->nesting.level > 1) {
527 if (!ev->nesting.allowed) {
528 tevent_abort_nesting(ev, location);
529 errno = ELOOP;
530 return -1;
533 if (ev->nesting.level > 0) {
534 if (ev->nesting.hook_fn) {
535 int ret2;
536 ret2 = ev->nesting.hook_fn(ev,
537 ev->nesting.hook_private,
538 ev->nesting.level,
539 true,
540 (void *)&nesting_stack_ptr,
541 location);
542 if (ret2 != 0) {
543 ret = ret2;
544 goto done;
549 while (!finished(private_data)) {
550 ret = ev->ops->loop_once(ev, location);
551 if (ret != 0) {
552 break;
556 if (ev->nesting.level > 0) {
557 if (ev->nesting.hook_fn) {
558 int ret2;
559 ret2 = ev->nesting.hook_fn(ev,
560 ev->nesting.hook_private,
561 ev->nesting.level,
562 false,
563 (void *)&nesting_stack_ptr,
564 location);
565 if (ret2 != 0) {
566 ret = ret2;
567 goto done;
572 done:
573 ev->nesting.level--;
574 return ret;
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 ||
587 ev->timer_events ||
588 ev->immediate_events ||
589 ev->signal_events) {
590 int ret;
591 ret = _tevent_loop_once(ev, location);
592 if (ret != 0) {
593 tevent_debug(ev, TEVENT_DEBUG_FATAL,
594 "_tevent_loop_once() failed: %d - %s\n",
595 ret, strerror(errno));
596 return ret;
600 tevent_debug(ev, TEVENT_DEBUG_WARNING,
601 "tevent_common_loop_wait() out of events\n");
602 return 0;
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);