Merge branch 'master' of ssh://git.samba.org/data/git/samba into pyregistry
[ira/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 event_context_init(); This returns a
45   'struct event_context' that you use in all subsequent calls.
46
47   After that you can add/remove events that you are interested in
48   using event_add_*() and talloc_free()
49
50   Finally, you call event_loop_wait_once() to block waiting for one of the
51   events to occor or event_loop_wait() which will loop
52   forever.
53
54 */
55 #include "replace.h"
56 #include "tevent.h"
57 #include "tevent_internal.h"
58 #include "tevent_util.h"
59
60 struct event_ops_list {
61         struct event_ops_list *next, *prev;
62         const char *name;
63         const struct event_ops *ops;
64 };
65
66 /* list of registered event backends */
67 static struct event_ops_list *event_backends = NULL;
68 static char *event_default_backend = NULL;
69
70 /*
71   register an events backend
72 */
73 bool event_register_backend(const char *name, const struct event_ops *ops)
74 {
75         struct event_ops_list *e;
76
77         for (e = event_backends; e != NULL; e = e->next) {
78                 if (0 == strcmp(e->name, name)) {
79                         /* already registered, skip it */
80                         return true;
81                 }
82         }
83
84         e = talloc(talloc_autofree_context(), struct event_ops_list);
85         if (e == NULL) return false;
86
87         e->name = name;
88         e->ops = ops;
89         DLIST_ADD(event_backends, e);
90
91         return true;
92 }
93
94 /*
95   set the default event backend
96  */
97 void event_set_default_backend(const char *backend)
98 {
99         if (event_default_backend) free(event_default_backend);
100         event_default_backend = strdup(backend);
101 }
102
103 /*
104   initialise backends if not already done
105 */
106 static void event_backend_init(void)
107 {
108         events_select_init();
109         events_standard_init();
110 #if HAVE_EVENTS_EPOLL
111         events_epoll_init();
112 #endif
113 #if HAVE_LINUX_AIO
114         events_aio_init();
115 #endif
116 }
117
118 /*
119   list available backends
120 */
121 const char **event_backend_list(TALLOC_CTX *mem_ctx)
122 {
123         const char **list = NULL;
124         struct event_ops_list *e;
125
126         event_backend_init();
127
128         for (e=event_backends;e;e=e->next) {
129                 list = ev_str_list_add(list, e->name);
130         }
131
132         talloc_steal(mem_ctx, list);
133
134         return list;
135 }
136
137 /*
138   create a event_context structure for a specific implemementation.
139   This must be the first events call, and all subsequent calls pass
140   this event_context as the first element. Event handlers also
141   receive this as their first argument.
142
143   This function is for allowing third-party-applications to hook in gluecode
144   to their own event loop code, so that they can make async usage of our client libs
145
146   NOTE: use event_context_init() inside of samba!
147 */
148 static struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, 
149                                                     const struct event_ops *ops)
150 {
151         struct event_context *ev;
152         int ret;
153
154         ev = talloc_zero(mem_ctx, struct event_context);
155         if (!ev) return NULL;
156
157         ev->ops = ops;
158
159         ret = ev->ops->context_init(ev);
160         if (ret != 0) {
161                 talloc_free(ev);
162                 return NULL;
163         }
164
165         return ev;
166 }
167
168 /*
169   create a event_context structure. This must be the first events
170   call, and all subsequent calls pass this event_context as the first
171   element. Event handlers also receive this as their first argument.
172 */
173 struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name)
174 {
175         struct event_ops_list *e;
176
177         event_backend_init();
178
179         if (name == NULL) {
180                 name = event_default_backend;
181         }
182         if (name == NULL) {
183                 name = "standard";
184         }
185
186         for (e=event_backends;e;e=e->next) {
187                 if (strcmp(name, e->name) == 0) {
188                         return event_context_init_ops(mem_ctx, e->ops);
189                 }
190         }
191         return NULL;
192 }
193
194
195 /*
196   create a event_context structure. This must be the first events
197   call, and all subsequent calls pass this event_context as the first
198   element. Event handlers also receive this as their first argument.
199 */
200 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
201 {
202         return event_context_init_byname(mem_ctx, NULL);
203 }
204
205 /*
206   add a fd based event
207   return NULL on failure (memory allocation error)
208
209   if flags contains EVENT_FD_AUTOCLOSE then the fd will be closed when
210   the returned fd_event context is freed
211 */
212 struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
213                               int fd, uint16_t flags, event_fd_handler_t handler,
214                               void *private_data)
215 {
216         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data);
217 }
218
219 /*
220   add a disk aio event
221 */
222 struct aio_event *event_add_aio(struct event_context *ev,
223                                 TALLOC_CTX *mem_ctx,
224                                 struct iocb *iocb,
225                                 event_aio_handler_t handler,
226                                 void *private_data)
227 {
228         if (ev->ops->add_aio == NULL) return NULL;
229         return ev->ops->add_aio(ev, mem_ctx, iocb, handler, private_data);
230 }
231
232 /*
233   return the fd event flags
234 */
235 uint16_t event_get_fd_flags(struct fd_event *fde)
236 {
237         if (!fde) return 0;
238         return fde->event_ctx->ops->get_fd_flags(fde);
239 }
240
241 /*
242   set the fd event flags
243 */
244 void event_set_fd_flags(struct fd_event *fde, uint16_t flags)
245 {
246         if (!fde) return;
247         fde->event_ctx->ops->set_fd_flags(fde, flags);
248 }
249
250 /*
251   add a timed event
252   return NULL on failure
253 */
254 struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
255                                     struct timeval next_event, 
256                                     event_timed_handler_t handler, 
257                                     void *private_data)
258 {
259         return ev->ops->add_timed(ev, mem_ctx, next_event, handler, private_data);
260 }
261
262 /*
263   add a signal event
264
265   sa_flags are flags to sigaction(2)
266
267   return NULL on failure
268 */
269 struct signal_event *event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx,
270                                       int signum,
271                                       int sa_flags,
272                                       event_signal_handler_t handler, 
273                                       void *private_data)
274 {
275         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data);
276 }
277
278 /*
279   do a single event loop using the events defined in ev 
280 */
281 int event_loop_once(struct event_context *ev)
282 {
283         return ev->ops->loop_once(ev);
284 }
285
286 /*
287   return on failure or (with 0) if all fd events are removed
288 */
289 int event_loop_wait(struct event_context *ev)
290 {
291         return ev->ops->loop_wait(ev);
292 }
293
294 /*
295   find an event context that is a parent of the given memory context,
296   or create a new event context as a child of the given context if
297   none is found
298
299   This should be used in preference to event_context_init() in places
300   where you would prefer to use the existing event context if possible
301   (which is most situations)
302 */
303 struct event_context *event_context_find(TALLOC_CTX *mem_ctx)
304 {
305         struct event_context *ev = talloc_find_parent_bytype(mem_ctx, struct event_context);
306         if (ev == NULL) {               
307                 ev = event_context_init(mem_ctx);
308         }
309         return ev;
310 }