tevent: add tevent_context destructor that unlinks the events from the context
[kai/samba-autobuild/.git] / lib / tevent / tevent.c
1 /* 
2    Unix SMB/CIFS implementation.
3    main select loop and event handling
4    Copyright (C) Andrew Tridgell 2003
5    
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.
10    
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.
15    
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/>.
18 */
19
20 /*
21   PLEASE READ THIS BEFORE MODIFYING!
22
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
26   somewhere else.
27
28   There are 2 types of event handling that are handled in this module:
29
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)
37
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.
42
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.
46
47   After that you can add/remove events that you are interested in
48   using tevent_add_*() and talloc_free()
49
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
52   forever.
53
54 */
55 #include "replace.h"
56 #include "system/filesys.h"
57 #include "tevent.h"
58 #include "tevent_internal.h"
59 #include "tevent_util.h"
60
61 struct tevent_ops_list {
62         struct tevent_ops_list *next, *prev;
63         const char *name;
64         const struct tevent_ops *ops;
65 };
66
67 /* list of registered event backends */
68 static struct tevent_ops_list *tevent_backends = NULL;
69 static char *tevent_default_backend = NULL;
70
71 /*
72   register an events backend
73 */
74 bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
75 {
76         struct tevent_ops_list *e;
77
78         for (e = tevent_backends; e != NULL; e = e->next) {
79                 if (0 == strcmp(e->name, name)) {
80                         /* already registered, skip it */
81                         return true;
82                 }
83         }
84
85         e = talloc(talloc_autofree_context(), struct tevent_ops_list);
86         if (e == NULL) return false;
87
88         e->name = name;
89         e->ops = ops;
90         DLIST_ADD(tevent_backends, e);
91
92         return true;
93 }
94
95 /*
96   set the default event backend
97  */
98 void tevent_set_default_backend(const char *backend)
99 {
100         talloc_free(tevent_default_backend);
101         tevent_default_backend = talloc_strdup(talloc_autofree_context(),
102                                                backend);
103 }
104
105 /*
106   initialise backends if not already done
107 */
108 static void tevent_backend_init(void)
109 {
110         tevent_select_init();
111         tevent_standard_init();
112 #ifdef HAVE_EPOLL
113         tevent_epoll_init();
114 #endif
115 #ifdef HAVE_LINUX_AIO
116         tevent_aio_init();
117 #endif
118 }
119
120 /*
121   list available backends
122 */
123 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
124 {
125         const char **list = NULL;
126         struct tevent_ops_list *e;
127
128         tevent_backend_init();
129
130         for (e=tevent_backends;e;e=e->next) {
131                 list = ev_str_list_add(list, e->name);
132         }
133
134         talloc_steal(mem_ctx, list);
135
136         return list;
137 }
138
139 int tevent_common_context_destructor(struct tevent_context *ev)
140 {
141         struct tevent_fd *fd;
142         struct tevent_timer *te;
143         struct tevent_signal *se;
144
145         if (ev->pipe_fde) {
146                 talloc_free(ev->pipe_fde);
147                 ev->pipe_fde = NULL;
148         }
149
150         for (fd=ev->fd_events; fd; fd = fd->next) {
151                 fd->event_ctx = NULL;
152                 DLIST_REMOVE(ev->fd_events, fd);
153         }
154
155         for (te=ev->timer_events; te; te = te->next) {
156                 te->event_ctx = NULL;
157                 DLIST_REMOVE(ev->timer_events, te);
158         }
159
160         for (se=ev->signal_events; se; se = se->next) {
161                 se->event_ctx = NULL;
162                 DLIST_REMOVE(ev->signal_events, se);
163         }
164
165         return 0;
166 }
167
168 /*
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.
173
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
176
177   NOTE: use tevent_context_init() inside of samba!
178 */
179 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
180                                                       const struct tevent_ops *ops)
181 {
182         struct tevent_context *ev;
183         int ret;
184
185         ev = talloc_zero(mem_ctx, struct tevent_context);
186         if (!ev) return NULL;
187
188         talloc_set_destructor(ev, tevent_common_context_destructor);
189
190         ev->ops = ops;
191
192         ret = ev->ops->context_init(ev);
193         if (ret != 0) {
194                 talloc_free(ev);
195                 return NULL;
196         }
197
198         return ev;
199 }
200
201 /*
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.
205 */
206 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
207                                                   const char *name)
208 {
209         struct tevent_ops_list *e;
210
211         tevent_backend_init();
212
213         if (name == NULL) {
214                 name = tevent_default_backend;
215         }
216         if (name == NULL) {
217                 name = "standard";
218         }
219
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);
223                 }
224         }
225         return NULL;
226 }
227
228
229 /*
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.
233 */
234 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
235 {
236         return tevent_context_init_byname(mem_ctx, NULL);
237 }
238
239 /*
240   add a fd based event
241   return NULL on failure (memory allocation error)
242
243   if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
244   the returned fd_event context is freed
245 */
246 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
247                                  TALLOC_CTX *mem_ctx,
248                                  int fd,
249                                  uint16_t flags,
250                                  tevent_fd_handler_t handler,
251                                  void *private_data,
252                                  const char *handler_name,
253                                  const char *location)
254 {
255         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
256                                handler_name, location);
257 }
258
259 /*
260   add a disk aio event
261 */
262 struct tevent_aio *_tevent_add_aio(struct tevent_context *ev,
263                                    TALLOC_CTX *mem_ctx,
264                                    struct iocb *iocb,
265                                    tevent_aio_handler_t handler,
266                                    void *private_data,
267                                    const char *handler_name,
268                                    const char *location)
269 {
270         if (ev->ops->add_aio == NULL) return NULL;
271         return ev->ops->add_aio(ev, mem_ctx, iocb, handler, private_data,
272                                 handler_name, location);
273 }
274
275 /*
276   set a close function on the fd event
277 */
278 void tevent_fd_set_close_fn(struct tevent_fd *fde,
279                             tevent_fd_close_fn_t close_fn)
280 {
281         if (!fde) return;
282         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
283 }
284
285 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
286                                     struct tevent_fd *fde,
287                                     int fd,
288                                     void *private_data)
289 {
290         close(fd);
291 }
292
293 void tevent_fd_set_auto_close(struct tevent_fd *fde)
294 {
295         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
296 }
297
298 /*
299   return the fd event flags
300 */
301 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
302 {
303         if (!fde) return 0;
304         return fde->event_ctx->ops->get_fd_flags(fde);
305 }
306
307 /*
308   set the fd event flags
309 */
310 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
311 {
312         if (!fde) return;
313         fde->event_ctx->ops->set_fd_flags(fde, flags);
314 }
315
316 /*
317   add a timer event
318   return NULL on failure
319 */
320 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
321                                        TALLOC_CTX *mem_ctx,
322                                        struct timeval next_event,
323                                        tevent_timer_handler_t handler,
324                                        void *private_data,
325                                        const char *handler_name,
326                                        const char *location)
327 {
328         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
329                                   handler_name, location);
330 }
331
332 /*
333   add a signal event
334
335   sa_flags are flags to sigaction(2)
336
337   return NULL on failure
338 */
339 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
340                                          TALLOC_CTX *mem_ctx,
341                                          int signum,
342                                          int sa_flags,
343                                          tevent_signal_handler_t handler,
344                                          void *private_data,
345                                          const char *handler_name,
346                                          const char *location)
347 {
348         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
349                                    handler_name, location);
350 }
351
352 /*
353   do a single event loop using the events defined in ev 
354 */
355 int tevent_loop_once(struct tevent_context *ev)
356 {
357         return ev->ops->loop_once(ev);
358 }
359
360 /*
361   return on failure or (with 0) if all fd events are removed
362 */
363 int tevent_loop_wait(struct tevent_context *ev)
364 {
365         return ev->ops->loop_wait(ev);
366 }