python/tests: add bind time feature related tests to dcerpc raw protocol tests
[Samba.git] / lib / tevent / tevent.c
blob65b101f28e5715d8b576b89c655e2d2662962c5b
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
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
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.
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.
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/>.
26 PLEASE READ THIS BEFORE MODIFYING!
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.
33 There are 2 types of event handling that are handled in this module:
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)
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.
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.
52 After that you can add/remove events that you are interested in
53 using tevent_add_*() and talloc_free()
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.
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
73 static void tevent_abort(struct tevent_context *ev, const char *reason);
75 struct tevent_ops_list {
76 struct tevent_ops_list *next, *prev;
77 const char *name;
78 const struct tevent_ops *ops;
81 /* list of registered event backends */
82 static struct tevent_ops_list *tevent_backends = NULL;
83 static char *tevent_default_backend = NULL;
86 register an events backend
88 bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
90 struct tevent_ops_list *e;
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;
99 e = talloc(NULL, struct tevent_ops_list);
100 if (e == NULL) return false;
102 e->name = name;
103 e->ops = ops;
104 DLIST_ADD(tevent_backends, e);
106 return true;
110 set the default event backend
112 void tevent_set_default_backend(const char *backend)
114 talloc_free(tevent_default_backend);
115 tevent_default_backend = talloc_strdup(NULL, backend);
119 initialise backends if not already done
121 static void tevent_backend_init(void)
123 static bool done;
125 if (done) {
126 return;
129 done = true;
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
140 tevent_standard_init();
143 _PRIVATE_ const struct tevent_ops *tevent_find_ops_byname(const char *name)
145 struct tevent_ops_list *e;
147 tevent_backend_init();
149 if (name == NULL) {
150 name = tevent_default_backend;
152 if (name == NULL) {
153 name = "standard";
156 for (e = tevent_backends; e != NULL; e = e->next) {
157 if (0 == strcmp(e->name, name)) {
158 return e->ops;
162 return NULL;
166 list available backends
168 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
170 const char **list = NULL;
171 struct tevent_ops_list *e;
173 tevent_backend_init();
175 for (e=tevent_backends;e;e=e->next) {
176 list = ev_str_list_add(list, e->name);
179 talloc_steal(mem_ctx, list);
181 return list;
184 static void tevent_common_wakeup_fini(struct tevent_context *ev);
186 #ifdef HAVE_PTHREAD
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;
192 static void tevent_atfork_prepare(void)
194 struct tevent_context *ev;
195 int ret;
197 ret = pthread_mutex_lock(&tevent_contexts_mutex);
198 if (ret != 0) {
199 abort();
202 for (ev = tevent_contexts; ev != NULL; ev = ev->next) {
203 struct tevent_threaded_context *tctx;
205 for (tctx = ev->threaded_contexts; tctx != NULL;
206 tctx = tctx->next) {
207 ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
208 if (ret != 0) {
209 tevent_abort(ev, "pthread_mutex_lock failed");
213 ret = pthread_mutex_lock(&ev->scheduled_mutex);
214 if (ret != 0) {
215 tevent_abort(ev, "pthread_mutex_lock failed");
220 static void tevent_atfork_parent(void)
222 struct tevent_context *ev;
223 int ret;
225 for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
226 ev = DLIST_PREV(ev)) {
227 struct tevent_threaded_context *tctx;
229 ret = pthread_mutex_unlock(&ev->scheduled_mutex);
230 if (ret != 0) {
231 tevent_abort(ev, "pthread_mutex_unlock failed");
234 for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
235 tctx = DLIST_PREV(tctx)) {
236 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
237 if (ret != 0) {
238 tevent_abort(
239 ev, "pthread_mutex_unlock failed");
244 ret = pthread_mutex_unlock(&tevent_contexts_mutex);
245 if (ret != 0) {
246 abort();
250 static void tevent_atfork_child(void)
252 struct tevent_context *ev;
253 int ret;
255 for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
256 ev = DLIST_PREV(ev)) {
257 struct tevent_threaded_context *tctx;
259 for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
260 tctx = DLIST_PREV(tctx)) {
261 tctx->event_ctx = NULL;
263 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
264 if (ret != 0) {
265 tevent_abort(
266 ev, "pthread_mutex_unlock failed");
270 ev->threaded_contexts = NULL;
272 ret = pthread_mutex_unlock(&ev->scheduled_mutex);
273 if (ret != 0) {
274 tevent_abort(ev, "pthread_mutex_unlock failed");
278 ret = pthread_mutex_unlock(&tevent_contexts_mutex);
279 if (ret != 0) {
280 abort();
284 static void tevent_prep_atfork(void)
286 int ret;
288 ret = pthread_atfork(tevent_atfork_prepare,
289 tevent_atfork_parent,
290 tevent_atfork_child);
291 if (ret != 0) {
292 abort();
296 #endif
298 int tevent_common_context_destructor(struct tevent_context *ev)
300 struct tevent_fd *fd, *fn;
301 struct tevent_timer *te, *tn;
302 struct tevent_immediate *ie, *in;
303 struct tevent_signal *se, *sn;
305 #ifdef HAVE_PTHREAD
306 int ret;
308 ret = pthread_mutex_lock(&tevent_contexts_mutex);
309 if (ret != 0) {
310 abort();
313 DLIST_REMOVE(tevent_contexts, ev);
315 ret = pthread_mutex_unlock(&tevent_contexts_mutex);
316 if (ret != 0) {
317 abort();
320 while (ev->threaded_contexts != NULL) {
321 struct tevent_threaded_context *tctx = ev->threaded_contexts;
323 ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
324 if (ret != 0) {
325 abort();
329 * Indicate to the thread that the tevent_context is
330 * gone. The counterpart of this is in
331 * _tevent_threaded_schedule_immediate, there we read
332 * this under the threaded_context's mutex.
335 tctx->event_ctx = NULL;
337 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
338 if (ret != 0) {
339 abort();
342 DLIST_REMOVE(ev->threaded_contexts, tctx);
344 #endif
346 tevent_common_wakeup_fini(ev);
348 for (fd = ev->fd_events; fd; fd = fn) {
349 fn = fd->next;
350 fd->event_ctx = NULL;
351 DLIST_REMOVE(ev->fd_events, fd);
354 ev->last_zero_timer = NULL;
355 for (te = ev->timer_events; te; te = tn) {
356 tn = te->next;
357 te->event_ctx = NULL;
358 DLIST_REMOVE(ev->timer_events, te);
361 for (ie = ev->immediate_events; ie; ie = in) {
362 in = ie->next;
363 ie->event_ctx = NULL;
364 ie->cancel_fn = NULL;
365 DLIST_REMOVE(ev->immediate_events, ie);
368 for (se = ev->signal_events; se; se = sn) {
369 sn = se->next;
370 se->event_ctx = NULL;
371 DLIST_REMOVE(ev->signal_events, se);
373 * This is important, Otherwise signals
374 * are handled twice in child. eg, SIGHUP.
375 * one added in parent, and another one in
376 * the child. -- BoYang
378 tevent_cleanup_pending_signal_handlers(se);
381 /* removing nesting hook or we get an abort when nesting is
382 * not allowed. -- SSS
383 * Note that we need to leave the allowed flag at its current
384 * value, otherwise the use in tevent_re_initialise() will
385 * leave the event context with allowed forced to false, which
386 * will break users that expect nesting to be allowed
388 ev->nesting.level = 0;
389 ev->nesting.hook_fn = NULL;
390 ev->nesting.hook_private = NULL;
392 return 0;
396 create a event_context structure for a specific implemementation.
397 This must be the first events call, and all subsequent calls pass
398 this event_context as the first element. Event handlers also
399 receive this as their first argument.
401 This function is for allowing third-party-applications to hook in gluecode
402 to their own event loop code, so that they can make async usage of our client libs
404 NOTE: use tevent_context_init() inside of samba!
406 struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
407 const struct tevent_ops *ops,
408 void *additional_data)
410 struct tevent_context *ev;
411 int ret;
413 ev = talloc_zero(mem_ctx, struct tevent_context);
414 if (!ev) return NULL;
416 #ifdef HAVE_PTHREAD
418 ret = pthread_once(&tevent_atfork_initialized, tevent_prep_atfork);
419 if (ret != 0) {
420 talloc_free(ev);
421 return NULL;
424 ret = pthread_mutex_init(&ev->scheduled_mutex, NULL);
425 if (ret != 0) {
426 talloc_free(ev);
427 return NULL;
430 ret = pthread_mutex_lock(&tevent_contexts_mutex);
431 if (ret != 0) {
432 pthread_mutex_destroy(&ev->scheduled_mutex);
433 talloc_free(ev);
434 return NULL;
437 DLIST_ADD(tevent_contexts, ev);
439 ret = pthread_mutex_unlock(&tevent_contexts_mutex);
440 if (ret != 0) {
441 abort();
444 #endif
446 talloc_set_destructor(ev, tevent_common_context_destructor);
448 ev->ops = ops;
449 ev->additional_data = additional_data;
451 ret = ev->ops->context_init(ev);
452 if (ret != 0) {
453 talloc_free(ev);
454 return NULL;
457 return ev;
461 create a event_context structure. This must be the first events
462 call, and all subsequent calls pass this event_context as the first
463 element. Event handlers also receive this as their first argument.
465 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
466 const char *name)
468 const struct tevent_ops *ops;
470 ops = tevent_find_ops_byname(name);
471 if (ops == NULL) {
472 return NULL;
475 return tevent_context_init_ops(mem_ctx, ops, NULL);
480 create a event_context structure. This must be the first events
481 call, and all subsequent calls pass this event_context as the first
482 element. Event handlers also receive this as their first argument.
484 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
486 return tevent_context_init_byname(mem_ctx, NULL);
490 add a fd based event
491 return NULL on failure (memory allocation error)
493 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
494 TALLOC_CTX *mem_ctx,
495 int fd,
496 uint16_t flags,
497 tevent_fd_handler_t handler,
498 void *private_data,
499 const char *handler_name,
500 const char *location)
502 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
503 handler_name, location);
507 set a close function on the fd event
509 void tevent_fd_set_close_fn(struct tevent_fd *fde,
510 tevent_fd_close_fn_t close_fn)
512 if (!fde) return;
513 if (!fde->event_ctx) return;
514 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
517 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
518 struct tevent_fd *fde,
519 int fd,
520 void *private_data)
522 close(fd);
525 void tevent_fd_set_auto_close(struct tevent_fd *fde)
527 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
531 return the fd event flags
533 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
535 if (!fde) return 0;
536 if (!fde->event_ctx) return 0;
537 return fde->event_ctx->ops->get_fd_flags(fde);
541 set the fd event flags
543 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
545 if (!fde) return;
546 if (!fde->event_ctx) return;
547 fde->event_ctx->ops->set_fd_flags(fde, flags);
550 bool tevent_signal_support(struct tevent_context *ev)
552 if (ev->ops->add_signal) {
553 return true;
555 return false;
558 static void (*tevent_abort_fn)(const char *reason);
560 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
562 tevent_abort_fn = abort_fn;
565 static void tevent_abort(struct tevent_context *ev, const char *reason)
567 tevent_debug(ev, TEVENT_DEBUG_FATAL,
568 "abort: %s\n", reason);
570 if (!tevent_abort_fn) {
571 abort();
574 tevent_abort_fn(reason);
578 add a timer event
579 return NULL on failure
581 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
582 TALLOC_CTX *mem_ctx,
583 struct timeval next_event,
584 tevent_timer_handler_t handler,
585 void *private_data,
586 const char *handler_name,
587 const char *location)
589 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
590 handler_name, location);
594 allocate an immediate event
595 return NULL on failure (memory allocation error)
597 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
598 const char *location)
600 struct tevent_immediate *im;
602 im = talloc(mem_ctx, struct tevent_immediate);
603 if (im == NULL) return NULL;
605 im->prev = NULL;
606 im->next = NULL;
607 im->event_ctx = NULL;
608 im->create_location = location;
609 im->handler = NULL;
610 im->private_data = NULL;
611 im->handler_name = NULL;
612 im->schedule_location = NULL;
613 im->cancel_fn = NULL;
614 im->additional_data = NULL;
616 return im;
620 schedule an immediate event
622 void _tevent_schedule_immediate(struct tevent_immediate *im,
623 struct tevent_context *ev,
624 tevent_immediate_handler_t handler,
625 void *private_data,
626 const char *handler_name,
627 const char *location)
629 ev->ops->schedule_immediate(im, ev, handler, private_data,
630 handler_name, location);
634 add a signal event
636 sa_flags are flags to sigaction(2)
638 return NULL on failure
640 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
641 TALLOC_CTX *mem_ctx,
642 int signum,
643 int sa_flags,
644 tevent_signal_handler_t handler,
645 void *private_data,
646 const char *handler_name,
647 const char *location)
649 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
650 handler_name, location);
653 void tevent_loop_allow_nesting(struct tevent_context *ev)
655 ev->nesting.allowed = true;
658 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
659 tevent_nesting_hook hook,
660 void *private_data)
662 if (ev->nesting.hook_fn &&
663 (ev->nesting.hook_fn != hook ||
664 ev->nesting.hook_private != private_data)) {
665 /* the way the nesting hook code is currently written
666 we cannot support two different nesting hooks at the
667 same time. */
668 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
670 ev->nesting.hook_fn = hook;
671 ev->nesting.hook_private = private_data;
674 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
676 const char *reason;
678 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
679 location);
680 if (!reason) {
681 reason = "tevent_loop_once() nesting";
684 tevent_abort(ev, reason);
688 do a single event loop using the events defined in ev
690 int _tevent_loop_once(struct tevent_context *ev, const char *location)
692 int ret;
693 void *nesting_stack_ptr = NULL;
695 ev->nesting.level++;
697 if (ev->nesting.level > 1) {
698 if (!ev->nesting.allowed) {
699 tevent_abort_nesting(ev, location);
700 errno = ELOOP;
701 return -1;
704 if (ev->nesting.level > 0) {
705 if (ev->nesting.hook_fn) {
706 int ret2;
707 ret2 = ev->nesting.hook_fn(ev,
708 ev->nesting.hook_private,
709 ev->nesting.level,
710 true,
711 (void *)&nesting_stack_ptr,
712 location);
713 if (ret2 != 0) {
714 ret = ret2;
715 goto done;
720 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
721 ret = ev->ops->loop_once(ev, location);
722 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
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 false,
731 (void *)&nesting_stack_ptr,
732 location);
733 if (ret2 != 0) {
734 ret = ret2;
735 goto done;
740 done:
741 ev->nesting.level--;
742 return ret;
746 this is a performance optimization for the samba4 nested event loop problems
748 int _tevent_loop_until(struct tevent_context *ev,
749 bool (*finished)(void *private_data),
750 void *private_data,
751 const char *location)
753 int ret = 0;
754 void *nesting_stack_ptr = NULL;
756 ev->nesting.level++;
758 if (ev->nesting.level > 1) {
759 if (!ev->nesting.allowed) {
760 tevent_abort_nesting(ev, location);
761 errno = ELOOP;
762 return -1;
765 if (ev->nesting.level > 0) {
766 if (ev->nesting.hook_fn) {
767 int ret2;
768 ret2 = ev->nesting.hook_fn(ev,
769 ev->nesting.hook_private,
770 ev->nesting.level,
771 true,
772 (void *)&nesting_stack_ptr,
773 location);
774 if (ret2 != 0) {
775 ret = ret2;
776 goto done;
781 while (!finished(private_data)) {
782 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
783 ret = ev->ops->loop_once(ev, location);
784 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
785 if (ret != 0) {
786 break;
790 if (ev->nesting.level > 0) {
791 if (ev->nesting.hook_fn) {
792 int ret2;
793 ret2 = ev->nesting.hook_fn(ev,
794 ev->nesting.hook_private,
795 ev->nesting.level,
796 false,
797 (void *)&nesting_stack_ptr,
798 location);
799 if (ret2 != 0) {
800 ret = ret2;
801 goto done;
806 done:
807 ev->nesting.level--;
808 return ret;
811 bool tevent_common_have_events(struct tevent_context *ev)
813 if (ev->fd_events != NULL) {
814 if (ev->fd_events != ev->wakeup_fde) {
815 return true;
817 if (ev->fd_events->next != NULL) {
818 return true;
822 * At this point we just have the wakeup pipe event as
823 * the only fd_event. That one does not count as a
824 * regular event, so look at the other event types.
828 return ((ev->timer_events != NULL) ||
829 (ev->immediate_events != NULL) ||
830 (ev->signal_events != NULL));
834 return on failure or (with 0) if all fd events are removed
836 int tevent_common_loop_wait(struct tevent_context *ev,
837 const char *location)
840 * loop as long as we have events pending
842 while (tevent_common_have_events(ev)) {
843 int ret;
844 ret = _tevent_loop_once(ev, location);
845 if (ret != 0) {
846 tevent_debug(ev, TEVENT_DEBUG_FATAL,
847 "_tevent_loop_once() failed: %d - %s\n",
848 ret, strerror(errno));
849 return ret;
853 tevent_debug(ev, TEVENT_DEBUG_WARNING,
854 "tevent_common_loop_wait() out of events\n");
855 return 0;
859 return on failure or (with 0) if all fd events are removed
861 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
863 return ev->ops->loop_wait(ev, location);
868 re-initialise a tevent context. This leaves you with the same
869 event context, but all events are wiped and the structure is
870 re-initialised. This is most useful after a fork()
872 zero is returned on success, non-zero on failure
874 int tevent_re_initialise(struct tevent_context *ev)
876 tevent_common_context_destructor(ev);
878 return ev->ops->context_init(ev);
881 static void wakeup_pipe_handler(struct tevent_context *ev,
882 struct tevent_fd *fde,
883 uint16_t flags, void *_private)
885 ssize_t ret;
887 do {
889 * This is the boilerplate for eventfd, but it works
890 * for pipes too. And as we don't care about the data
891 * we read, we're fine.
893 uint64_t val;
894 ret = read(fde->fd, &val, sizeof(val));
895 } while (ret == -1 && errno == EINTR);
899 * Initialize the wakeup pipe and pipe fde
902 int tevent_common_wakeup_init(struct tevent_context *ev)
904 int ret, read_fd;
906 if (ev->wakeup_fde != NULL) {
907 return 0;
910 #ifdef HAVE_EVENTFD
911 ret = eventfd(0, EFD_NONBLOCK);
912 if (ret == -1) {
913 return errno;
915 read_fd = ev->wakeup_fd = ret;
916 #else
918 int pipe_fds[2];
919 ret = pipe(pipe_fds);
920 if (ret == -1) {
921 return errno;
923 ev->wakeup_fd = pipe_fds[1];
924 ev->wakeup_read_fd = pipe_fds[0];
926 ev_set_blocking(ev->wakeup_fd, false);
927 ev_set_blocking(ev->wakeup_read_fd, false);
929 read_fd = ev->wakeup_read_fd;
931 #endif
933 ev->wakeup_fde = tevent_add_fd(ev, ev, read_fd, TEVENT_FD_READ,
934 wakeup_pipe_handler, NULL);
935 if (ev->wakeup_fde == NULL) {
936 close(ev->wakeup_fd);
937 #ifndef HAVE_EVENTFD
938 close(ev->wakeup_read_fd);
939 #endif
940 return ENOMEM;
943 return 0;
946 int tevent_common_wakeup_fd(int fd)
948 ssize_t ret;
950 do {
951 #ifdef HAVE_EVENTFD
952 uint64_t val = 1;
953 ret = write(fd, &val, sizeof(val));
954 #else
955 char c = '\0';
956 ret = write(fd, &c, 1);
957 #endif
958 } while ((ret == -1) && (errno == EINTR));
960 return 0;
963 int tevent_common_wakeup(struct tevent_context *ev)
965 if (ev->wakeup_fde == NULL) {
966 return ENOTCONN;
969 return tevent_common_wakeup_fd(ev->wakeup_fd);
972 static void tevent_common_wakeup_fini(struct tevent_context *ev)
974 if (ev->wakeup_fde == NULL) {
975 return;
978 TALLOC_FREE(ev->wakeup_fde);
980 close(ev->wakeup_fd);
981 #ifndef HAVE_EVENTFD
982 close(ev->wakeup_read_fd);
983 #endif