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