Merge branch 'master' of ssh://git.samba.org/data/git/samba
[metze/samba/wip.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 /*
140   create a event_context structure for a specific implemementation.
141   This must be the first events call, and all subsequent calls pass
142   this event_context as the first element. Event handlers also
143   receive this as their first argument.
144
145   This function is for allowing third-party-applications to hook in gluecode
146   to their own event loop code, so that they can make async usage of our client libs
147
148   NOTE: use tevent_context_init() inside of samba!
149 */
150 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
151                                                       const struct tevent_ops *ops)
152 {
153         struct tevent_context *ev;
154         int ret;
155
156         ev = talloc_zero(mem_ctx, struct tevent_context);
157         if (!ev) return NULL;
158
159         ev->ops = ops;
160
161         ret = ev->ops->context_init(ev);
162         if (ret != 0) {
163                 talloc_free(ev);
164                 return NULL;
165         }
166
167         return ev;
168 }
169
170 /*
171   create a event_context structure. This must be the first events
172   call, and all subsequent calls pass this event_context as the first
173   element. Event handlers also receive this as their first argument.
174 */
175 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
176                                                   const char *name)
177 {
178         struct tevent_ops_list *e;
179
180         tevent_backend_init();
181
182         if (name == NULL) {
183                 name = tevent_default_backend;
184         }
185         if (name == NULL) {
186                 name = "standard";
187         }
188
189         for (e=tevent_backends;e;e=e->next) {
190                 if (strcmp(name, e->name) == 0) {
191                         return tevent_context_init_ops(mem_ctx, e->ops);
192                 }
193         }
194         return NULL;
195 }
196
197
198 /*
199   create a event_context structure. This must be the first events
200   call, and all subsequent calls pass this event_context as the first
201   element. Event handlers also receive this as their first argument.
202 */
203 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
204 {
205         return tevent_context_init_byname(mem_ctx, NULL);
206 }
207
208 /*
209   add a fd based event
210   return NULL on failure (memory allocation error)
211
212   if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
213   the returned fd_event context is freed
214 */
215 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
216                                  TALLOC_CTX *mem_ctx,
217                                  int fd,
218                                  uint16_t flags,
219                                  tevent_fd_handler_t handler,
220                                  void *private_data,
221                                  const char *handler_name,
222                                  const char *location)
223 {
224         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
225                                handler_name, location);
226 }
227
228 /*
229   add a disk aio event
230 */
231 struct tevent_aio *_tevent_add_aio(struct tevent_context *ev,
232                                    TALLOC_CTX *mem_ctx,
233                                    struct iocb *iocb,
234                                    tevent_aio_handler_t handler,
235                                    void *private_data,
236                                    const char *handler_name,
237                                    const char *location)
238 {
239         if (ev->ops->add_aio == NULL) return NULL;
240         return ev->ops->add_aio(ev, mem_ctx, iocb, handler, private_data,
241                                 handler_name, location);
242 }
243
244 /*
245   set a close function on the fd event
246 */
247 void tevent_fd_set_close_fn(struct tevent_fd *fde,
248                             tevent_fd_close_fn_t close_fn)
249 {
250         if (!fde) return;
251         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
252 }
253
254 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
255                                     struct tevent_fd *fde,
256                                     int fd,
257                                     void *private_data)
258 {
259         close(fd);
260 }
261
262 void tevent_fd_set_auto_close(struct tevent_fd *fde)
263 {
264         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
265 }
266
267 /*
268   return the fd event flags
269 */
270 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
271 {
272         if (!fde) return 0;
273         return fde->event_ctx->ops->get_fd_flags(fde);
274 }
275
276 /*
277   set the fd event flags
278 */
279 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
280 {
281         if (!fde) return;
282         fde->event_ctx->ops->set_fd_flags(fde, flags);
283 }
284
285 /*
286   add a timer event
287   return NULL on failure
288 */
289 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
290                                        TALLOC_CTX *mem_ctx,
291                                        struct timeval next_event,
292                                        tevent_timer_handler_t handler,
293                                        void *private_data,
294                                        const char *handler_name,
295                                        const char *location)
296 {
297         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
298                                   handler_name, location);
299 }
300
301 /*
302   add a signal event
303
304   sa_flags are flags to sigaction(2)
305
306   return NULL on failure
307 */
308 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
309                                          TALLOC_CTX *mem_ctx,
310                                          int signum,
311                                          int sa_flags,
312                                          tevent_signal_handler_t handler,
313                                          void *private_data,
314                                          const char *handler_name,
315                                          const char *location)
316 {
317         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
318                                    handler_name, location);
319 }
320
321 /*
322   do a single event loop using the events defined in ev 
323 */
324 int tevent_loop_once(struct tevent_context *ev)
325 {
326         return ev->ops->loop_once(ev);
327 }
328
329 /*
330   return on failure or (with 0) if all fd events are removed
331 */
332 int tevent_loop_wait(struct tevent_context *ev)
333 {
334         return ev->ops->loop_wait(ev);
335 }