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();
118 list available backends
120 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
122 const char **list = NULL;
123 struct tevent_ops_list *e;
125 tevent_backend_init();
127 for (e=tevent_backends;e;e=e->next) {
128 list = ev_str_list_add(list, e->name);
131 talloc_steal(mem_ctx, list);
136 int tevent_common_context_destructor(struct tevent_context *ev)
138 struct tevent_fd *fd, *fn;
139 struct tevent_timer *te, *tn;
140 struct tevent_signal *se, *sn;
143 talloc_free(ev->pipe_fde);
147 for (fd = ev->fd_events; fd; fd = fn) {
149 fd->event_ctx = NULL;
150 DLIST_REMOVE(ev->fd_events, fd);
153 for (te = ev->timer_events; te; te = tn) {
155 te->event_ctx = NULL;
156 DLIST_REMOVE(ev->timer_events, te);
159 for (se = ev->signal_events; se; se = sn) {
161 se->event_ctx = NULL;
162 DLIST_REMOVE(ev->signal_events, se);
169 create a event_context structure for a specific implemementation.
170 This must be the first events call, and all subsequent calls pass
171 this event_context as the first element. Event handlers also
172 receive this as their first argument.
174 This function is for allowing third-party-applications to hook in gluecode
175 to their own event loop code, so that they can make async usage of our client libs
177 NOTE: use tevent_context_init() inside of samba!
179 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
180 const struct tevent_ops *ops)
182 struct tevent_context *ev;
185 ev = talloc_zero(mem_ctx, struct tevent_context);
186 if (!ev) return NULL;
188 talloc_set_destructor(ev, tevent_common_context_destructor);
192 ret = ev->ops->context_init(ev);
202 create a event_context structure. This must be the first events
203 call, and all subsequent calls pass this event_context as the first
204 element. Event handlers also receive this as their first argument.
206 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
209 struct tevent_ops_list *e;
211 tevent_backend_init();
214 name = tevent_default_backend;
220 for (e=tevent_backends;e;e=e->next) {
221 if (strcmp(name, e->name) == 0) {
222 return tevent_context_init_ops(mem_ctx, e->ops);
230 create a event_context structure. This must be the first events
231 call, and all subsequent calls pass this event_context as the first
232 element. Event handlers also receive this as their first argument.
234 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
236 return tevent_context_init_byname(mem_ctx, NULL);
241 return NULL on failure (memory allocation error)
243 if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
244 the returned fd_event context is freed
246 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
250 tevent_fd_handler_t handler,
252 const char *handler_name,
253 const char *location)
255 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
256 handler_name, location);
260 set a close function on the fd event
262 void tevent_fd_set_close_fn(struct tevent_fd *fde,
263 tevent_fd_close_fn_t close_fn)
266 if (!fde->event_ctx) return;
267 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
270 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
271 struct tevent_fd *fde,
278 void tevent_fd_set_auto_close(struct tevent_fd *fde)
280 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
284 return the fd event flags
286 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
289 if (!fde->event_ctx) return 0;
290 return fde->event_ctx->ops->get_fd_flags(fde);
294 set the fd event flags
296 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
299 if (!fde->event_ctx) return;
300 fde->event_ctx->ops->set_fd_flags(fde, flags);
305 return NULL on failure
307 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
309 struct timeval next_event,
310 tevent_timer_handler_t handler,
312 const char *handler_name,
313 const char *location)
315 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
316 handler_name, location);
322 sa_flags are flags to sigaction(2)
324 return NULL on failure
326 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
330 tevent_signal_handler_t handler,
332 const char *handler_name,
333 const char *location)
335 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
336 handler_name, location);
340 do a single event loop using the events defined in ev
342 int tevent_loop_once(struct tevent_context *ev)
344 return ev->ops->loop_once(ev);
348 return on failure or (with 0) if all fd events are removed
350 int tevent_loop_wait(struct tevent_context *ev)
352 return ev->ops->loop_wait(ev);