]> git.ozlabs.org Git - ccan-lca-2011.git/blob - ccan/tevent/tevent.c
lca2011: hacky import of tevent.
[ccan-lca-2011.git] / ccan / tevent / tevent.c
1 /* 
2    Unix SMB/CIFS implementation.
3    main select loop and event handling
4    Copyright (C) Andrew Tridgell 2003
5    Copyright (C) Stefan Metzmacher 2009
6
7      ** NOTE! The following LGPL license applies to the tevent
8      ** library. This does NOT imply that all of Samba is released
9      ** under the LGPL
10
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Lesser General Public
13    License as published by the Free Software Foundation; either
14    version 3 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Lesser General Public License for more details.
20
21    You should have received a copy of the GNU Lesser General Public
22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 */
24
25 /*
26   PLEASE READ THIS BEFORE MODIFYING!
27
28   This module is a general abstraction for the main select loop and
29   event handling. Do not ever put any localised hacks in here, instead
30   register one of the possible event types and implement that event
31   somewhere else.
32
33   There are 2 types of event handling that are handled in this module:
34
35   1) a file descriptor becoming readable or writeable. This is mostly
36      used for network sockets, but can be used for any type of file
37      descriptor. You may only register one handler for each file
38      descriptor/io combination or you will get unpredictable results
39      (this means that you can have a handler for read events, and a
40      separate handler for write events, but not two handlers that are
41      both handling read events)
42
43   2) a timed event. You can register an event that happens at a
44      specific time.  You can register as many of these as you
45      like. They are single shot - add a new timed event in the event
46      handler to get another event.
47
48   To setup a set of events you first need to create a event_context
49   structure using the function tevent_context_init(); This returns a
50   'struct tevent_context' that you use in all subsequent calls.
51
52   After that you can add/remove events that you are interested in
53   using tevent_add_*() and talloc_free()
54
55   Finally, you call tevent_loop_wait_once() to block waiting for one of the
56   events to occor or tevent_loop_wait() which will loop
57   forever.
58
59 */
60 #include <ccan/tevent/tevent.h>
61 #include <ccan/tevent/tevent_internal.h>
62 #include <ccan/tevent/tevent_util.h>
63 #include <string.h>
64 #include <unistd.h>
65 #include <errno.h>
66
67 struct tevent_ops_list {
68         struct tevent_ops_list *next, *prev;
69         const char *name;
70         const struct tevent_ops *ops;
71 };
72
73 /* list of registered event backends */
74 static struct tevent_ops_list *tevent_backends = NULL;
75 static char *tevent_default_backend = NULL;
76
77 /*
78   register an events backend
79 */
80 bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
81 {
82         struct tevent_ops_list *e;
83
84         for (e = tevent_backends; e != NULL; e = e->next) {
85                 if (0 == strcmp(e->name, name)) {
86                         /* already registered, skip it */
87                         return true;
88                 }
89         }
90
91         e = talloc(NULL, struct tevent_ops_list);
92         if (e == NULL) return false;
93
94         e->name = name;
95         e->ops = ops;
96         DLIST_ADD(tevent_backends, e);
97
98         return true;
99 }
100
101 /*
102   set the default event backend
103  */
104 void tevent_set_default_backend(const char *backend)
105 {
106         talloc_free(tevent_default_backend);
107         tevent_default_backend = talloc_strdup(NULL, backend);
108 }
109
110 /*
111   initialise backends if not already done
112 */
113 static void tevent_backend_init(void)
114 {
115         tevent_select_init();
116         tevent_standard_init();
117 #ifdef HAVE_EPOLL
118         tevent_epoll_init();
119 #endif
120 }
121
122 /*
123   list available backends
124 */
125 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
126 {
127         const char **list = NULL;
128         struct tevent_ops_list *e;
129
130         tevent_backend_init();
131
132         for (e=tevent_backends;e;e=e->next) {
133                 list = ev_str_list_add(list, e->name);
134         }
135
136         talloc_steal(mem_ctx, list);
137
138         return list;
139 }
140
141 int tevent_common_context_destructor(struct tevent_context *ev)
142 {
143         struct tevent_fd *fd, *fn;
144         struct tevent_timer *te, *tn;
145         struct tevent_immediate *ie, *in;
146         struct tevent_signal *se, *sn;
147
148         if (ev->pipe_fde) {
149                 talloc_free(ev->pipe_fde);
150                 close(ev->pipe_fds[0]);
151                 close(ev->pipe_fds[1]);
152                 ev->pipe_fde = NULL;
153         }
154
155         for (fd = ev->fd_events; fd; fd = fn) {
156                 fn = fd->next;
157                 fd->event_ctx = NULL;
158                 DLIST_REMOVE(ev->fd_events, fd);
159         }
160
161         for (te = ev->timer_events; te; te = tn) {
162                 tn = te->next;
163                 te->event_ctx = NULL;
164                 DLIST_REMOVE(ev->timer_events, te);
165         }
166
167         for (ie = ev->immediate_events; ie; ie = in) {
168                 in = ie->next;
169                 ie->event_ctx = NULL;
170                 ie->cancel_fn = NULL;
171                 DLIST_REMOVE(ev->immediate_events, ie);
172         }
173
174         for (se = ev->signal_events; se; se = sn) {
175                 sn = se->next;
176                 se->event_ctx = NULL;
177                 DLIST_REMOVE(ev->signal_events, se);
178                 /*
179                  * This is important, Otherwise signals
180                  * are handled twice in child. eg, SIGHUP.
181                  * one added in parent, and another one in
182                  * the child. -- BoYang
183                  */
184                 tevent_cleanup_pending_signal_handlers(se);
185         }
186
187         return 0;
188 }
189
190 /*
191   create a event_context structure for a specific implemementation.
192   This must be the first events call, and all subsequent calls pass
193   this event_context as the first element. Event handlers also
194   receive this as their first argument.
195
196   This function is for allowing third-party-applications to hook in gluecode
197   to their own event loop code, so that they can make async usage of our client libs
198
199   NOTE: use tevent_context_init() inside of samba!
200 */
201 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
202                                                       const struct tevent_ops *ops)
203 {
204         struct tevent_context *ev;
205         int ret;
206
207         ev = talloc_zero(mem_ctx, struct tevent_context);
208         if (!ev) return NULL;
209
210         talloc_set_destructor(ev, tevent_common_context_destructor);
211
212         ev->ops = ops;
213
214         ret = ev->ops->context_init(ev);
215         if (ret != 0) {
216                 talloc_free(ev);
217                 return NULL;
218         }
219
220         return ev;
221 }
222
223 /*
224   create a event_context structure. This must be the first events
225   call, and all subsequent calls pass this event_context as the first
226   element. Event handlers also receive this as their first argument.
227 */
228 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
229                                                   const char *name)
230 {
231         struct tevent_ops_list *e;
232
233         tevent_backend_init();
234
235         if (name == NULL) {
236                 name = tevent_default_backend;
237         }
238         if (name == NULL) {
239                 name = "standard";
240         }
241
242         for (e=tevent_backends;e;e=e->next) {
243                 if (strcmp(name, e->name) == 0) {
244                         return tevent_context_init_ops(mem_ctx, e->ops);
245                 }
246         }
247         return NULL;
248 }
249
250
251 /*
252   create a event_context structure. This must be the first events
253   call, and all subsequent calls pass this event_context as the first
254   element. Event handlers also receive this as their first argument.
255 */
256 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
257 {
258         return tevent_context_init_byname(mem_ctx, NULL);
259 }
260
261 /*
262   add a fd based event
263   return NULL on failure (memory allocation error)
264 */
265 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
266                                  TALLOC_CTX *mem_ctx,
267                                  int fd,
268                                  uint16_t flags,
269                                  tevent_fd_handler_t handler,
270                                  void *private_data,
271                                  const char *handler_name,
272                                  const char *location)
273 {
274         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
275                                handler_name, location);
276 }
277
278 /*
279   set a close function on the fd event
280 */
281 void tevent_fd_set_close_fn(struct tevent_fd *fde,
282                             tevent_fd_close_fn_t close_fn)
283 {
284         if (!fde) return;
285         if (!fde->event_ctx) return;
286         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
287 }
288
289 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
290                                     struct tevent_fd *fde,
291                                     int fd,
292                                     void *private_data)
293 {
294         close(fd);
295 }
296
297 void tevent_fd_set_auto_close(struct tevent_fd *fde)
298 {
299         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
300 }
301
302 /*
303   return the fd event flags
304 */
305 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
306 {
307         if (!fde) return 0;
308         if (!fde->event_ctx) return 0;
309         return fde->event_ctx->ops->get_fd_flags(fde);
310 }
311
312 /*
313   set the fd event flags
314 */
315 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
316 {
317         if (!fde) return;
318         if (!fde->event_ctx) return;
319         fde->event_ctx->ops->set_fd_flags(fde, flags);
320 }
321
322 bool tevent_signal_support(struct tevent_context *ev)
323 {
324         if (ev->ops->add_signal) {
325                 return true;
326         }
327         return false;
328 }
329
330 static void (*tevent_abort_fn)(const char *reason);
331
332 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
333 {
334         tevent_abort_fn = abort_fn;
335 }
336
337 /*
338   add a timer event
339   return NULL on failure
340 */
341 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
342                                        TALLOC_CTX *mem_ctx,
343                                        struct timeval next_event,
344                                        tevent_timer_handler_t handler,
345                                        void *private_data,
346                                        const char *handler_name,
347                                        const char *location)
348 {
349         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
350                                   handler_name, location);
351 }
352
353 /*
354   allocate an immediate event
355   return NULL on failure (memory allocation error)
356 */
357 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
358                                                   const char *location)
359 {
360         struct tevent_immediate *im;
361
362         im = talloc(mem_ctx, struct tevent_immediate);
363         if (im == NULL) return NULL;
364
365         im->prev                = NULL;
366         im->next                = NULL;
367         im->event_ctx           = NULL;
368         im->create_location     = location;
369         im->handler             = NULL;
370         im->private_data        = NULL;
371         im->handler_name        = NULL;
372         im->schedule_location   = NULL;
373         im->cancel_fn           = NULL;
374         im->additional_data     = NULL;
375
376         return im;
377 }
378
379 /*
380   schedule an immediate event
381   return NULL on failure
382 */
383 void _tevent_schedule_immediate(struct tevent_immediate *im,
384                                 struct tevent_context *ev,
385                                 tevent_immediate_handler_t handler,
386                                 void *private_data,
387                                 const char *handler_name,
388                                 const char *location)
389 {
390         ev->ops->schedule_immediate(im, ev, handler, private_data,
391                                     handler_name, location);
392 }
393
394 /*
395   add a signal event
396
397   sa_flags are flags to sigaction(2)
398
399   return NULL on failure
400 */
401 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
402                                          TALLOC_CTX *mem_ctx,
403                                          int signum,
404                                          int sa_flags,
405                                          tevent_signal_handler_t handler,
406                                          void *private_data,
407                                          const char *handler_name,
408                                          const char *location)
409 {
410         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
411                                    handler_name, location);
412 }
413
414 /*
415   do a single event loop using the events defined in ev 
416 */
417 int _tevent_loop_once(struct tevent_context *ev, const char *location)
418 {
419         return ev->ops->loop_once(ev, location);
420 }
421
422 /*
423   return on failure or (with 0) if all fd events are removed
424 */
425 int tevent_common_loop_wait(struct tevent_context *ev,
426                             const char *location)
427 {
428         /*
429          * loop as long as we have events pending
430          */
431         while (ev->fd_events ||
432                ev->timer_events ||
433                ev->immediate_events ||
434                ev->signal_events) {
435                 int ret;
436                 ret = _tevent_loop_once(ev, location);
437                 if (ret != 0) {
438                         tevent_debug(ev, TEVENT_DEBUG_FATAL,
439                                      "_tevent_loop_once() failed: %d - %s\n",
440                                      ret, strerror(errno));
441                         return ret;
442                 }
443         }
444
445         tevent_debug(ev, TEVENT_DEBUG_WARNING,
446                      "tevent_common_loop_wait() out of events\n");
447         return 0;
448 }
449
450 /*
451   return on failure or (with 0) if all fd events are removed
452 */
453 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
454 {
455         return ev->ops->loop_wait(ev, location);
456 }
457