tevent: add support for immediate events
[metze/samba/wip.git] / lib / 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 "replace.h"
61 #include "system/filesys.h"
62 #define TEVENT_DEPRECATED 1
63 #include "tevent.h"
64 #include "tevent_internal.h"
65 #include "tevent_util.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(talloc_autofree_context(), 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(talloc_autofree_context(),
108                                                backend);
109 }
110
111 /*
112   initialise backends if not already done
113 */
114 static void tevent_backend_init(void)
115 {
116         tevent_select_init();
117         tevent_standard_init();
118 #ifdef HAVE_EPOLL
119         tevent_epoll_init();
120 #endif
121 }
122
123 /*
124   list available backends
125 */
126 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
127 {
128         const char **list = NULL;
129         struct tevent_ops_list *e;
130
131         tevent_backend_init();
132
133         for (e=tevent_backends;e;e=e->next) {
134                 list = ev_str_list_add(list, e->name);
135         }
136
137         talloc_steal(mem_ctx, list);
138
139         return list;
140 }
141
142 int tevent_common_context_destructor(struct tevent_context *ev)
143 {
144         struct tevent_fd *fd, *fn;
145         struct tevent_timer *te, *tn;
146         struct tevent_immediate *ie, *in;
147         struct tevent_signal *se, *sn;
148
149         if (ev->pipe_fde) {
150                 talloc_free(ev->pipe_fde);
151                 ev->pipe_fde = NULL;
152         }
153
154         for (fd = ev->fd_events; fd; fd = fn) {
155                 fn = fd->next;
156                 fd->event_ctx = NULL;
157                 DLIST_REMOVE(ev->fd_events, fd);
158         }
159
160         for (te = ev->timer_events; te; te = tn) {
161                 tn = te->next;
162                 te->event_ctx = NULL;
163                 DLIST_REMOVE(ev->timer_events, te);
164         }
165
166         for (ie = ev->immediate_events; ie; ie = in) {
167                 in = ie->next;
168                 ie->event_ctx = NULL;
169                 ie->cancel_fn = NULL;
170                 DLIST_REMOVE(ev->immediate_events, ie);
171         }
172
173         for (se = ev->signal_events; se; se = sn) {
174                 sn = se->next;
175                 se->event_ctx = NULL;
176                 DLIST_REMOVE(ev->signal_events, se);
177         }
178
179         return 0;
180 }
181
182 /*
183   create a event_context structure for a specific implemementation.
184   This must be the first events call, and all subsequent calls pass
185   this event_context as the first element. Event handlers also
186   receive this as their first argument.
187
188   This function is for allowing third-party-applications to hook in gluecode
189   to their own event loop code, so that they can make async usage of our client libs
190
191   NOTE: use tevent_context_init() inside of samba!
192 */
193 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
194                                                       const struct tevent_ops *ops)
195 {
196         struct tevent_context *ev;
197         int ret;
198
199         ev = talloc_zero(mem_ctx, struct tevent_context);
200         if (!ev) return NULL;
201
202         talloc_set_destructor(ev, tevent_common_context_destructor);
203
204         ev->ops = ops;
205
206         ret = ev->ops->context_init(ev);
207         if (ret != 0) {
208                 talloc_free(ev);
209                 return NULL;
210         }
211
212         return ev;
213 }
214
215 /*
216   create a event_context structure. This must be the first events
217   call, and all subsequent calls pass this event_context as the first
218   element. Event handlers also receive this as their first argument.
219 */
220 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
221                                                   const char *name)
222 {
223         struct tevent_ops_list *e;
224
225         tevent_backend_init();
226
227         if (name == NULL) {
228                 name = tevent_default_backend;
229         }
230         if (name == NULL) {
231                 name = "standard";
232         }
233
234         for (e=tevent_backends;e;e=e->next) {
235                 if (strcmp(name, e->name) == 0) {
236                         return tevent_context_init_ops(mem_ctx, e->ops);
237                 }
238         }
239         return NULL;
240 }
241
242
243 /*
244   create a event_context structure. This must be the first events
245   call, and all subsequent calls pass this event_context as the first
246   element. Event handlers also receive this as their first argument.
247 */
248 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
249 {
250         return tevent_context_init_byname(mem_ctx, NULL);
251 }
252
253 /*
254   add a fd based event
255   return NULL on failure (memory allocation error)
256
257   if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
258   the returned fd_event context is freed
259 */
260 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
261                                  TALLOC_CTX *mem_ctx,
262                                  int fd,
263                                  uint16_t flags,
264                                  tevent_fd_handler_t handler,
265                                  void *private_data,
266                                  const char *handler_name,
267                                  const char *location)
268 {
269         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
270                                handler_name, location);
271 }
272
273 /*
274   set a close function on the fd event
275 */
276 void tevent_fd_set_close_fn(struct tevent_fd *fde,
277                             tevent_fd_close_fn_t close_fn)
278 {
279         if (!fde) return;
280         if (!fde->event_ctx) return;
281         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
282 }
283
284 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
285                                     struct tevent_fd *fde,
286                                     int fd,
287                                     void *private_data)
288 {
289         close(fd);
290 }
291
292 void tevent_fd_set_auto_close(struct tevent_fd *fde)
293 {
294         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
295 }
296
297 /*
298   return the fd event flags
299 */
300 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
301 {
302         if (!fde) return 0;
303         if (!fde->event_ctx) return 0;
304         return fde->event_ctx->ops->get_fd_flags(fde);
305 }
306
307 /*
308   set the fd event flags
309 */
310 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
311 {
312         if (!fde) return;
313         if (!fde->event_ctx) return;
314         fde->event_ctx->ops->set_fd_flags(fde, flags);
315 }
316
317 bool tevent_signal_support(struct tevent_context *ev)
318 {
319         if (ev->ops->add_signal) {
320                 return true;
321         }
322         return false;
323 }
324
325 static void (*tevent_abort_fn)(const char *reason);
326
327 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
328 {
329         tevent_abort_fn = abort_fn;
330 }
331
332 static void tevent_abort(struct tevent_context *ev, const char *reason)
333 {
334         tevent_debug(ev, TEVENT_DEBUG_FATAL,
335                      "abort: %s\n", reason);
336
337         if (!tevent_abort_fn) {
338                 abort();
339         }
340
341         tevent_abort_fn(reason);
342 }
343
344 /*
345   add a timer event
346   return NULL on failure
347 */
348 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
349                                        TALLOC_CTX *mem_ctx,
350                                        struct timeval next_event,
351                                        tevent_timer_handler_t handler,
352                                        void *private_data,
353                                        const char *handler_name,
354                                        const char *location)
355 {
356         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
357                                   handler_name, location);
358 }
359
360 /*
361   allocate an immediate event
362   return NULL on failure (memory allocation error)
363 */
364 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
365                                                   const char *location)
366 {
367         struct tevent_immediate *im;
368
369         im = talloc(mem_ctx, struct tevent_immediate);
370         if (im == NULL) return NULL;
371
372         im->prev                = NULL;
373         im->next                = NULL;
374         im->event_ctx           = NULL;
375         im->create_location     = location;
376         im->handler             = NULL;
377         im->private_data        = NULL;
378         im->handler_name        = NULL;
379         im->schedule_location   = NULL;
380         im->cancel_fn           = NULL;
381         im->additional_data     = NULL;
382
383         return im;
384 }
385
386 /*
387   schedule an immediate event
388   return NULL on failure
389 */
390 void _tevent_schedule_immediate(struct tevent_immediate *im,
391                                 struct tevent_context *ev,
392                                 tevent_immediate_handler_t handler,
393                                 void *private_data,
394                                 const char *handler_name,
395                                 const char *location)
396 {
397         ev->ops->schedule_immediate(im, ev, handler, private_data,
398                                     handler_name, location);
399 }
400
401 /*
402   add a signal event
403
404   sa_flags are flags to sigaction(2)
405
406   return NULL on failure
407 */
408 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
409                                          TALLOC_CTX *mem_ctx,
410                                          int signum,
411                                          int sa_flags,
412                                          tevent_signal_handler_t handler,
413                                          void *private_data,
414                                          const char *handler_name,
415                                          const char *location)
416 {
417         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
418                                    handler_name, location);
419 }
420
421 void tevent_loop_allow_nesting(struct tevent_context *ev)
422 {
423         ev->nesting.allowed = true;
424 }
425
426 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
427                                   tevent_nesting_hook hook,
428                                   void *private_data)
429 {
430         ev->nesting.hook_fn = hook;
431         ev->nesting.hook_private = private_data;
432 }
433
434 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
435 {
436         const char *reason;
437
438         reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
439                                  location);
440         if (!reason) {
441                 reason = "tevent_loop_once() nesting";
442         }
443
444         tevent_abort(ev, reason);
445 }
446
447 /*
448   do a single event loop using the events defined in ev 
449 */
450 int _tevent_loop_once(struct tevent_context *ev, const char *location)
451 {
452         int ret;
453         void *nesting_stack_ptr = NULL;
454
455         ev->nesting.level++;
456
457         if (ev->nesting.level > 1) {
458                 if (!ev->nesting.allowed) {
459                         tevent_abort_nesting(ev, location);
460                         errno = ELOOP;
461                         return -1;
462                 }
463                 if (ev->nesting.hook_fn) {
464                         int ret2;
465                         ret2 = ev->nesting.hook_fn(ev,
466                                                    ev->nesting.hook_private,
467                                                    ev->nesting.level,
468                                                    true,
469                                                    (void *)&nesting_stack_ptr,
470                                                    location);
471                         if (ret2 != 0) {
472                                 ret = ret2;
473                                 goto done;
474                         }
475                 }
476         }
477
478         ret = ev->ops->loop_once(ev, location);
479
480         if (ev->nesting.level > 1) {
481                 if (ev->nesting.hook_fn) {
482                         int ret2;
483                         ret2 = ev->nesting.hook_fn(ev,
484                                                    ev->nesting.hook_private,
485                                                    ev->nesting.level,
486                                                    false,
487                                                    (void *)&nesting_stack_ptr,
488                                                    location);
489                         if (ret2 != 0) {
490                                 ret = ret2;
491                                 goto done;
492                         }
493                 }
494         }
495
496 done:
497         ev->nesting.level--;
498         return ret;
499 }
500
501 /*
502   this is a performance optimization for the samba4 nested event loop problems
503 */
504 int _tevent_loop_until(struct tevent_context *ev,
505                        bool (*finished)(void *private_data),
506                        void *private_data,
507                        const char *location)
508 {
509         int ret = 0;
510         void *nesting_stack_ptr = NULL;
511
512         ev->nesting.level++;
513
514         if (ev->nesting.level > 1) {
515                 if (!ev->nesting.allowed) {
516                         tevent_abort_nesting(ev, location);
517                         errno = ELOOP;
518                         return -1;
519                 }
520                 if (ev->nesting.hook_fn) {
521                         int ret2;
522                         ret2 = ev->nesting.hook_fn(ev,
523                                                    ev->nesting.hook_private,
524                                                    ev->nesting.level,
525                                                    true,
526                                                    (void *)&nesting_stack_ptr,
527                                                    location);
528                         if (ret2 != 0) {
529                                 ret = ret2;
530                                 goto done;
531                         }
532                 }
533         }
534
535         while (!finished(private_data)) {
536                 ret = ev->ops->loop_once(ev, location);
537                 if (ret != 0) {
538                         break;
539                 }
540         }
541
542         if (ev->nesting.level > 1) {
543                 if (ev->nesting.hook_fn) {
544                         int ret2;
545                         ret2 = ev->nesting.hook_fn(ev,
546                                                    ev->nesting.hook_private,
547                                                    ev->nesting.level,
548                                                    false,
549                                                    (void *)&nesting_stack_ptr,
550                                                    location);
551                         if (ret2 != 0) {
552                                 ret = ret2;
553                                 goto done;
554                         }
555                 }
556         }
557
558 done:
559         ev->nesting.level--;
560         return ret;
561 }
562
563 /*
564   return on failure or (with 0) if all fd events are removed
565 */
566 int tevent_common_loop_wait(struct tevent_context *ev,
567                             const char *location)
568 {
569         /*
570          * loop as long as we have events pending
571          */
572         while (ev->fd_events ||
573                ev->timer_events ||
574                ev->immediate_events ||
575                ev->signal_events) {
576                 int ret;
577                 ret = _tevent_loop_once(ev, location);
578                 if (ret != 0) {
579                         tevent_debug(ev, TEVENT_DEBUG_FATAL,
580                                      "_tevent_loop_once() failed: %d - %s\n",
581                                      ret, strerror(errno));
582                         return ret;
583                 }
584         }
585
586         tevent_debug(ev, TEVENT_DEBUG_WARNING,
587                      "tevent_common_loop_wait() out of events\n");
588         return 0;
589 }
590
591 /*
592   return on failure or (with 0) if all fd events are removed
593 */
594 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
595 {
596         return ev->ops->loop_wait(ev, location);
597 }