fa8219e2348e4f48b8a1b892dd106f5fc1808097
[tprouty/samba.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         fd = ev->fd_events;
151         while (fd) {
152                 fd->event_ctx = NULL;
153                 DLIST_REMOVE(ev->fd_events, fd);
154                 fd = ev->fd_events;
155         }
156
157         te = ev->timer_events;
158         while (te) {
159                 te->event_ctx = NULL;
160                 DLIST_REMOVE(te->timer_events, te);
161                 te = ev->timer_events;
162         }
163
164         se = ev->signal_events;
165         while (se) {
166                 se->event_ctx = NULL;
167                 DLIST_REMOVE(ev->signal_events, se);
168                 se = ev->signal_events;
169         }
170
171         return 0;
172 }
173
174 /*
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.
179
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
182
183   NOTE: use tevent_context_init() inside of samba!
184 */
185 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
186                                                       const struct tevent_ops *ops)
187 {
188         struct tevent_context *ev;
189         int ret;
190
191         ev = talloc_zero(mem_ctx, struct tevent_context);
192         if (!ev) return NULL;
193
194         talloc_set_destructor(ev, tevent_common_context_destructor);
195
196         ev->ops = ops;
197
198         ret = ev->ops->context_init(ev);
199         if (ret != 0) {
200                 talloc_free(ev);
201                 return NULL;
202         }
203
204         return ev;
205 }
206
207 /*
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.
211 */
212 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
213                                                   const char *name)
214 {
215         struct tevent_ops_list *e;
216
217         tevent_backend_init();
218
219         if (name == NULL) {
220                 name = tevent_default_backend;
221         }
222         if (name == NULL) {
223                 name = "standard";
224         }
225
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);
229                 }
230         }
231         return NULL;
232 }
233
234
235 /*
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.
239 */
240 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
241 {
242         return tevent_context_init_byname(mem_ctx, NULL);
243 }
244
245 /*
246   add a fd based event
247   return NULL on failure (memory allocation error)
248
249   if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
250   the returned fd_event context is freed
251 */
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)
260 {
261         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
262                                handler_name, location);
263 }
264
265 /*
266   add a disk aio event
267 */
268 struct tevent_aio *_tevent_add_aio(struct tevent_context *ev,
269                                    TALLOC_CTX *mem_ctx,
270                                    struct iocb *iocb,
271                                    tevent_aio_handler_t handler,
272                                    void *private_data,
273                                    const char *handler_name,
274                                    const char *location)
275 {
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);
279 }
280
281 /*
282   set a close function on the fd event
283 */
284 void tevent_fd_set_close_fn(struct tevent_fd *fde,
285                             tevent_fd_close_fn_t close_fn)
286 {
287         if (!fde) return;
288         if (!fde->event_ctx) return;
289         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
290 }
291
292 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
293                                     struct tevent_fd *fde,
294                                     int fd,
295                                     void *private_data)
296 {
297         close(fd);
298 }
299
300 void tevent_fd_set_auto_close(struct tevent_fd *fde)
301 {
302         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
303 }
304
305 /*
306   return the fd event flags
307 */
308 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
309 {
310         if (!fde) return 0;
311         if (!fde->event_ctx) return 0;
312         return fde->event_ctx->ops->get_fd_flags(fde);
313 }
314
315 /*
316   set the fd event flags
317 */
318 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
319 {
320         if (!fde) return;
321         if (!fde->event_ctx) return;
322         fde->event_ctx->ops->set_fd_flags(fde, flags);
323 }
324
325 /*
326   add a timer event
327   return NULL on failure
328 */
329 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
330                                        TALLOC_CTX *mem_ctx,
331                                        struct timeval next_event,
332                                        tevent_timer_handler_t handler,
333                                        void *private_data,
334                                        const char *handler_name,
335                                        const char *location)
336 {
337         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
338                                   handler_name, location);
339 }
340
341 /*
342   add a signal event
343
344   sa_flags are flags to sigaction(2)
345
346   return NULL on failure
347 */
348 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
349                                          TALLOC_CTX *mem_ctx,
350                                          int signum,
351                                          int sa_flags,
352                                          tevent_signal_handler_t handler,
353                                          void *private_data,
354                                          const char *handler_name,
355                                          const char *location)
356 {
357         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
358                                    handler_name, location);
359 }
360
361 /*
362   do a single event loop using the events defined in ev 
363 */
364 int tevent_loop_once(struct tevent_context *ev)
365 {
366         return ev->ops->loop_once(ev);
367 }
368
369 /*
370   return on failure or (with 0) if all fd events are removed
371 */
372 int tevent_loop_wait(struct tevent_context *ev)
373 {
374         return ev->ops->loop_wait(ev);
375 }