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