s4:samba_upgradedns: delete dns-HOSTNAME account if using the internal dns server
[Samba/gbeck.git] / lib / tevent / tevent.c
blobfa842e42086bc88d033f71df41ea9c6c991548b6
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 tevent_select_init();
116 tevent_poll_init();
117 tevent_poll_mt_init();
118 tevent_standard_init();
119 #ifdef HAVE_EPOLL
120 tevent_epoll_init();
121 #endif
125 list available backends
127 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
129 const char **list = NULL;
130 struct tevent_ops_list *e;
132 tevent_backend_init();
134 for (e=tevent_backends;e;e=e->next) {
135 list = ev_str_list_add(list, e->name);
138 talloc_steal(mem_ctx, list);
140 return list;
143 int tevent_common_context_destructor(struct tevent_context *ev)
145 struct tevent_fd *fd, *fn;
146 struct tevent_timer *te, *tn;
147 struct tevent_immediate *ie, *in;
148 struct tevent_signal *se, *sn;
150 if (ev->pipe_fde) {
151 talloc_free(ev->pipe_fde);
152 close(ev->pipe_fds[0]);
153 close(ev->pipe_fds[1]);
154 ev->pipe_fde = NULL;
157 for (fd = ev->fd_events; fd; fd = fn) {
158 fn = fd->next;
159 fd->event_ctx = NULL;
160 DLIST_REMOVE(ev->fd_events, fd);
163 for (te = ev->timer_events; te; te = tn) {
164 tn = te->next;
165 te->event_ctx = NULL;
166 DLIST_REMOVE(ev->timer_events, te);
169 for (ie = ev->immediate_events; ie; ie = in) {
170 in = ie->next;
171 ie->event_ctx = NULL;
172 ie->cancel_fn = NULL;
173 DLIST_REMOVE(ev->immediate_events, ie);
176 for (se = ev->signal_events; se; se = sn) {
177 sn = se->next;
178 se->event_ctx = NULL;
179 DLIST_REMOVE(ev->signal_events, se);
181 * This is important, Otherwise signals
182 * are handled twice in child. eg, SIGHUP.
183 * one added in parent, and another one in
184 * the child. -- BoYang
186 tevent_cleanup_pending_signal_handlers(se);
189 /* removing nesting hook or we get an abort when nesting is
190 * not allowed. -- SSS
191 * Note that we need to leave the allowed flag at its current
192 * value, otherwise the use in tevent_re_initialise() will
193 * leave the event context with allowed forced to false, which
194 * will break users that expect nesting to be allowed
196 ev->nesting.level = 0;
197 ev->nesting.hook_fn = NULL;
198 ev->nesting.hook_private = NULL;
200 return 0;
204 create a event_context structure for a specific implemementation.
205 This must be the first events call, and all subsequent calls pass
206 this event_context as the first element. Event handlers also
207 receive this as their first argument.
209 This function is for allowing third-party-applications to hook in gluecode
210 to their own event loop code, so that they can make async usage of our client libs
212 NOTE: use tevent_context_init() inside of samba!
214 struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
215 const struct tevent_ops *ops,
216 void *additional_data)
218 struct tevent_context *ev;
219 int ret;
221 ev = talloc_zero(mem_ctx, struct tevent_context);
222 if (!ev) return NULL;
224 talloc_set_destructor(ev, tevent_common_context_destructor);
226 ev->ops = ops;
227 ev->additional_data = additional_data;
229 ret = ev->ops->context_init(ev);
230 if (ret != 0) {
231 talloc_free(ev);
232 return NULL;
235 return ev;
239 create a event_context structure. This must be the first events
240 call, and all subsequent calls pass this event_context as the first
241 element. Event handlers also receive this as their first argument.
243 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
244 const char *name)
246 struct tevent_ops_list *e;
248 tevent_backend_init();
250 if (name == NULL) {
251 name = tevent_default_backend;
253 if (name == NULL) {
254 name = "standard";
257 for (e=tevent_backends;e;e=e->next) {
258 if (strcmp(name, e->name) == 0) {
259 return tevent_context_init_ops(mem_ctx, e->ops, NULL);
262 return NULL;
267 create a event_context structure. This must be the first events
268 call, and all subsequent calls pass this event_context as the first
269 element. Event handlers also receive this as their first argument.
271 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
273 return tevent_context_init_byname(mem_ctx, NULL);
277 add a fd based event
278 return NULL on failure (memory allocation error)
280 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
281 TALLOC_CTX *mem_ctx,
282 int fd,
283 uint16_t flags,
284 tevent_fd_handler_t handler,
285 void *private_data,
286 const char *handler_name,
287 const char *location)
289 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
290 handler_name, location);
294 set a close function on the fd event
296 void tevent_fd_set_close_fn(struct tevent_fd *fde,
297 tevent_fd_close_fn_t close_fn)
299 if (!fde) return;
300 if (!fde->event_ctx) return;
301 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
304 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
305 struct tevent_fd *fde,
306 int fd,
307 void *private_data)
309 close(fd);
312 void tevent_fd_set_auto_close(struct tevent_fd *fde)
314 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
318 return the fd event flags
320 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
322 if (!fde) return 0;
323 if (!fde->event_ctx) return 0;
324 return fde->event_ctx->ops->get_fd_flags(fde);
328 set the fd event flags
330 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
332 if (!fde) return;
333 if (!fde->event_ctx) return;
334 fde->event_ctx->ops->set_fd_flags(fde, flags);
337 bool tevent_signal_support(struct tevent_context *ev)
339 if (ev->ops->add_signal) {
340 return true;
342 return false;
345 static void (*tevent_abort_fn)(const char *reason);
347 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
349 tevent_abort_fn = abort_fn;
352 static void tevent_abort(struct tevent_context *ev, const char *reason)
354 tevent_debug(ev, TEVENT_DEBUG_FATAL,
355 "abort: %s\n", reason);
357 if (!tevent_abort_fn) {
358 abort();
361 tevent_abort_fn(reason);
365 add a timer event
366 return NULL on failure
368 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
369 TALLOC_CTX *mem_ctx,
370 struct timeval next_event,
371 tevent_timer_handler_t handler,
372 void *private_data,
373 const char *handler_name,
374 const char *location)
376 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
377 handler_name, location);
381 allocate an immediate event
382 return NULL on failure (memory allocation error)
384 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
385 const char *location)
387 struct tevent_immediate *im;
389 im = talloc(mem_ctx, struct tevent_immediate);
390 if (im == NULL) return NULL;
392 im->prev = NULL;
393 im->next = NULL;
394 im->event_ctx = NULL;
395 im->create_location = location;
396 im->handler = NULL;
397 im->private_data = NULL;
398 im->handler_name = NULL;
399 im->schedule_location = NULL;
400 im->cancel_fn = NULL;
401 im->additional_data = NULL;
403 return im;
407 schedule an immediate event
409 void _tevent_schedule_immediate(struct tevent_immediate *im,
410 struct tevent_context *ev,
411 tevent_immediate_handler_t handler,
412 void *private_data,
413 const char *handler_name,
414 const char *location)
416 ev->ops->schedule_immediate(im, ev, handler, private_data,
417 handler_name, location);
421 add a signal event
423 sa_flags are flags to sigaction(2)
425 return NULL on failure
427 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
428 TALLOC_CTX *mem_ctx,
429 int signum,
430 int sa_flags,
431 tevent_signal_handler_t handler,
432 void *private_data,
433 const char *handler_name,
434 const char *location)
436 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
437 handler_name, location);
440 void tevent_loop_allow_nesting(struct tevent_context *ev)
442 ev->nesting.allowed = true;
445 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
446 tevent_nesting_hook hook,
447 void *private_data)
449 if (ev->nesting.hook_fn &&
450 (ev->nesting.hook_fn != hook ||
451 ev->nesting.hook_private != private_data)) {
452 /* the way the nesting hook code is currently written
453 we cannot support two different nesting hooks at the
454 same time. */
455 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
457 ev->nesting.hook_fn = hook;
458 ev->nesting.hook_private = private_data;
461 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
463 const char *reason;
465 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
466 location);
467 if (!reason) {
468 reason = "tevent_loop_once() nesting";
471 tevent_abort(ev, reason);
475 do a single event loop using the events defined in ev
477 int _tevent_loop_once(struct tevent_context *ev, const char *location)
479 int ret;
480 void *nesting_stack_ptr = NULL;
482 ev->nesting.level++;
484 if (ev->nesting.level > 1) {
485 if (!ev->nesting.allowed) {
486 tevent_abort_nesting(ev, location);
487 errno = ELOOP;
488 return -1;
491 if (ev->nesting.level > 0) {
492 if (ev->nesting.hook_fn) {
493 int ret2;
494 ret2 = ev->nesting.hook_fn(ev,
495 ev->nesting.hook_private,
496 ev->nesting.level,
497 true,
498 (void *)&nesting_stack_ptr,
499 location);
500 if (ret2 != 0) {
501 ret = ret2;
502 goto done;
507 ret = ev->ops->loop_once(ev, location);
509 if (ev->nesting.level > 0) {
510 if (ev->nesting.hook_fn) {
511 int ret2;
512 ret2 = ev->nesting.hook_fn(ev,
513 ev->nesting.hook_private,
514 ev->nesting.level,
515 false,
516 (void *)&nesting_stack_ptr,
517 location);
518 if (ret2 != 0) {
519 ret = ret2;
520 goto done;
525 done:
526 ev->nesting.level--;
527 return ret;
531 this is a performance optimization for the samba4 nested event loop problems
533 int _tevent_loop_until(struct tevent_context *ev,
534 bool (*finished)(void *private_data),
535 void *private_data,
536 const char *location)
538 int ret = 0;
539 void *nesting_stack_ptr = NULL;
541 ev->nesting.level++;
543 if (ev->nesting.level > 1) {
544 if (!ev->nesting.allowed) {
545 tevent_abort_nesting(ev, location);
546 errno = ELOOP;
547 return -1;
550 if (ev->nesting.level > 0) {
551 if (ev->nesting.hook_fn) {
552 int ret2;
553 ret2 = ev->nesting.hook_fn(ev,
554 ev->nesting.hook_private,
555 ev->nesting.level,
556 true,
557 (void *)&nesting_stack_ptr,
558 location);
559 if (ret2 != 0) {
560 ret = ret2;
561 goto done;
566 while (!finished(private_data)) {
567 ret = ev->ops->loop_once(ev, location);
568 if (ret != 0) {
569 break;
573 if (ev->nesting.level > 0) {
574 if (ev->nesting.hook_fn) {
575 int ret2;
576 ret2 = ev->nesting.hook_fn(ev,
577 ev->nesting.hook_private,
578 ev->nesting.level,
579 false,
580 (void *)&nesting_stack_ptr,
581 location);
582 if (ret2 != 0) {
583 ret = ret2;
584 goto done;
589 done:
590 ev->nesting.level--;
591 return ret;
595 return on failure or (with 0) if all fd events are removed
597 int tevent_common_loop_wait(struct tevent_context *ev,
598 const char *location)
601 * loop as long as we have events pending
603 while (ev->fd_events ||
604 ev->timer_events ||
605 ev->immediate_events ||
606 ev->signal_events) {
607 int ret;
608 ret = _tevent_loop_once(ev, location);
609 if (ret != 0) {
610 tevent_debug(ev, TEVENT_DEBUG_FATAL,
611 "_tevent_loop_once() failed: %d - %s\n",
612 ret, strerror(errno));
613 return ret;
617 tevent_debug(ev, TEVENT_DEBUG_WARNING,
618 "tevent_common_loop_wait() out of events\n");
619 return 0;
623 return on failure or (with 0) if all fd events are removed
625 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
627 return ev->ops->loop_wait(ev, location);
632 re-initialise a tevent context. This leaves you with the same
633 event context, but all events are wiped and the structure is
634 re-initialised. This is most useful after a fork()
636 zero is returned on success, non-zero on failure
638 int tevent_re_initialise(struct tevent_context *ev)
640 tevent_common_context_destructor(ev);
642 return ev->ops->context_init(ev);