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