s3: Add SMB2 performance counters.
[Samba/gebeck_regimport.git] / lib / tevent / tevent.c
bloba91e56893123d90cd2a1f249162b426026557fef
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);
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);
188 return 0;
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;
206 int ret;
208 ev = talloc_zero(mem_ctx, struct tevent_context);
209 if (!ev) return NULL;
211 talloc_set_destructor(ev, tevent_common_context_destructor);
213 ev->ops = ops;
215 ret = ev->ops->context_init(ev);
216 if (ret != 0) {
217 talloc_free(ev);
218 return NULL;
221 return 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,
230 const char *name)
232 struct tevent_ops_list *e;
234 tevent_backend_init();
236 if (name == NULL) {
237 name = tevent_default_backend;
239 if (name == NULL) {
240 name = "standard";
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);
248 return NULL;
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);
263 add a fd based event
264 return NULL on failure (memory allocation error)
266 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
267 TALLOC_CTX *mem_ctx,
268 int fd,
269 uint16_t flags,
270 tevent_fd_handler_t handler,
271 void *private_data,
272 const char *handler_name,
273 const char *location)
275 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
276 handler_name, location);
280 set a close function on the fd event
282 void tevent_fd_set_close_fn(struct tevent_fd *fde,
283 tevent_fd_close_fn_t close_fn)
285 if (!fde) return;
286 if (!fde->event_ctx) return;
287 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
290 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
291 struct tevent_fd *fde,
292 int fd,
293 void *private_data)
295 close(fd);
298 void tevent_fd_set_auto_close(struct tevent_fd *fde)
300 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
304 return the fd event flags
306 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
308 if (!fde) return 0;
309 if (!fde->event_ctx) return 0;
310 return fde->event_ctx->ops->get_fd_flags(fde);
314 set the fd event flags
316 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
318 if (!fde) return;
319 if (!fde->event_ctx) return;
320 fde->event_ctx->ops->set_fd_flags(fde, flags);
323 bool tevent_signal_support(struct tevent_context *ev)
325 if (ev->ops->add_signal) {
326 return true;
328 return false;
331 static void (*tevent_abort_fn)(const char *reason);
333 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
335 tevent_abort_fn = abort_fn;
338 static void tevent_abort(struct tevent_context *ev, const char *reason)
340 tevent_debug(ev, TEVENT_DEBUG_FATAL,
341 "abort: %s\n", reason);
343 if (!tevent_abort_fn) {
344 abort();
347 tevent_abort_fn(reason);
351 add a timer event
352 return NULL on failure
354 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
355 TALLOC_CTX *mem_ctx,
356 struct timeval next_event,
357 tevent_timer_handler_t handler,
358 void *private_data,
359 const char *handler_name,
360 const char *location)
362 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
363 handler_name, location);
367 allocate an immediate event
368 return NULL on failure (memory allocation error)
370 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
371 const char *location)
373 struct tevent_immediate *im;
375 im = talloc(mem_ctx, struct tevent_immediate);
376 if (im == NULL) return NULL;
378 im->prev = NULL;
379 im->next = NULL;
380 im->event_ctx = NULL;
381 im->create_location = location;
382 im->handler = NULL;
383 im->private_data = NULL;
384 im->handler_name = NULL;
385 im->schedule_location = NULL;
386 im->cancel_fn = NULL;
387 im->additional_data = NULL;
389 return im;
393 schedule an immediate event
394 return NULL on failure
396 void _tevent_schedule_immediate(struct tevent_immediate *im,
397 struct tevent_context *ev,
398 tevent_immediate_handler_t handler,
399 void *private_data,
400 const char *handler_name,
401 const char *location)
403 ev->ops->schedule_immediate(im, ev, handler, private_data,
404 handler_name, location);
408 add a signal event
410 sa_flags are flags to sigaction(2)
412 return NULL on failure
414 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
415 TALLOC_CTX *mem_ctx,
416 int signum,
417 int sa_flags,
418 tevent_signal_handler_t handler,
419 void *private_data,
420 const char *handler_name,
421 const char *location)
423 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
424 handler_name, location);
427 void tevent_loop_allow_nesting(struct tevent_context *ev)
429 ev->nesting.allowed = true;
432 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
433 tevent_nesting_hook hook,
434 void *private_data)
436 if (ev->nesting.hook_fn &&
437 (ev->nesting.hook_fn != hook ||
438 ev->nesting.hook_private != private_data)) {
439 /* the way the nesting hook code is currently written
440 we cannot support two different nesting hooks at the
441 same time. */
442 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
444 ev->nesting.hook_fn = hook;
445 ev->nesting.hook_private = private_data;
448 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
450 const char *reason;
452 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
453 location);
454 if (!reason) {
455 reason = "tevent_loop_once() nesting";
458 tevent_abort(ev, reason);
462 do a single event loop using the events defined in ev
464 int _tevent_loop_once(struct tevent_context *ev, const char *location)
466 int ret;
467 void *nesting_stack_ptr = NULL;
469 ev->nesting.level++;
471 if (ev->nesting.level > 1) {
472 if (!ev->nesting.allowed) {
473 tevent_abort_nesting(ev, location);
474 errno = ELOOP;
475 return -1;
478 if (ev->nesting.level > 0) {
479 if (ev->nesting.hook_fn) {
480 int ret2;
481 ret2 = ev->nesting.hook_fn(ev,
482 ev->nesting.hook_private,
483 ev->nesting.level,
484 true,
485 (void *)&nesting_stack_ptr,
486 location);
487 if (ret2 != 0) {
488 ret = ret2;
489 goto done;
494 ret = ev->ops->loop_once(ev, location);
496 if (ev->nesting.level > 0) {
497 if (ev->nesting.hook_fn) {
498 int ret2;
499 ret2 = ev->nesting.hook_fn(ev,
500 ev->nesting.hook_private,
501 ev->nesting.level,
502 false,
503 (void *)&nesting_stack_ptr,
504 location);
505 if (ret2 != 0) {
506 ret = ret2;
507 goto done;
512 done:
513 ev->nesting.level--;
514 return ret;
518 this is a performance optimization for the samba4 nested event loop problems
520 int _tevent_loop_until(struct tevent_context *ev,
521 bool (*finished)(void *private_data),
522 void *private_data,
523 const char *location)
525 int ret = 0;
526 void *nesting_stack_ptr = NULL;
528 ev->nesting.level++;
530 if (ev->nesting.level > 1) {
531 if (!ev->nesting.allowed) {
532 tevent_abort_nesting(ev, location);
533 errno = ELOOP;
534 return -1;
537 if (ev->nesting.level > 0) {
538 if (ev->nesting.hook_fn) {
539 int ret2;
540 ret2 = ev->nesting.hook_fn(ev,
541 ev->nesting.hook_private,
542 ev->nesting.level,
543 true,
544 (void *)&nesting_stack_ptr,
545 location);
546 if (ret2 != 0) {
547 ret = ret2;
548 goto done;
553 while (!finished(private_data)) {
554 ret = ev->ops->loop_once(ev, location);
555 if (ret != 0) {
556 break;
560 if (ev->nesting.level > 0) {
561 if (ev->nesting.hook_fn) {
562 int ret2;
563 ret2 = ev->nesting.hook_fn(ev,
564 ev->nesting.hook_private,
565 ev->nesting.level,
566 false,
567 (void *)&nesting_stack_ptr,
568 location);
569 if (ret2 != 0) {
570 ret = ret2;
571 goto done;
576 done:
577 ev->nesting.level--;
578 return ret;
582 return on failure or (with 0) if all fd events are removed
584 int tevent_common_loop_wait(struct tevent_context *ev,
585 const char *location)
588 * loop as long as we have events pending
590 while (ev->fd_events ||
591 ev->timer_events ||
592 ev->immediate_events ||
593 ev->signal_events) {
594 int ret;
595 ret = _tevent_loop_once(ev, location);
596 if (ret != 0) {
597 tevent_debug(ev, TEVENT_DEBUG_FATAL,
598 "_tevent_loop_once() failed: %d - %s\n",
599 ret, strerror(errno));
600 return ret;
604 tevent_debug(ev, TEVENT_DEBUG_WARNING,
605 "tevent_common_loop_wait() out of events\n");
606 return 0;
610 return on failure or (with 0) if all fd events are removed
612 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
614 return ev->ops->loop_wait(ev, location);
619 re-initialise a tevent context. This leaves you with the same
620 event context, but all events are wiped and the structure is
621 re-initialised. This is most useful after a fork()
623 zero is returned on success, non-zero on failure
625 int tevent_re_initialise(struct tevent_context *ev)
627 tevent_common_context_destructor(ev);
629 return ev->ops->context_init(ev);