331be0eb11089c71f2a892e30680ab5c17a3a396
[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 #ifdef HAVE_PTHREAD
63 #include "system/threads.h"
64 #endif
65 #define TEVENT_DEPRECATED 1
66 #include "tevent.h"
67 #include "tevent_internal.h"
68 #include "tevent_util.h"
69 #ifdef HAVE_EVENTFD
70 #include <sys/eventfd.h>
71 #endif
72
73 static void tevent_abort(struct tevent_context *ev, const char *reason);
74
75 struct tevent_ops_list {
76         struct tevent_ops_list *next, *prev;
77         const char *name;
78         const struct tevent_ops *ops;
79 };
80
81 /* list of registered event backends */
82 static struct tevent_ops_list *tevent_backends = NULL;
83 static char *tevent_default_backend = NULL;
84
85 /*
86   register an events backend
87 */
88 bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
89 {
90         struct tevent_ops_list *e;
91
92         for (e = tevent_backends; e != NULL; e = e->next) {
93                 if (0 == strcmp(e->name, name)) {
94                         /* already registered, skip it */
95                         return true;
96                 }
97         }
98
99         e = talloc(NULL, struct tevent_ops_list);
100         if (e == NULL) return false;
101
102         e->name = name;
103         e->ops = ops;
104         DLIST_ADD(tevent_backends, e);
105
106         return true;
107 }
108
109 /*
110   set the default event backend
111  */
112 void tevent_set_default_backend(const char *backend)
113 {
114         talloc_free(tevent_default_backend);
115         tevent_default_backend = talloc_strdup(NULL, backend);
116 }
117
118 /*
119   initialise backends if not already done
120 */
121 static void tevent_backend_init(void)
122 {
123         static bool done;
124
125         if (done) {
126                 return;
127         }
128
129         done = true;
130
131         tevent_select_init();
132         tevent_poll_init();
133         tevent_poll_mt_init();
134 #if defined(HAVE_EPOLL)
135         tevent_epoll_init();
136 #elif defined(HAVE_SOLARIS_PORTS)
137         tevent_port_init();
138 #endif
139
140         tevent_standard_init();
141 }
142
143 _PRIVATE_ const struct tevent_ops *tevent_find_ops_byname(const char *name)
144 {
145         struct tevent_ops_list *e;
146
147         tevent_backend_init();
148
149         if (name == NULL) {
150                 name = tevent_default_backend;
151         }
152         if (name == NULL) {
153                 name = "standard";
154         }
155
156         for (e = tevent_backends; e != NULL; e = e->next) {
157                 if (0 == strcmp(e->name, name)) {
158                         return e->ops;
159                 }
160         }
161
162         return NULL;
163 }
164
165 /*
166   list available backends
167 */
168 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
169 {
170         const char **list = NULL;
171         struct tevent_ops_list *e;
172
173         tevent_backend_init();
174
175         for (e=tevent_backends;e;e=e->next) {
176                 list = ev_str_list_add(list, e->name);
177         }
178
179         talloc_steal(mem_ctx, list);
180
181         return list;
182 }
183
184 static void tevent_common_wakeup_fini(struct tevent_context *ev);
185
186 #ifdef HAVE_PTHREAD
187
188 static pthread_mutex_t tevent_contexts_mutex = PTHREAD_MUTEX_INITIALIZER;
189 static struct tevent_context *tevent_contexts = NULL;
190 static pthread_once_t tevent_atfork_initialized = PTHREAD_ONCE_INIT;
191
192 static void tevent_atfork_prepare(void)
193 {
194         struct tevent_context *ev;
195         int ret;
196
197         ret = pthread_mutex_lock(&tevent_contexts_mutex);
198         if (ret != 0) {
199                 abort();
200         }
201
202         for (ev = tevent_contexts; ev != NULL; ev = ev->next) {
203                 ret = pthread_mutex_lock(&ev->scheduled_mutex);
204                 if (ret != 0) {
205                         tevent_abort(ev, "pthread_mutex_lock failed");
206                 }
207         }
208 }
209
210 static void tevent_atfork_parent(void)
211 {
212         struct tevent_context *ev;
213         int ret;
214
215         for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
216              ev = DLIST_PREV(ev)) {
217                 ret = pthread_mutex_unlock(&ev->scheduled_mutex);
218                 if (ret != 0) {
219                         tevent_abort(ev, "pthread_mutex_unlock failed");
220                 }
221         }
222
223         ret = pthread_mutex_unlock(&tevent_contexts_mutex);
224         if (ret != 0) {
225                 abort();
226         }
227 }
228
229 static void tevent_atfork_child(void)
230 {
231         struct tevent_context *ev;
232         int ret;
233
234         for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
235              ev = DLIST_PREV(ev)) {
236                 struct tevent_threaded_context *tctx;
237
238                 for (tctx = ev->threaded_contexts; tctx != NULL;
239                      tctx = tctx->next) {
240                         tctx->event_ctx = NULL;
241                 }
242
243                 ev->threaded_contexts = NULL;
244
245                 ret = pthread_mutex_unlock(&ev->scheduled_mutex);
246                 if (ret != 0) {
247                         tevent_abort(ev, "pthread_mutex_unlock failed");
248                 }
249         }
250
251         ret = pthread_mutex_unlock(&tevent_contexts_mutex);
252         if (ret != 0) {
253                 abort();
254         }
255 }
256
257 static void tevent_prep_atfork(void)
258 {
259         int ret;
260
261         ret = pthread_atfork(tevent_atfork_prepare,
262                              tevent_atfork_parent,
263                              tevent_atfork_child);
264         if (ret != 0) {
265                 abort();
266         }
267 }
268
269 #endif
270
271 int tevent_common_context_destructor(struct tevent_context *ev)
272 {
273         struct tevent_fd *fd, *fn;
274         struct tevent_timer *te, *tn;
275         struct tevent_immediate *ie, *in;
276         struct tevent_signal *se, *sn;
277
278 #ifdef HAVE_PTHREAD
279         int ret;
280
281         ret = pthread_mutex_lock(&tevent_contexts_mutex);
282         if (ret != 0) {
283                 abort();
284         }
285
286         DLIST_REMOVE(tevent_contexts, ev);
287
288         ret = pthread_mutex_unlock(&tevent_contexts_mutex);
289         if (ret != 0) {
290                 abort();
291         }
292 #endif
293
294         if (ev->threaded_contexts != NULL) {
295                 /*
296                  * Threaded contexts are indicators that threads are
297                  * about to send us immediates via
298                  * tevent_threaded_schedule_immediate. The caller
299                  * needs to make sure that the tevent context lives
300                  * long enough to receive immediates from all threads.
301                  */
302                 tevent_abort(ev, "threaded contexts exist");
303         }
304
305         tevent_common_wakeup_fini(ev);
306
307         for (fd = ev->fd_events; fd; fd = fn) {
308                 fn = fd->next;
309                 fd->event_ctx = NULL;
310                 DLIST_REMOVE(ev->fd_events, fd);
311         }
312
313         ev->last_zero_timer = NULL;
314         for (te = ev->timer_events; te; te = tn) {
315                 tn = te->next;
316                 te->event_ctx = NULL;
317                 DLIST_REMOVE(ev->timer_events, te);
318         }
319
320         for (ie = ev->immediate_events; ie; ie = in) {
321                 in = ie->next;
322                 ie->event_ctx = NULL;
323                 ie->cancel_fn = NULL;
324                 DLIST_REMOVE(ev->immediate_events, ie);
325         }
326
327         for (se = ev->signal_events; se; se = sn) {
328                 sn = se->next;
329                 se->event_ctx = NULL;
330                 DLIST_REMOVE(ev->signal_events, se);
331                 /*
332                  * This is important, Otherwise signals
333                  * are handled twice in child. eg, SIGHUP.
334                  * one added in parent, and another one in
335                  * the child. -- BoYang
336                  */
337                 tevent_cleanup_pending_signal_handlers(se);
338         }
339
340         /* removing nesting hook or we get an abort when nesting is
341          * not allowed. -- SSS
342          * Note that we need to leave the allowed flag at its current
343          * value, otherwise the use in tevent_re_initialise() will
344          * leave the event context with allowed forced to false, which
345          * will break users that expect nesting to be allowed
346          */
347         ev->nesting.level = 0;
348         ev->nesting.hook_fn = NULL;
349         ev->nesting.hook_private = NULL;
350
351         return 0;
352 }
353
354 /*
355   create a event_context structure for a specific implemementation.
356   This must be the first events call, and all subsequent calls pass
357   this event_context as the first element. Event handlers also
358   receive this as their first argument.
359
360   This function is for allowing third-party-applications to hook in gluecode
361   to their own event loop code, so that they can make async usage of our client libs
362
363   NOTE: use tevent_context_init() inside of samba!
364 */
365 struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
366                                                const struct tevent_ops *ops,
367                                                void *additional_data)
368 {
369         struct tevent_context *ev;
370         int ret;
371
372         ev = talloc_zero(mem_ctx, struct tevent_context);
373         if (!ev) return NULL;
374
375 #ifdef HAVE_PTHREAD
376
377         ret = pthread_once(&tevent_atfork_initialized, tevent_prep_atfork);
378         if (ret != 0) {
379                 talloc_free(ev);
380                 return NULL;
381         }
382
383         ret = pthread_mutex_init(&ev->scheduled_mutex, NULL);
384         if (ret != 0) {
385                 talloc_free(ev);
386                 return NULL;
387         }
388
389         ret = pthread_mutex_lock(&tevent_contexts_mutex);
390         if (ret != 0) {
391                 pthread_mutex_destroy(&ev->scheduled_mutex);
392                 talloc_free(ev);
393                 return NULL;
394         }
395
396         DLIST_ADD(tevent_contexts, ev);
397
398         ret = pthread_mutex_unlock(&tevent_contexts_mutex);
399         if (ret != 0) {
400                 abort();
401         }
402
403 #endif
404
405         talloc_set_destructor(ev, tevent_common_context_destructor);
406
407         ev->ops = ops;
408         ev->additional_data = additional_data;
409
410         ret = ev->ops->context_init(ev);
411         if (ret != 0) {
412                 talloc_free(ev);
413                 return NULL;
414         }
415
416         return ev;
417 }
418
419 /*
420   create a event_context structure. This must be the first events
421   call, and all subsequent calls pass this event_context as the first
422   element. Event handlers also receive this as their first argument.
423 */
424 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
425                                                   const char *name)
426 {
427         const struct tevent_ops *ops;
428
429         ops = tevent_find_ops_byname(name);
430         if (ops == NULL) {
431                 return NULL;
432         }
433
434         return tevent_context_init_ops(mem_ctx, ops, NULL);
435 }
436
437
438 /*
439   create a event_context structure. This must be the first events
440   call, and all subsequent calls pass this event_context as the first
441   element. Event handlers also receive this as their first argument.
442 */
443 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
444 {
445         return tevent_context_init_byname(mem_ctx, NULL);
446 }
447
448 /*
449   add a fd based event
450   return NULL on failure (memory allocation error)
451 */
452 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
453                                  TALLOC_CTX *mem_ctx,
454                                  int fd,
455                                  uint16_t flags,
456                                  tevent_fd_handler_t handler,
457                                  void *private_data,
458                                  const char *handler_name,
459                                  const char *location)
460 {
461         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
462                                handler_name, location);
463 }
464
465 /*
466   set a close function on the fd event
467 */
468 void tevent_fd_set_close_fn(struct tevent_fd *fde,
469                             tevent_fd_close_fn_t close_fn)
470 {
471         if (!fde) return;
472         if (!fde->event_ctx) return;
473         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
474 }
475
476 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
477                                     struct tevent_fd *fde,
478                                     int fd,
479                                     void *private_data)
480 {
481         close(fd);
482 }
483
484 void tevent_fd_set_auto_close(struct tevent_fd *fde)
485 {
486         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
487 }
488
489 /*
490   return the fd event flags
491 */
492 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
493 {
494         if (!fde) return 0;
495         if (!fde->event_ctx) return 0;
496         return fde->event_ctx->ops->get_fd_flags(fde);
497 }
498
499 /*
500   set the fd event flags
501 */
502 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
503 {
504         if (!fde) return;
505         if (!fde->event_ctx) return;
506         fde->event_ctx->ops->set_fd_flags(fde, flags);
507 }
508
509 bool tevent_signal_support(struct tevent_context *ev)
510 {
511         if (ev->ops->add_signal) {
512                 return true;
513         }
514         return false;
515 }
516
517 static void (*tevent_abort_fn)(const char *reason);
518
519 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
520 {
521         tevent_abort_fn = abort_fn;
522 }
523
524 static void tevent_abort(struct tevent_context *ev, const char *reason)
525 {
526         tevent_debug(ev, TEVENT_DEBUG_FATAL,
527                      "abort: %s\n", reason);
528
529         if (!tevent_abort_fn) {
530                 abort();
531         }
532
533         tevent_abort_fn(reason);
534 }
535
536 /*
537   add a timer event
538   return NULL on failure
539 */
540 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
541                                        TALLOC_CTX *mem_ctx,
542                                        struct timeval next_event,
543                                        tevent_timer_handler_t handler,
544                                        void *private_data,
545                                        const char *handler_name,
546                                        const char *location)
547 {
548         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
549                                   handler_name, location);
550 }
551
552 /*
553   allocate an immediate event
554   return NULL on failure (memory allocation error)
555 */
556 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
557                                                   const char *location)
558 {
559         struct tevent_immediate *im;
560
561         im = talloc(mem_ctx, struct tevent_immediate);
562         if (im == NULL) return NULL;
563
564         im->prev                = NULL;
565         im->next                = NULL;
566         im->event_ctx           = NULL;
567         im->create_location     = location;
568         im->handler             = NULL;
569         im->private_data        = NULL;
570         im->handler_name        = NULL;
571         im->schedule_location   = NULL;
572         im->cancel_fn           = NULL;
573         im->additional_data     = NULL;
574
575         return im;
576 }
577
578 /*
579   schedule an immediate event
580 */
581 void _tevent_schedule_immediate(struct tevent_immediate *im,
582                                 struct tevent_context *ev,
583                                 tevent_immediate_handler_t handler,
584                                 void *private_data,
585                                 const char *handler_name,
586                                 const char *location)
587 {
588         ev->ops->schedule_immediate(im, ev, handler, private_data,
589                                     handler_name, location);
590 }
591
592 /*
593   add a signal event
594
595   sa_flags are flags to sigaction(2)
596
597   return NULL on failure
598 */
599 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
600                                          TALLOC_CTX *mem_ctx,
601                                          int signum,
602                                          int sa_flags,
603                                          tevent_signal_handler_t handler,
604                                          void *private_data,
605                                          const char *handler_name,
606                                          const char *location)
607 {
608         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
609                                    handler_name, location);
610 }
611
612 void tevent_loop_allow_nesting(struct tevent_context *ev)
613 {
614         ev->nesting.allowed = true;
615 }
616
617 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
618                                   tevent_nesting_hook hook,
619                                   void *private_data)
620 {
621         if (ev->nesting.hook_fn && 
622             (ev->nesting.hook_fn != hook ||
623              ev->nesting.hook_private != private_data)) {
624                 /* the way the nesting hook code is currently written
625                    we cannot support two different nesting hooks at the
626                    same time. */
627                 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
628         }
629         ev->nesting.hook_fn = hook;
630         ev->nesting.hook_private = private_data;
631 }
632
633 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
634 {
635         const char *reason;
636
637         reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
638                                  location);
639         if (!reason) {
640                 reason = "tevent_loop_once() nesting";
641         }
642
643         tevent_abort(ev, reason);
644 }
645
646 /*
647   do a single event loop using the events defined in ev 
648 */
649 int _tevent_loop_once(struct tevent_context *ev, const char *location)
650 {
651         int ret;
652         void *nesting_stack_ptr = NULL;
653
654         ev->nesting.level++;
655
656         if (ev->nesting.level > 1) {
657                 if (!ev->nesting.allowed) {
658                         tevent_abort_nesting(ev, location);
659                         errno = ELOOP;
660                         return -1;
661                 }
662         }
663         if (ev->nesting.level > 0) {
664                 if (ev->nesting.hook_fn) {
665                         int ret2;
666                         ret2 = ev->nesting.hook_fn(ev,
667                                                    ev->nesting.hook_private,
668                                                    ev->nesting.level,
669                                                    true,
670                                                    (void *)&nesting_stack_ptr,
671                                                    location);
672                         if (ret2 != 0) {
673                                 ret = ret2;
674                                 goto done;
675                         }
676                 }
677         }
678
679         tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
680         ret = ev->ops->loop_once(ev, location);
681         tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
682
683         if (ev->nesting.level > 0) {
684                 if (ev->nesting.hook_fn) {
685                         int ret2;
686                         ret2 = ev->nesting.hook_fn(ev,
687                                                    ev->nesting.hook_private,
688                                                    ev->nesting.level,
689                                                    false,
690                                                    (void *)&nesting_stack_ptr,
691                                                    location);
692                         if (ret2 != 0) {
693                                 ret = ret2;
694                                 goto done;
695                         }
696                 }
697         }
698
699 done:
700         ev->nesting.level--;
701         return ret;
702 }
703
704 /*
705   this is a performance optimization for the samba4 nested event loop problems
706 */
707 int _tevent_loop_until(struct tevent_context *ev,
708                        bool (*finished)(void *private_data),
709                        void *private_data,
710                        const char *location)
711 {
712         int ret = 0;
713         void *nesting_stack_ptr = NULL;
714
715         ev->nesting.level++;
716
717         if (ev->nesting.level > 1) {
718                 if (!ev->nesting.allowed) {
719                         tevent_abort_nesting(ev, location);
720                         errno = ELOOP;
721                         return -1;
722                 }
723         }
724         if (ev->nesting.level > 0) {
725                 if (ev->nesting.hook_fn) {
726                         int ret2;
727                         ret2 = ev->nesting.hook_fn(ev,
728                                                    ev->nesting.hook_private,
729                                                    ev->nesting.level,
730                                                    true,
731                                                    (void *)&nesting_stack_ptr,
732                                                    location);
733                         if (ret2 != 0) {
734                                 ret = ret2;
735                                 goto done;
736                         }
737                 }
738         }
739
740         while (!finished(private_data)) {
741                 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
742                 ret = ev->ops->loop_once(ev, location);
743                 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
744                 if (ret != 0) {
745                         break;
746                 }
747         }
748
749         if (ev->nesting.level > 0) {
750                 if (ev->nesting.hook_fn) {
751                         int ret2;
752                         ret2 = ev->nesting.hook_fn(ev,
753                                                    ev->nesting.hook_private,
754                                                    ev->nesting.level,
755                                                    false,
756                                                    (void *)&nesting_stack_ptr,
757                                                    location);
758                         if (ret2 != 0) {
759                                 ret = ret2;
760                                 goto done;
761                         }
762                 }
763         }
764
765 done:
766         ev->nesting.level--;
767         return ret;
768 }
769
770 bool tevent_common_have_events(struct tevent_context *ev)
771 {
772         if (ev->fd_events != NULL) {
773                 if (ev->fd_events != ev->wakeup_fde) {
774                         return true;
775                 }
776                 if (ev->fd_events->next != NULL) {
777                         return true;
778                 }
779
780                 /*
781                  * At this point we just have the wakeup pipe event as
782                  * the only fd_event. That one does not count as a
783                  * regular event, so look at the other event types.
784                  */
785         }
786
787         return ((ev->timer_events != NULL) ||
788                 (ev->immediate_events != NULL) ||
789                 (ev->signal_events != NULL));
790 }
791
792 /*
793   return on failure or (with 0) if all fd events are removed
794 */
795 int tevent_common_loop_wait(struct tevent_context *ev,
796                             const char *location)
797 {
798         /*
799          * loop as long as we have events pending
800          */
801         while (tevent_common_have_events(ev)) {
802                 int ret;
803                 ret = _tevent_loop_once(ev, location);
804                 if (ret != 0) {
805                         tevent_debug(ev, TEVENT_DEBUG_FATAL,
806                                      "_tevent_loop_once() failed: %d - %s\n",
807                                      ret, strerror(errno));
808                         return ret;
809                 }
810         }
811
812         tevent_debug(ev, TEVENT_DEBUG_WARNING,
813                      "tevent_common_loop_wait() out of events\n");
814         return 0;
815 }
816
817 /*
818   return on failure or (with 0) if all fd events are removed
819 */
820 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
821 {
822         return ev->ops->loop_wait(ev, location);
823 }
824
825
826 /*
827   re-initialise a tevent context. This leaves you with the same
828   event context, but all events are wiped and the structure is
829   re-initialised. This is most useful after a fork()  
830
831   zero is returned on success, non-zero on failure
832 */
833 int tevent_re_initialise(struct tevent_context *ev)
834 {
835         tevent_common_context_destructor(ev);
836
837         return ev->ops->context_init(ev);
838 }
839
840 static void wakeup_pipe_handler(struct tevent_context *ev,
841                                 struct tevent_fd *fde,
842                                 uint16_t flags, void *_private)
843 {
844         ssize_t ret;
845
846         do {
847                 /*
848                  * This is the boilerplate for eventfd, but it works
849                  * for pipes too. And as we don't care about the data
850                  * we read, we're fine.
851                  */
852                 uint64_t val;
853                 ret = read(fde->fd, &val, sizeof(val));
854         } while (ret == -1 && errno == EINTR);
855 }
856
857 /*
858  * Initialize the wakeup pipe and pipe fde
859  */
860
861 int tevent_common_wakeup_init(struct tevent_context *ev)
862 {
863         int ret;
864
865         if (ev->wakeup_fde != NULL) {
866                 return 0;
867         }
868
869 #ifdef HAVE_EVENTFD
870         ret = eventfd(0, EFD_NONBLOCK);
871         if (ret == -1) {
872                 return errno;
873         }
874         ev->wakeup_fd = ret;
875 #else
876         {
877                 int pipe_fds[2];
878                 ret = pipe(pipe_fds);
879                 if (ret == -1) {
880                         return errno;
881                 }
882                 ev->wakeup_fd = pipe_fds[0];
883                 ev->wakeup_write_fd = pipe_fds[1];
884
885                 ev_set_blocking(ev->wakeup_fd, false);
886                 ev_set_blocking(ev->wakeup_write_fd, false);
887         }
888 #endif
889
890         ev->wakeup_fde = tevent_add_fd(ev, ev, ev->wakeup_fd,
891                                      TEVENT_FD_READ,
892                                      wakeup_pipe_handler, NULL);
893         if (ev->wakeup_fde == NULL) {
894                 close(ev->wakeup_fd);
895 #ifndef HAVE_EVENTFD
896                 close(ev->wakeup_write_fd);
897 #endif
898                 return ENOMEM;
899         }
900
901         return 0;
902 }
903
904 int tevent_common_wakeup(struct tevent_context *ev)
905 {
906         ssize_t ret;
907
908         if (ev->wakeup_fde == NULL) {
909                 return ENOTCONN;
910         }
911
912         do {
913 #ifdef HAVE_EVENTFD
914                 uint64_t val = 1;
915                 ret = write(ev->wakeup_fd, &val, sizeof(val));
916 #else
917                 char c = '\0';
918                 ret = write(ev->wakeup_write_fd, &c, 1);
919 #endif
920         } while ((ret == -1) && (errno == EINTR));
921
922         return 0;
923 }
924
925 static void tevent_common_wakeup_fini(struct tevent_context *ev)
926 {
927         if (ev->wakeup_fde == NULL) {
928                 return;
929         }
930
931         TALLOC_FREE(ev->wakeup_fde);
932
933         close(ev->wakeup_fd);
934 #ifndef HAVE_EVENTFD
935         close(ev->wakeup_write_fd);
936 #endif
937 }