tevent: Fix might be unitialized warning
[Samba.git] / lib / tevent / tevent.c
blob867cfc08feff88c3532a98f76c94d1f5b8fb0e47
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_signal *se, *sn;
148 if (ev->pipe_fde) {
149 talloc_free(ev->pipe_fde);
150 ev->pipe_fde = NULL;
153 for (fd = ev->fd_events; fd; fd = fn) {
154 fn = fd->next;
155 fd->event_ctx = NULL;
156 DLIST_REMOVE(ev->fd_events, fd);
159 for (te = ev->timer_events; te; te = tn) {
160 tn = te->next;
161 te->event_ctx = NULL;
162 DLIST_REMOVE(ev->timer_events, te);
165 for (se = ev->signal_events; se; se = sn) {
166 sn = se->next;
167 se->event_ctx = NULL;
168 DLIST_REMOVE(ev->signal_events, se);
171 return 0;
175 create a event_context structure for a specific implemementation.
176 This must be the first events call, and all subsequent calls pass
177 this event_context as the first element. Event handlers also
178 receive this as their first argument.
180 This function is for allowing third-party-applications to hook in gluecode
181 to their own event loop code, so that they can make async usage of our client libs
183 NOTE: use tevent_context_init() inside of samba!
185 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
186 const struct tevent_ops *ops)
188 struct tevent_context *ev;
189 int ret;
191 ev = talloc_zero(mem_ctx, struct tevent_context);
192 if (!ev) return NULL;
194 talloc_set_destructor(ev, tevent_common_context_destructor);
196 ev->ops = ops;
198 ret = ev->ops->context_init(ev);
199 if (ret != 0) {
200 talloc_free(ev);
201 return NULL;
204 return ev;
208 create a event_context structure. This must be the first events
209 call, and all subsequent calls pass this event_context as the first
210 element. Event handlers also receive this as their first argument.
212 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
213 const char *name)
215 struct tevent_ops_list *e;
217 tevent_backend_init();
219 if (name == NULL) {
220 name = tevent_default_backend;
222 if (name == NULL) {
223 name = "standard";
226 for (e=tevent_backends;e;e=e->next) {
227 if (strcmp(name, e->name) == 0) {
228 return tevent_context_init_ops(mem_ctx, e->ops);
231 return NULL;
236 create a event_context structure. This must be the first events
237 call, and all subsequent calls pass this event_context as the first
238 element. Event handlers also receive this as their first argument.
240 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
242 return tevent_context_init_byname(mem_ctx, NULL);
246 add a fd based event
247 return NULL on failure (memory allocation error)
249 if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
250 the returned fd_event context is freed
252 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
253 TALLOC_CTX *mem_ctx,
254 int fd,
255 uint16_t flags,
256 tevent_fd_handler_t handler,
257 void *private_data,
258 const char *handler_name,
259 const char *location)
261 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
262 handler_name, location);
266 set a close function on the fd event
268 void tevent_fd_set_close_fn(struct tevent_fd *fde,
269 tevent_fd_close_fn_t close_fn)
271 if (!fde) return;
272 if (!fde->event_ctx) return;
273 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
276 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
277 struct tevent_fd *fde,
278 int fd,
279 void *private_data)
281 close(fd);
284 void tevent_fd_set_auto_close(struct tevent_fd *fde)
286 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
290 return the fd event flags
292 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
294 if (!fde) return 0;
295 if (!fde->event_ctx) return 0;
296 return fde->event_ctx->ops->get_fd_flags(fde);
300 set the fd event flags
302 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
304 if (!fde) return;
305 if (!fde->event_ctx) return;
306 fde->event_ctx->ops->set_fd_flags(fde, flags);
309 bool tevent_signal_support(struct tevent_context *ev)
311 if (ev->ops->add_signal) {
312 return true;
314 return false;
317 static void (*tevent_abort_fn)(const char *reason);
319 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
321 tevent_abort_fn = abort_fn;
324 static void tevent_abort(struct tevent_context *ev, const char *reason)
326 tevent_debug(ev, TEVENT_DEBUG_FATAL,
327 "abort: %s\n", reason);
329 if (!tevent_abort_fn) {
330 abort();
333 tevent_abort_fn(reason);
337 add a timer event
338 return NULL on failure
340 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
341 TALLOC_CTX *mem_ctx,
342 struct timeval next_event,
343 tevent_timer_handler_t handler,
344 void *private_data,
345 const char *handler_name,
346 const char *location)
348 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
349 handler_name, location);
353 add a signal event
355 sa_flags are flags to sigaction(2)
357 return NULL on failure
359 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
360 TALLOC_CTX *mem_ctx,
361 int signum,
362 int sa_flags,
363 tevent_signal_handler_t handler,
364 void *private_data,
365 const char *handler_name,
366 const char *location)
368 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
369 handler_name, location);
372 void tevent_loop_allow_nesting(struct tevent_context *ev)
374 ev->nesting.allowed = true;
377 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
378 tevent_nesting_hook hook,
379 void *private_data)
381 ev->nesting.hook_fn = hook;
382 ev->nesting.hook_private = private_data;
385 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
387 const char *reason;
389 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
390 location);
391 if (!reason) {
392 reason = "tevent_loop_once() nesting";
395 tevent_abort(ev, reason);
399 do a single event loop using the events defined in ev
401 int _tevent_loop_once(struct tevent_context *ev, const char *location)
403 int ret;
404 void *nesting_stack_ptr = NULL;
406 ev->nesting.level++;
408 if (ev->nesting.level > 1) {
409 if (!ev->nesting.allowed) {
410 tevent_abort_nesting(ev, location);
411 errno = ELOOP;
412 return -1;
414 if (ev->nesting.hook_fn) {
415 int ret2;
416 ret2 = ev->nesting.hook_fn(ev,
417 ev->nesting.hook_private,
418 ev->nesting.level,
419 true,
420 (void *)&nesting_stack_ptr,
421 location);
422 if (ret2 != 0) {
423 ret = ret2;
424 goto done;
429 ret = ev->ops->loop_once(ev, location);
431 if (ev->nesting.level > 1) {
432 if (ev->nesting.hook_fn) {
433 int ret2;
434 ret2 = ev->nesting.hook_fn(ev,
435 ev->nesting.hook_private,
436 ev->nesting.level,
437 false,
438 (void *)&nesting_stack_ptr,
439 location);
440 if (ret2 != 0) {
441 ret = ret2;
442 goto done;
447 done:
448 ev->nesting.level--;
449 return ret;
453 this is a performance optimization for the samba4 nested event loop problems
455 int _tevent_loop_until(struct tevent_context *ev,
456 bool (*finished)(void *private_data),
457 void *private_data,
458 const char *location)
460 int ret = 0;
461 void *nesting_stack_ptr = NULL;
463 ev->nesting.level++;
465 if (ev->nesting.level > 1) {
466 if (!ev->nesting.allowed) {
467 tevent_abort_nesting(ev, location);
468 errno = ELOOP;
469 return -1;
471 if (ev->nesting.hook_fn) {
472 int ret2;
473 ret2 = ev->nesting.hook_fn(ev,
474 ev->nesting.hook_private,
475 ev->nesting.level,
476 true,
477 (void *)&nesting_stack_ptr,
478 location);
479 if (ret2 != 0) {
480 ret = ret2;
481 goto done;
486 while (!finished(private_data)) {
487 ret = ev->ops->loop_once(ev, location);
488 if (ret != 0) {
489 break;
493 if (ev->nesting.level > 1) {
494 if (ev->nesting.hook_fn) {
495 int ret2;
496 ret2 = ev->nesting.hook_fn(ev,
497 ev->nesting.hook_private,
498 ev->nesting.level,
499 false,
500 (void *)&nesting_stack_ptr,
501 location);
502 if (ret2 != 0) {
503 ret = ret2;
504 goto done;
509 done:
510 ev->nesting.level--;
511 return ret;
515 return on failure or (with 0) if all fd events are removed
517 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
519 return ev->ops->loop_wait(ev, location);