2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 PLEASE READ THIS BEFORE MODIFYING!
23 This module is a general abstraction for the main select loop and
24 event handling. Do not ever put any localised hacks in here, instead
25 register one of the possible event types and implement that event
28 There are 2 types of event handling that are handled in this module:
30 1) a file descriptor becoming readable or writeable. This is mostly
31 used for network sockets, but can be used for any type of file
32 descriptor. You may only register one handler for each file
33 descriptor/io combination or you will get unpredictable results
34 (this means that you can have a handler for read events, and a
35 separate handler for write events, but not two handlers that are
36 both handling read events)
38 2) a timed event. You can register an event that happens at a
39 specific time. You can register as many of these as you
40 like. They are single shot - add a new timed event in the event
41 handler to get another event.
43 To setup a set of events you first need to create a event_context
44 structure using the function tevent_context_init(); This returns a
45 'struct tevent_context' that you use in all subsequent calls.
47 After that you can add/remove events that you are interested in
48 using tevent_add_*() and talloc_free()
50 Finally, you call tevent_loop_wait_once() to block waiting for one of the
51 events to occor or tevent_loop_wait() which will loop
56 #include "system/filesys.h"
58 #include "tevent_internal.h"
59 #include "tevent_util.h"
61 struct tevent_ops_list {
62 struct tevent_ops_list *next, *prev;
64 const struct tevent_ops *ops;
67 /* list of registered event backends */
68 static struct tevent_ops_list *tevent_backends = NULL;
69 static char *tevent_default_backend = NULL;
72 register an events backend
74 bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
76 struct tevent_ops_list *e;
78 for (e = tevent_backends; e != NULL; e = e->next) {
79 if (0 == strcmp(e->name, name)) {
80 /* already registered, skip it */
85 e = talloc(talloc_autofree_context(), struct tevent_ops_list);
86 if (e == NULL) return false;
90 DLIST_ADD(tevent_backends, e);
96 set the default event backend
98 void tevent_set_default_backend(const char *backend)
100 talloc_free(tevent_default_backend);
101 tevent_default_backend = talloc_strdup(talloc_autofree_context(),
106 initialise backends if not already done
108 static void tevent_backend_init(void)
110 tevent_select_init();
111 tevent_standard_init();
115 #ifdef HAVE_LINUX_AIO
121 list available backends
123 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
125 const char **list = NULL;
126 struct tevent_ops_list *e;
128 tevent_backend_init();
130 for (e=tevent_backends;e;e=e->next) {
131 list = ev_str_list_add(list, e->name);
134 talloc_steal(mem_ctx, list);
139 int tevent_common_context_destructor(struct tevent_context *ev)
141 struct tevent_fd *fd;
142 struct tevent_timer *te;
143 struct tevent_signal *se;
146 talloc_free(ev->pipe_fde);
152 fd->event_ctx = NULL;
153 DLIST_REMOVE(ev->fd_events, fd);
157 te = ev->timer_events;
159 te->event_ctx = NULL;
160 DLIST_REMOVE(ev->timer_events, te);
161 te = ev->timer_events;
164 se = ev->signal_events;
166 se->event_ctx = NULL;
167 DLIST_REMOVE(ev->signal_events, se);
168 se = ev->signal_events;
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;
191 ev = talloc_zero(mem_ctx, struct tevent_context);
192 if (!ev) return NULL;
194 talloc_set_destructor(ev, tevent_common_context_destructor);
198 ret = ev->ops->context_init(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,
215 struct tevent_ops_list *e;
217 tevent_backend_init();
220 name = tevent_default_backend;
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);
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);
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,
256 tevent_fd_handler_t handler,
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);
268 struct tevent_aio *_tevent_add_aio(struct tevent_context *ev,
271 tevent_aio_handler_t handler,
273 const char *handler_name,
274 const char *location)
276 if (ev->ops->add_aio == NULL) return NULL;
277 return ev->ops->add_aio(ev, mem_ctx, iocb, handler, private_data,
278 handler_name, location);
282 set a close function on the fd event
284 void tevent_fd_set_close_fn(struct tevent_fd *fde,
285 tevent_fd_close_fn_t close_fn)
288 if (!fde->event_ctx) return;
289 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
292 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
293 struct tevent_fd *fde,
300 void tevent_fd_set_auto_close(struct tevent_fd *fde)
302 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
306 return the fd event flags
308 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
311 if (!fde->event_ctx) return 0;
312 return fde->event_ctx->ops->get_fd_flags(fde);
316 set the fd event flags
318 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
321 if (!fde->event_ctx) return;
322 fde->event_ctx->ops->set_fd_flags(fde, flags);
327 return NULL on failure
329 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
331 struct timeval next_event,
332 tevent_timer_handler_t handler,
334 const char *handler_name,
335 const char *location)
337 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
338 handler_name, location);
344 sa_flags are flags to sigaction(2)
346 return NULL on failure
348 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
352 tevent_signal_handler_t handler,
354 const char *handler_name,
355 const char *location)
357 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
358 handler_name, location);
362 do a single event loop using the events defined in ev
364 int tevent_loop_once(struct tevent_context *ev)
366 return ev->ops->loop_once(ev);
370 return on failure or (with 0) if all fd events are removed
372 int tevent_loop_wait(struct tevent_context *ev)
374 return ev->ops->loop_wait(ev);