pytevent: remove const warnings using discard_const_p()
[Samba.git] / lib / tevent / tevent.c
blob843cf0560f3b5190f4e1f10d9bd421e0db4cc047
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(NULL, 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(NULL, backend);
111 initialise backends if not already done
113 static void tevent_backend_init(void)
115 static bool done;
117 if (done) {
118 return;
121 done = true;
123 tevent_select_init();
124 tevent_poll_init();
125 tevent_poll_mt_init();
126 #if defined(HAVE_EPOLL)
127 tevent_epoll_init();
128 #elif defined(HAVE_SOLARIS_PORTS)
129 tevent_port_init();
130 #endif
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();
141 if (name == NULL) {
142 name = tevent_default_backend;
144 if (name == NULL) {
145 name = "standard";
148 for (e = tevent_backends; e != NULL; e = e->next) {
149 if (0 == strcmp(e->name, name)) {
150 return e->ops;
154 return NULL;
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);
173 return 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;
183 if (ev->pipe_fde) {
184 talloc_free(ev->pipe_fde);
185 close(ev->pipe_fds[0]);
186 close(ev->pipe_fds[1]);
187 ev->pipe_fde = NULL;
190 for (fd = ev->fd_events; fd; fd = fn) {
191 fn = fd->next;
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) {
198 tn = te->next;
199 te->event_ctx = NULL;
200 DLIST_REMOVE(ev->timer_events, te);
203 for (ie = ev->immediate_events; ie; ie = in) {
204 in = ie->next;
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) {
211 sn = se->next;
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;
234 return 0;
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;
253 int ret;
255 ev = talloc_zero(mem_ctx, struct tevent_context);
256 if (!ev) return NULL;
258 talloc_set_destructor(ev, tevent_common_context_destructor);
260 ev->ops = ops;
261 ev->additional_data = additional_data;
263 ret = ev->ops->context_init(ev);
264 if (ret != 0) {
265 talloc_free(ev);
266 return NULL;
269 return 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,
278 const char *name)
280 const struct tevent_ops *ops;
282 ops = tevent_find_ops_byname(name);
283 if (ops == NULL) {
284 return NULL;
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);
302 add a fd based event
303 return NULL on failure (memory allocation error)
305 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
306 TALLOC_CTX *mem_ctx,
307 int fd,
308 uint16_t flags,
309 tevent_fd_handler_t handler,
310 void *private_data,
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)
324 if (!fde) return;
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,
331 int fd,
332 void *private_data)
334 close(fd);
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)
347 if (!fde) return 0;
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)
357 if (!fde) return;
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) {
365 return true;
367 return false;
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) {
383 abort();
386 tevent_abort_fn(reason);
390 add a timer event
391 return NULL on failure
393 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
394 TALLOC_CTX *mem_ctx,
395 struct timeval next_event,
396 tevent_timer_handler_t handler,
397 void *private_data,
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;
417 im->prev = NULL;
418 im->next = NULL;
419 im->event_ctx = NULL;
420 im->create_location = location;
421 im->handler = NULL;
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;
428 return im;
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,
437 void *private_data,
438 const char *handler_name,
439 const char *location)
441 ev->ops->schedule_immediate(im, ev, handler, private_data,
442 handler_name, location);
446 add a signal event
448 sa_flags are flags to sigaction(2)
450 return NULL on failure
452 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
453 TALLOC_CTX *mem_ctx,
454 int signum,
455 int sa_flags,
456 tevent_signal_handler_t handler,
457 void *private_data,
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,
472 void *private_data)
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
479 same time. */
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)
488 const char *reason;
490 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
491 location);
492 if (!reason) {
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)
504 int ret;
505 void *nesting_stack_ptr = NULL;
507 ev->nesting.level++;
509 if (ev->nesting.level > 1) {
510 if (!ev->nesting.allowed) {
511 tevent_abort_nesting(ev, location);
512 errno = ELOOP;
513 return -1;
516 if (ev->nesting.level > 0) {
517 if (ev->nesting.hook_fn) {
518 int ret2;
519 ret2 = ev->nesting.hook_fn(ev,
520 ev->nesting.hook_private,
521 ev->nesting.level,
522 true,
523 (void *)&nesting_stack_ptr,
524 location);
525 if (ret2 != 0) {
526 ret = ret2;
527 goto done;
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) {
538 int ret2;
539 ret2 = ev->nesting.hook_fn(ev,
540 ev->nesting.hook_private,
541 ev->nesting.level,
542 false,
543 (void *)&nesting_stack_ptr,
544 location);
545 if (ret2 != 0) {
546 ret = ret2;
547 goto done;
552 done:
553 ev->nesting.level--;
554 return ret;
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),
562 void *private_data,
563 const char *location)
565 int ret = 0;
566 void *nesting_stack_ptr = NULL;
568 ev->nesting.level++;
570 if (ev->nesting.level > 1) {
571 if (!ev->nesting.allowed) {
572 tevent_abort_nesting(ev, location);
573 errno = ELOOP;
574 return -1;
577 if (ev->nesting.level > 0) {
578 if (ev->nesting.hook_fn) {
579 int ret2;
580 ret2 = ev->nesting.hook_fn(ev,
581 ev->nesting.hook_private,
582 ev->nesting.level,
583 true,
584 (void *)&nesting_stack_ptr,
585 location);
586 if (ret2 != 0) {
587 ret = ret2;
588 goto done;
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);
597 if (ret != 0) {
598 break;
602 if (ev->nesting.level > 0) {
603 if (ev->nesting.hook_fn) {
604 int ret2;
605 ret2 = ev->nesting.hook_fn(ev,
606 ev->nesting.hook_private,
607 ev->nesting.level,
608 false,
609 (void *)&nesting_stack_ptr,
610 location);
611 if (ret2 != 0) {
612 ret = ret2;
613 goto done;
618 done:
619 ev->nesting.level--;
620 return ret;
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 ||
633 ev->timer_events ||
634 ev->immediate_events ||
635 ev->signal_events) {
636 int ret;
637 ret = _tevent_loop_once(ev, location);
638 if (ret != 0) {
639 tevent_debug(ev, TEVENT_DEBUG_FATAL,
640 "_tevent_loop_once() failed: %d - %s\n",
641 ret, strerror(errno));
642 return ret;
646 tevent_debug(ev, TEVENT_DEBUG_WARNING,
647 "tevent_common_loop_wait() out of events\n");
648 return 0;
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);