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