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