Add async read_packet
[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    Copyright (C) Stefan Metzmacher 2009
6
7      ** NOTE! The following LGPL license applies to the tevent
8      ** library. This does NOT imply that all of Samba is released
9      ** under the LGPL
10
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Lesser General Public
13    License as published by the Free Software Foundation; either
14    version 3 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Lesser General Public License for more details.
20
21    You should have received a copy of the GNU Lesser General Public
22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 */
24
25 /*
26   PLEASE READ THIS BEFORE MODIFYING!
27
28   This module is a general abstraction for the main select loop and
29   event handling. Do not ever put any localised hacks in here, instead
30   register one of the possible event types and implement that event
31   somewhere else.
32
33   There are 2 types of event handling that are handled in this module:
34
35   1) a file descriptor becoming readable or writeable. This is mostly
36      used for network sockets, but can be used for any type of file
37      descriptor. You may only register one handler for each file
38      descriptor/io combination or you will get unpredictable results
39      (this means that you can have a handler for read events, and a
40      separate handler for write events, but not two handlers that are
41      both handling read events)
42
43   2) a timed event. You can register an event that happens at a
44      specific time.  You can register as many of these as you
45      like. They are single shot - add a new timed event in the event
46      handler to get another event.
47
48   To setup a set of events you first need to create a event_context
49   structure using the function tevent_context_init(); This returns a
50   'struct tevent_context' that you use in all subsequent calls.
51
52   After that you can add/remove events that you are interested in
53   using tevent_add_*() and talloc_free()
54
55   Finally, you call tevent_loop_wait_once() to block waiting for one of the
56   events to occor or tevent_loop_wait() which will loop
57   forever.
58
59 */
60 #include "replace.h"
61 #include "system/filesys.h"
62 #include "tevent.h"
63 #include "tevent_internal.h"
64 #include "tevent_util.h"
65
66 struct tevent_ops_list {
67         struct tevent_ops_list *next, *prev;
68         const char *name;
69         const struct tevent_ops *ops;
70 };
71
72 /* list of registered event backends */
73 static struct tevent_ops_list *tevent_backends = NULL;
74 static char *tevent_default_backend = NULL;
75
76 /*
77   register an events backend
78 */
79 bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
80 {
81         struct tevent_ops_list *e;
82
83         for (e = tevent_backends; e != NULL; e = e->next) {
84                 if (0 == strcmp(e->name, name)) {
85                         /* already registered, skip it */
86                         return true;
87                 }
88         }
89
90         e = talloc(talloc_autofree_context(), struct tevent_ops_list);
91         if (e == NULL) return false;
92
93         e->name = name;
94         e->ops = ops;
95         DLIST_ADD(tevent_backends, e);
96
97         return true;
98 }
99
100 /*
101   set the default event backend
102  */
103 void tevent_set_default_backend(const char *backend)
104 {
105         talloc_free(tevent_default_backend);
106         tevent_default_backend = talloc_strdup(talloc_autofree_context(),
107                                                backend);
108 }
109
110 /*
111   initialise backends if not already done
112 */
113 static void tevent_backend_init(void)
114 {
115         tevent_select_init();
116         tevent_standard_init();
117 #ifdef HAVE_EPOLL
118         tevent_epoll_init();
119 #endif
120 }
121
122 /*
123   list available backends
124 */
125 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
126 {
127         const char **list = NULL;
128         struct tevent_ops_list *e;
129
130         tevent_backend_init();
131
132         for (e=tevent_backends;e;e=e->next) {
133                 list = ev_str_list_add(list, e->name);
134         }
135
136         talloc_steal(mem_ctx, list);
137
138         return list;
139 }
140
141 int tevent_common_context_destructor(struct tevent_context *ev)
142 {
143         struct tevent_fd *fd, *fn;
144         struct tevent_timer *te, *tn;
145         struct tevent_signal *se, *sn;
146
147         if (ev->pipe_fde) {
148                 talloc_free(ev->pipe_fde);
149                 ev->pipe_fde = NULL;
150         }
151
152         for (fd = ev->fd_events; fd; fd = fn) {
153                 fn = fd->next;
154                 fd->event_ctx = NULL;
155                 DLIST_REMOVE(ev->fd_events, fd);
156         }
157
158         for (te = ev->timer_events; te; te = tn) {
159                 tn = te->next;
160                 te->event_ctx = NULL;
161                 DLIST_REMOVE(ev->timer_events, te);
162         }
163
164         for (se = ev->signal_events; se; se = sn) {
165                 sn = se->next;
166                 se->event_ctx = NULL;
167                 DLIST_REMOVE(ev->signal_events, se);
168         }
169
170         return 0;
171 }
172
173 /*
174   create a event_context structure for a specific implemementation.
175   This must be the first events call, and all subsequent calls pass
176   this event_context as the first element. Event handlers also
177   receive this as their first argument.
178
179   This function is for allowing third-party-applications to hook in gluecode
180   to their own event loop code, so that they can make async usage of our client libs
181
182   NOTE: use tevent_context_init() inside of samba!
183 */
184 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
185                                                       const struct tevent_ops *ops)
186 {
187         struct tevent_context *ev;
188         int ret;
189
190         ev = talloc_zero(mem_ctx, struct tevent_context);
191         if (!ev) return NULL;
192
193         talloc_set_destructor(ev, tevent_common_context_destructor);
194
195         ev->ops = ops;
196
197         ret = ev->ops->context_init(ev);
198         if (ret != 0) {
199                 talloc_free(ev);
200                 return NULL;
201         }
202
203         return ev;
204 }
205
206 /*
207   create a event_context structure. This must be the first events
208   call, and all subsequent calls pass this event_context as the first
209   element. Event handlers also receive this as their first argument.
210 */
211 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
212                                                   const char *name)
213 {
214         struct tevent_ops_list *e;
215
216         tevent_backend_init();
217
218         if (name == NULL) {
219                 name = tevent_default_backend;
220         }
221         if (name == NULL) {
222                 name = "standard";
223         }
224
225         for (e=tevent_backends;e;e=e->next) {
226                 if (strcmp(name, e->name) == 0) {
227                         return tevent_context_init_ops(mem_ctx, e->ops);
228                 }
229         }
230         return NULL;
231 }
232
233
234 /*
235   create a event_context structure. This must be the first events
236   call, and all subsequent calls pass this event_context as the first
237   element. Event handlers also receive this as their first argument.
238 */
239 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
240 {
241         return tevent_context_init_byname(mem_ctx, NULL);
242 }
243
244 /*
245   add a fd based event
246   return NULL on failure (memory allocation error)
247
248   if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
249   the returned fd_event context is freed
250 */
251 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
252                                  TALLOC_CTX *mem_ctx,
253                                  int fd,
254                                  uint16_t flags,
255                                  tevent_fd_handler_t handler,
256                                  void *private_data,
257                                  const char *handler_name,
258                                  const char *location)
259 {
260         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
261                                handler_name, location);
262 }
263
264 /*
265   set a close function on the fd event
266 */
267 void tevent_fd_set_close_fn(struct tevent_fd *fde,
268                             tevent_fd_close_fn_t close_fn)
269 {
270         if (!fde) return;
271         if (!fde->event_ctx) return;
272         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
273 }
274
275 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
276                                     struct tevent_fd *fde,
277                                     int fd,
278                                     void *private_data)
279 {
280         close(fd);
281 }
282
283 void tevent_fd_set_auto_close(struct tevent_fd *fde)
284 {
285         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
286 }
287
288 /*
289   return the fd event flags
290 */
291 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
292 {
293         if (!fde) return 0;
294         if (!fde->event_ctx) return 0;
295         return fde->event_ctx->ops->get_fd_flags(fde);
296 }
297
298 /*
299   set the fd event flags
300 */
301 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
302 {
303         if (!fde) return;
304         if (!fde->event_ctx) return;
305         fde->event_ctx->ops->set_fd_flags(fde, flags);
306 }
307
308 /*
309   add a timer event
310   return NULL on failure
311 */
312 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
313                                        TALLOC_CTX *mem_ctx,
314                                        struct timeval next_event,
315                                        tevent_timer_handler_t handler,
316                                        void *private_data,
317                                        const char *handler_name,
318                                        const char *location)
319 {
320         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
321                                   handler_name, location);
322 }
323
324 /*
325   add a signal event
326
327   sa_flags are flags to sigaction(2)
328
329   return NULL on failure
330 */
331 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
332                                          TALLOC_CTX *mem_ctx,
333                                          int signum,
334                                          int sa_flags,
335                                          tevent_signal_handler_t handler,
336                                          void *private_data,
337                                          const char *handler_name,
338                                          const char *location)
339 {
340         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
341                                    handler_name, location);
342 }
343
344 /*
345   do a single event loop using the events defined in ev 
346 */
347 int tevent_loop_once(struct tevent_context *ev)
348 {
349         return ev->ops->loop_once(ev);
350 }
351
352 /*
353   return on failure or (with 0) if all fd events are removed
354 */
355 int tevent_loop_wait(struct tevent_context *ev)
356 {
357         return ev->ops->loop_wait(ev);
358 }