r22634: make the events system much less dependent on the samba4 build system
[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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22   PLEASE READ THIS BEFORE MODIFYING!
23
24   This module is a general abstraction for the main select loop and
25   event handling. Do not ever put any localised hacks in here, instead
26   register one of the possible event types and implement that event
27   somewhere else.
28
29   There are 2 types of event handling that are handled in this module:
30
31   1) a file descriptor becoming readable or writeable. This is mostly
32      used for network sockets, but can be used for any type of file
33      descriptor. You may only register one handler for each file
34      descriptor/io combination or you will get unpredictable results
35      (this means that you can have a handler for read events, and a
36      separate handler for write events, but not two handlers that are
37      both handling read events)
38
39   2) a timed event. You can register an event that happens at a
40      specific time.  You can register as many of these as you
41      like. They are single shot - add a new timed event in the event
42      handler to get another event.
43
44   To setup a set of events you first need to create a event_context
45   structure using the function event_context_init(); This returns a
46   'struct event_context' that you use in all subsequent calls.
47
48   After that you can add/remove events that you are interested in
49   using event_add_*() and talloc_free()
50
51   Finally, you call event_loop_wait_once() to block waiting for one of the
52   events to occor or event_loop_wait() which will loop
53   forever.
54
55 */
56
57 #include "includes.h"
58 #include "lib/events/events.h"
59 #include "lib/events/events_internal.h"
60 #include "lib/util/dlinklist.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 /*
75   register an events backend
76 */
77 bool event_register_backend(const char *name, const struct event_ops *ops)
78 {
79         struct event_ops_list *e;
80         e = talloc(talloc_autofree_context(), struct event_ops_list);
81         if (e == NULL) return False;
82         e->name = name;
83         e->ops = ops;
84         DLIST_ADD(event_backends, e);
85         return True;
86 }
87
88 /*
89   initialise backends if not already done
90 */
91 static void event_backend_init(void)
92 {
93 #if _SAMBA_BUILD_
94         init_module_fn static_init[] = STATIC_LIBEVENTS_MODULES;
95         init_module_fn *shared_init;
96         if (event_backends) return;
97         shared_init = load_samba_modules(NULL, "LIBEVENTS");
98         run_init_functions(static_init);
99         run_init_functions(shared_init);
100 #else
101         bool events_standard_init(void);
102         events_standard_init();
103 #endif
104 }
105
106 /*
107   list available backends
108 */
109 const char **event_backend_list(TALLOC_CTX *mem_ctx)
110 {
111         const char **list = NULL;
112         struct event_ops_list *e;
113
114         event_backend_init();
115
116         for (e=event_backends;e;e=e->next) {
117                 list = str_list_add(list, e->name);
118         }
119
120         talloc_steal(mem_ctx, list);
121
122         return list;
123 }
124
125 /*
126   create a event_context structure for a specific implemementation.
127   This must be the first events call, and all subsequent calls pass
128   this event_context as the first element. Event handlers also
129   receive this as their first argument.
130
131   This function is for allowing third-party-applications to hook in gluecode
132   to their own event loop code, so that they can make async usage of our client libs
133
134   NOTE: use event_context_init() inside of samba!
135 */
136 static struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, 
137                                                     const struct event_ops *ops)
138 {
139         struct event_context *ev;
140         int ret;
141
142         ev = talloc_zero(mem_ctx, struct event_context);
143         if (!ev) return NULL;
144
145         ev->ops = ops;
146
147         ret = ev->ops->context_init(ev);
148         if (ret != 0) {
149                 talloc_free(ev);
150                 return NULL;
151         }
152
153         return ev;
154 }
155
156 /*
157   create a event_context structure. This must be the first events
158   call, and all subsequent calls pass this event_context as the first
159   element. Event handlers also receive this as their first argument.
160 */
161 struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name)
162 {
163         struct event_ops_list *e;
164
165         event_backend_init();
166
167 #if _SAMBA_BUILD_
168         if (name == NULL) {
169                 name = lp_parm_string(-1, "event", "backend");
170         }
171 #endif
172         if (name == NULL) {
173                 name = "standard";
174         }
175
176         for (e=event_backends;e;e=e->next) {
177                 if (strcmp(name, e->name) == 0) {
178                         return event_context_init_ops(mem_ctx, e->ops);
179                 }
180         }
181         return NULL;
182 }
183
184
185 /*
186   create a event_context structure. This must be the first events
187   call, and all subsequent calls pass this event_context as the first
188   element. Event handlers also receive this as their first argument.
189 */
190 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
191 {
192         return event_context_init_byname(mem_ctx, NULL);
193 }
194
195 /*
196   add a fd based event
197   return NULL on failure (memory allocation error)
198 */
199 struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
200                               int fd, uint16_t flags, event_fd_handler_t handler,
201                               void *private_data)
202 {
203         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data);
204 }
205
206 /*
207   add a disk aio event
208 */
209 struct aio_event *event_add_aio(struct event_context *ev,
210                                 TALLOC_CTX *mem_ctx,
211                                 struct iocb *iocb,
212                                 event_aio_handler_t handler,
213                                 void *private_data)
214 {
215         if (ev->ops->add_aio == NULL) return NULL;
216         return ev->ops->add_aio(ev, mem_ctx, iocb, handler, private_data);
217 }
218
219 /*
220   return the fd event flags
221 */
222 uint16_t event_get_fd_flags(struct fd_event *fde)
223 {
224         if (!fde) return 0;
225         return fde->event_ctx->ops->get_fd_flags(fde);
226 }
227
228 /*
229   set the fd event flags
230 */
231 void event_set_fd_flags(struct fd_event *fde, uint16_t flags)
232 {
233         if (!fde) return;
234         fde->event_ctx->ops->set_fd_flags(fde, flags);
235 }
236
237 /*
238   add a timed event
239   return NULL on failure
240 */
241 struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
242                                     struct timeval next_event, 
243                                     event_timed_handler_t handler, 
244                                     void *private_data)
245 {
246         return ev->ops->add_timed(ev, mem_ctx, next_event, handler, private_data);
247 }
248
249 /*
250   add a signal event
251
252   sa_flags are flags to sigaction(2)
253
254   return NULL on failure
255 */
256 struct signal_event *event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx,
257                                       int signum,
258                                       int sa_flags,
259                                       event_signal_handler_t handler, 
260                                       void *private_data)
261 {
262         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data);
263 }
264
265 /*
266   do a single event loop using the events defined in ev 
267 */
268 _PUBLIC_ int event_loop_once(struct event_context *ev)
269 {
270         return ev->ops->loop_once(ev);
271 }
272
273 /*
274   return on failure or (with 0) if all fd events are removed
275 */
276 int event_loop_wait(struct event_context *ev)
277 {
278         return ev->ops->loop_wait(ev);
279 }
280
281 /*
282   find an event context that is a parent of the given memory context,
283   or create a new event context as a child of the given context if
284   none is found
285
286   This should be used in preference to event_context_init() in places
287   where you would prefer to use the existing event context if possible
288   (which is most situations)
289 */
290 struct event_context *event_context_find(TALLOC_CTX *mem_ctx)
291 {
292         struct event_context *ev = talloc_find_parent_bytype(mem_ctx, struct event_context);
293         if (ev == NULL) {               
294                 ev = event_context_init(mem_ctx);
295         }
296         return ev;
297 }