4b22e33b3406f88a9a30d18bf46a613d1829799b
[jra/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 }
116
117 /*
118   list available backends
119 */
120 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
121 {
122         const char **list = NULL;
123         struct tevent_ops_list *e;
124
125         tevent_backend_init();
126
127         for (e=tevent_backends;e;e=e->next) {
128                 list = ev_str_list_add(list, e->name);
129         }
130
131         talloc_steal(mem_ctx, list);
132
133         return list;
134 }
135
136 int tevent_common_context_destructor(struct tevent_context *ev)
137 {
138         struct tevent_fd *fd, *fn;
139         struct tevent_timer *te, *tn;
140         struct tevent_signal *se, *sn;
141
142         if (ev->pipe_fde) {
143                 talloc_free(ev->pipe_fde);
144                 ev->pipe_fde = NULL;
145         }
146
147         for (fd = ev->fd_events; fd; fd = fn) {
148                 fn = fd->next;
149                 fd->event_ctx = NULL;
150                 DLIST_REMOVE(ev->fd_events, fd);
151         }
152
153         for (te = ev->timer_events; te; te = tn) {
154                 tn = te->next;
155                 te->event_ctx = NULL;
156                 DLIST_REMOVE(ev->timer_events, te);
157         }
158
159         for (se = ev->signal_events; se; se = sn) {
160                 sn = 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   set a close function on the fd event
261 */
262 void tevent_fd_set_close_fn(struct tevent_fd *fde,
263                             tevent_fd_close_fn_t close_fn)
264 {
265         if (!fde) return;
266         if (!fde->event_ctx) return;
267         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
268 }
269
270 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
271                                     struct tevent_fd *fde,
272                                     int fd,
273                                     void *private_data)
274 {
275         close(fd);
276 }
277
278 void tevent_fd_set_auto_close(struct tevent_fd *fde)
279 {
280         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
281 }
282
283 /*
284   return the fd event flags
285 */
286 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
287 {
288         if (!fde) return 0;
289         if (!fde->event_ctx) return 0;
290         return fde->event_ctx->ops->get_fd_flags(fde);
291 }
292
293 /*
294   set the fd event flags
295 */
296 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
297 {
298         if (!fde) return;
299         if (!fde->event_ctx) return;
300         fde->event_ctx->ops->set_fd_flags(fde, flags);
301 }
302
303 /*
304   add a timer event
305   return NULL on failure
306 */
307 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
308                                        TALLOC_CTX *mem_ctx,
309                                        struct timeval next_event,
310                                        tevent_timer_handler_t handler,
311                                        void *private_data,
312                                        const char *handler_name,
313                                        const char *location)
314 {
315         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
316                                   handler_name, location);
317 }
318
319 /*
320   add a signal event
321
322   sa_flags are flags to sigaction(2)
323
324   return NULL on failure
325 */
326 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
327                                          TALLOC_CTX *mem_ctx,
328                                          int signum,
329                                          int sa_flags,
330                                          tevent_signal_handler_t handler,
331                                          void *private_data,
332                                          const char *handler_name,
333                                          const char *location)
334 {
335         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
336                                    handler_name, location);
337 }
338
339 /*
340   do a single event loop using the events defined in ev 
341 */
342 int tevent_loop_once(struct tevent_context *ev)
343 {
344         return ev->ops->loop_once(ev);
345 }
346
347 /*
348   return on failure or (with 0) if all fd events are removed
349 */
350 int tevent_loop_wait(struct tevent_context *ev)
351 {
352         return ev->ops->loop_wait(ev);
353 }