s4:auth_winbind: remove unused 'winbind_wbclient' backend
[Samba.git] / lib / tevent / tevent.c
bloba2d2003cbf4322dd1524e7e7e40edcbd37e10d5b
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_poll_init();
132 tevent_poll_mt_init();
133 #if defined(HAVE_EPOLL)
134 tevent_epoll_init();
135 #elif defined(HAVE_SOLARIS_PORTS)
136 tevent_port_init();
137 #endif
139 tevent_standard_init();
142 _PRIVATE_ const struct tevent_ops *tevent_find_ops_byname(const char *name)
144 struct tevent_ops_list *e;
146 tevent_backend_init();
148 if (name == NULL) {
149 name = tevent_default_backend;
151 if (name == NULL) {
152 name = "standard";
155 for (e = tevent_backends; e != NULL; e = e->next) {
156 if (0 == strcmp(e->name, name)) {
157 return e->ops;
161 return NULL;
165 list available backends
167 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
169 const char **list = NULL;
170 struct tevent_ops_list *e;
172 tevent_backend_init();
174 for (e=tevent_backends;e;e=e->next) {
175 list = ev_str_list_add(list, e->name);
178 talloc_steal(mem_ctx, list);
180 return list;
183 static void tevent_common_wakeup_fini(struct tevent_context *ev);
185 #ifdef HAVE_PTHREAD
187 static pthread_mutex_t tevent_contexts_mutex = PTHREAD_MUTEX_INITIALIZER;
188 static struct tevent_context *tevent_contexts = NULL;
189 static pthread_once_t tevent_atfork_initialized = PTHREAD_ONCE_INIT;
191 static void tevent_atfork_prepare(void)
193 struct tevent_context *ev;
194 int ret;
196 ret = pthread_mutex_lock(&tevent_contexts_mutex);
197 if (ret != 0) {
198 abort();
201 for (ev = tevent_contexts; ev != NULL; ev = ev->next) {
202 struct tevent_threaded_context *tctx;
204 for (tctx = ev->threaded_contexts; tctx != NULL;
205 tctx = tctx->next) {
206 ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
207 if (ret != 0) {
208 tevent_abort(ev, "pthread_mutex_lock failed");
212 ret = pthread_mutex_lock(&ev->scheduled_mutex);
213 if (ret != 0) {
214 tevent_abort(ev, "pthread_mutex_lock failed");
219 static void tevent_atfork_parent(void)
221 struct tevent_context *ev;
222 int ret;
224 for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
225 ev = DLIST_PREV(ev)) {
226 struct tevent_threaded_context *tctx;
228 ret = pthread_mutex_unlock(&ev->scheduled_mutex);
229 if (ret != 0) {
230 tevent_abort(ev, "pthread_mutex_unlock failed");
233 for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
234 tctx = DLIST_PREV(tctx)) {
235 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
236 if (ret != 0) {
237 tevent_abort(
238 ev, "pthread_mutex_unlock failed");
243 ret = pthread_mutex_unlock(&tevent_contexts_mutex);
244 if (ret != 0) {
245 abort();
249 static void tevent_atfork_child(void)
251 struct tevent_context *ev;
252 int ret;
254 for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
255 ev = DLIST_PREV(ev)) {
256 struct tevent_threaded_context *tctx;
258 for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
259 tctx = DLIST_PREV(tctx)) {
260 tctx->event_ctx = NULL;
262 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
263 if (ret != 0) {
264 tevent_abort(
265 ev, "pthread_mutex_unlock failed");
269 ev->threaded_contexts = NULL;
271 ret = pthread_mutex_unlock(&ev->scheduled_mutex);
272 if (ret != 0) {
273 tevent_abort(ev, "pthread_mutex_unlock failed");
277 ret = pthread_mutex_unlock(&tevent_contexts_mutex);
278 if (ret != 0) {
279 abort();
283 static void tevent_prep_atfork(void)
285 int ret;
287 ret = pthread_atfork(tevent_atfork_prepare,
288 tevent_atfork_parent,
289 tevent_atfork_child);
290 if (ret != 0) {
291 abort();
295 #endif
297 int tevent_common_context_destructor(struct tevent_context *ev)
299 struct tevent_fd *fd, *fn;
300 struct tevent_timer *te, *tn;
301 struct tevent_immediate *ie, *in;
302 struct tevent_signal *se, *sn;
304 #ifdef HAVE_PTHREAD
305 int ret;
307 ret = pthread_mutex_lock(&tevent_contexts_mutex);
308 if (ret != 0) {
309 abort();
312 DLIST_REMOVE(tevent_contexts, ev);
314 ret = pthread_mutex_unlock(&tevent_contexts_mutex);
315 if (ret != 0) {
316 abort();
319 while (ev->threaded_contexts != NULL) {
320 struct tevent_threaded_context *tctx = ev->threaded_contexts;
322 ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
323 if (ret != 0) {
324 abort();
328 * Indicate to the thread that the tevent_context is
329 * gone. The counterpart of this is in
330 * _tevent_threaded_schedule_immediate, there we read
331 * this under the threaded_context's mutex.
334 tctx->event_ctx = NULL;
336 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
337 if (ret != 0) {
338 abort();
341 DLIST_REMOVE(ev->threaded_contexts, tctx);
344 ret = pthread_mutex_destroy(&ev->scheduled_mutex);
345 if (ret != 0) {
346 abort();
348 #endif
350 tevent_common_wakeup_fini(ev);
352 for (fd = ev->fd_events; fd; fd = fn) {
353 fn = fd->next;
354 fd->event_ctx = NULL;
355 DLIST_REMOVE(ev->fd_events, fd);
358 ev->last_zero_timer = NULL;
359 for (te = ev->timer_events; te; te = tn) {
360 tn = te->next;
361 te->event_ctx = NULL;
362 DLIST_REMOVE(ev->timer_events, te);
365 for (ie = ev->immediate_events; ie; ie = in) {
366 in = ie->next;
367 ie->event_ctx = NULL;
368 ie->cancel_fn = NULL;
369 DLIST_REMOVE(ev->immediate_events, ie);
372 for (se = ev->signal_events; se; se = sn) {
373 sn = se->next;
374 se->event_ctx = NULL;
375 DLIST_REMOVE(ev->signal_events, se);
377 * This is important, Otherwise signals
378 * are handled twice in child. eg, SIGHUP.
379 * one added in parent, and another one in
380 * the child. -- BoYang
382 tevent_cleanup_pending_signal_handlers(se);
385 /* removing nesting hook or we get an abort when nesting is
386 * not allowed. -- SSS
387 * Note that we need to leave the allowed flag at its current
388 * value, otherwise the use in tevent_re_initialise() will
389 * leave the event context with allowed forced to false, which
390 * will break users that expect nesting to be allowed
392 ev->nesting.level = 0;
393 ev->nesting.hook_fn = NULL;
394 ev->nesting.hook_private = NULL;
396 return 0;
399 static int tevent_common_context_constructor(struct tevent_context *ev)
401 int ret;
403 #ifdef HAVE_PTHREAD
405 ret = pthread_once(&tevent_atfork_initialized, tevent_prep_atfork);
406 if (ret != 0) {
407 return ret;
410 ret = pthread_mutex_init(&ev->scheduled_mutex, NULL);
411 if (ret != 0) {
412 return ret;
415 ret = pthread_mutex_lock(&tevent_contexts_mutex);
416 if (ret != 0) {
417 pthread_mutex_destroy(&ev->scheduled_mutex);
418 return ret;
421 DLIST_ADD(tevent_contexts, ev);
423 ret = pthread_mutex_unlock(&tevent_contexts_mutex);
424 if (ret != 0) {
425 abort();
427 #endif
429 talloc_set_destructor(ev, tevent_common_context_destructor);
431 return 0;
435 create a event_context structure for a specific implemementation.
436 This must be the first events call, and all subsequent calls pass
437 this event_context as the first element. Event handlers also
438 receive this as their first argument.
440 This function is for allowing third-party-applications to hook in gluecode
441 to their own event loop code, so that they can make async usage of our client libs
443 NOTE: use tevent_context_init() inside of samba!
445 struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
446 const struct tevent_ops *ops,
447 void *additional_data)
449 struct tevent_context *ev;
450 int ret;
452 ev = talloc_zero(mem_ctx, struct tevent_context);
453 if (!ev) return NULL;
455 ret = tevent_common_context_constructor(ev);
456 if (ret != 0) {
457 talloc_free(ev);
458 return NULL;
461 ev->ops = ops;
462 ev->additional_data = additional_data;
464 ret = ev->ops->context_init(ev);
465 if (ret != 0) {
466 talloc_free(ev);
467 return NULL;
470 return ev;
474 create a event_context structure. This must be the first events
475 call, and all subsequent calls pass this event_context as the first
476 element. Event handlers also receive this as their first argument.
478 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
479 const char *name)
481 const struct tevent_ops *ops;
483 ops = tevent_find_ops_byname(name);
484 if (ops == NULL) {
485 return NULL;
488 return tevent_context_init_ops(mem_ctx, ops, NULL);
493 create a event_context structure. This must be the first events
494 call, and all subsequent calls pass this event_context as the first
495 element. Event handlers also receive this as their first argument.
497 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
499 return tevent_context_init_byname(mem_ctx, NULL);
503 add a fd based event
504 return NULL on failure (memory allocation error)
506 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
507 TALLOC_CTX *mem_ctx,
508 int fd,
509 uint16_t flags,
510 tevent_fd_handler_t handler,
511 void *private_data,
512 const char *handler_name,
513 const char *location)
515 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
516 handler_name, location);
520 set a close function on the fd event
522 void tevent_fd_set_close_fn(struct tevent_fd *fde,
523 tevent_fd_close_fn_t close_fn)
525 if (!fde) return;
526 if (!fde->event_ctx) return;
527 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
530 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
531 struct tevent_fd *fde,
532 int fd,
533 void *private_data)
535 close(fd);
538 void tevent_fd_set_auto_close(struct tevent_fd *fde)
540 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
544 return the fd event flags
546 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
548 if (!fde) return 0;
549 if (!fde->event_ctx) return 0;
550 return fde->event_ctx->ops->get_fd_flags(fde);
554 set the fd event flags
556 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
558 if (!fde) return;
559 if (!fde->event_ctx) return;
560 fde->event_ctx->ops->set_fd_flags(fde, flags);
563 bool tevent_signal_support(struct tevent_context *ev)
565 if (ev->ops->add_signal) {
566 return true;
568 return false;
571 static void (*tevent_abort_fn)(const char *reason);
573 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
575 tevent_abort_fn = abort_fn;
578 static void tevent_abort(struct tevent_context *ev, const char *reason)
580 tevent_debug(ev, TEVENT_DEBUG_FATAL,
581 "abort: %s\n", reason);
583 if (!tevent_abort_fn) {
584 abort();
587 tevent_abort_fn(reason);
591 add a timer event
592 return NULL on failure
594 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
595 TALLOC_CTX *mem_ctx,
596 struct timeval next_event,
597 tevent_timer_handler_t handler,
598 void *private_data,
599 const char *handler_name,
600 const char *location)
602 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
603 handler_name, location);
607 allocate an immediate event
608 return NULL on failure (memory allocation error)
610 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
611 const char *location)
613 struct tevent_immediate *im;
615 im = talloc(mem_ctx, struct tevent_immediate);
616 if (im == NULL) return NULL;
618 *im = (struct tevent_immediate) { .create_location = location };
620 return im;
624 schedule an immediate event
626 void _tevent_schedule_immediate(struct tevent_immediate *im,
627 struct tevent_context *ev,
628 tevent_immediate_handler_t handler,
629 void *private_data,
630 const char *handler_name,
631 const char *location)
633 ev->ops->schedule_immediate(im, ev, handler, private_data,
634 handler_name, location);
638 add a signal event
640 sa_flags are flags to sigaction(2)
642 return NULL on failure
644 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
645 TALLOC_CTX *mem_ctx,
646 int signum,
647 int sa_flags,
648 tevent_signal_handler_t handler,
649 void *private_data,
650 const char *handler_name,
651 const char *location)
653 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
654 handler_name, location);
657 void tevent_loop_allow_nesting(struct tevent_context *ev)
659 ev->nesting.allowed = true;
662 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
663 tevent_nesting_hook hook,
664 void *private_data)
666 if (ev->nesting.hook_fn &&
667 (ev->nesting.hook_fn != hook ||
668 ev->nesting.hook_private != private_data)) {
669 /* the way the nesting hook code is currently written
670 we cannot support two different nesting hooks at the
671 same time. */
672 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
674 ev->nesting.hook_fn = hook;
675 ev->nesting.hook_private = private_data;
678 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
680 const char *reason;
682 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
683 location);
684 if (!reason) {
685 reason = "tevent_loop_once() nesting";
688 tevent_abort(ev, reason);
692 do a single event loop using the events defined in ev
694 int _tevent_loop_once(struct tevent_context *ev, const char *location)
696 int ret;
697 void *nesting_stack_ptr = NULL;
699 ev->nesting.level++;
701 if (ev->nesting.level > 1) {
702 if (!ev->nesting.allowed) {
703 tevent_abort_nesting(ev, location);
704 errno = ELOOP;
705 return -1;
708 if (ev->nesting.level > 0) {
709 if (ev->nesting.hook_fn) {
710 int ret2;
711 ret2 = ev->nesting.hook_fn(ev,
712 ev->nesting.hook_private,
713 ev->nesting.level,
714 true,
715 (void *)&nesting_stack_ptr,
716 location);
717 if (ret2 != 0) {
718 ret = ret2;
719 goto done;
724 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
725 ret = ev->ops->loop_once(ev, location);
726 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
728 if (ev->nesting.level > 0) {
729 if (ev->nesting.hook_fn) {
730 int ret2;
731 ret2 = ev->nesting.hook_fn(ev,
732 ev->nesting.hook_private,
733 ev->nesting.level,
734 false,
735 (void *)&nesting_stack_ptr,
736 location);
737 if (ret2 != 0) {
738 ret = ret2;
739 goto done;
744 done:
745 ev->nesting.level--;
746 return ret;
750 this is a performance optimization for the samba4 nested event loop problems
752 int _tevent_loop_until(struct tevent_context *ev,
753 bool (*finished)(void *private_data),
754 void *private_data,
755 const char *location)
757 int ret = 0;
758 void *nesting_stack_ptr = NULL;
760 ev->nesting.level++;
762 if (ev->nesting.level > 1) {
763 if (!ev->nesting.allowed) {
764 tevent_abort_nesting(ev, location);
765 errno = ELOOP;
766 return -1;
769 if (ev->nesting.level > 0) {
770 if (ev->nesting.hook_fn) {
771 int ret2;
772 ret2 = ev->nesting.hook_fn(ev,
773 ev->nesting.hook_private,
774 ev->nesting.level,
775 true,
776 (void *)&nesting_stack_ptr,
777 location);
778 if (ret2 != 0) {
779 ret = ret2;
780 goto done;
785 while (!finished(private_data)) {
786 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
787 ret = ev->ops->loop_once(ev, location);
788 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
789 if (ret != 0) {
790 break;
794 if (ev->nesting.level > 0) {
795 if (ev->nesting.hook_fn) {
796 int ret2;
797 ret2 = ev->nesting.hook_fn(ev,
798 ev->nesting.hook_private,
799 ev->nesting.level,
800 false,
801 (void *)&nesting_stack_ptr,
802 location);
803 if (ret2 != 0) {
804 ret = ret2;
805 goto done;
810 done:
811 ev->nesting.level--;
812 return ret;
815 bool tevent_common_have_events(struct tevent_context *ev)
817 if (ev->fd_events != NULL) {
818 if (ev->fd_events != ev->wakeup_fde) {
819 return true;
821 if (ev->fd_events->next != NULL) {
822 return true;
826 * At this point we just have the wakeup pipe event as
827 * the only fd_event. That one does not count as a
828 * regular event, so look at the other event types.
832 return ((ev->timer_events != NULL) ||
833 (ev->immediate_events != NULL) ||
834 (ev->signal_events != NULL));
838 return on failure or (with 0) if all fd events are removed
840 int tevent_common_loop_wait(struct tevent_context *ev,
841 const char *location)
844 * loop as long as we have events pending
846 while (tevent_common_have_events(ev)) {
847 int ret;
848 ret = _tevent_loop_once(ev, location);
849 if (ret != 0) {
850 tevent_debug(ev, TEVENT_DEBUG_FATAL,
851 "_tevent_loop_once() failed: %d - %s\n",
852 ret, strerror(errno));
853 return ret;
857 tevent_debug(ev, TEVENT_DEBUG_WARNING,
858 "tevent_common_loop_wait() out of events\n");
859 return 0;
863 return on failure or (with 0) if all fd events are removed
865 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
867 return ev->ops->loop_wait(ev, location);
872 re-initialise a tevent context. This leaves you with the same
873 event context, but all events are wiped and the structure is
874 re-initialised. This is most useful after a fork()
876 zero is returned on success, non-zero on failure
878 int tevent_re_initialise(struct tevent_context *ev)
880 tevent_common_context_destructor(ev);
882 tevent_common_context_constructor(ev);
884 return ev->ops->context_init(ev);
887 static void wakeup_pipe_handler(struct tevent_context *ev,
888 struct tevent_fd *fde,
889 uint16_t flags, void *_private)
891 ssize_t ret;
893 do {
895 * This is the boilerplate for eventfd, but it works
896 * for pipes too. And as we don't care about the data
897 * we read, we're fine.
899 uint64_t val;
900 ret = read(fde->fd, &val, sizeof(val));
901 } while (ret == -1 && errno == EINTR);
905 * Initialize the wakeup pipe and pipe fde
908 int tevent_common_wakeup_init(struct tevent_context *ev)
910 int ret, read_fd;
912 if (ev->wakeup_fde != NULL) {
913 return 0;
916 #ifdef HAVE_EVENTFD
917 ret = eventfd(0, EFD_NONBLOCK);
918 if (ret == -1) {
919 return errno;
921 read_fd = ev->wakeup_fd = ret;
922 #else
924 int pipe_fds[2];
925 ret = pipe(pipe_fds);
926 if (ret == -1) {
927 return errno;
929 ev->wakeup_fd = pipe_fds[1];
930 ev->wakeup_read_fd = pipe_fds[0];
932 ev_set_blocking(ev->wakeup_fd, false);
933 ev_set_blocking(ev->wakeup_read_fd, false);
935 read_fd = ev->wakeup_read_fd;
937 #endif
939 ev->wakeup_fde = tevent_add_fd(ev, ev, read_fd, TEVENT_FD_READ,
940 wakeup_pipe_handler, NULL);
941 if (ev->wakeup_fde == NULL) {
942 close(ev->wakeup_fd);
943 #ifndef HAVE_EVENTFD
944 close(ev->wakeup_read_fd);
945 #endif
946 return ENOMEM;
949 return 0;
952 int tevent_common_wakeup_fd(int fd)
954 ssize_t ret;
956 do {
957 #ifdef HAVE_EVENTFD
958 uint64_t val = 1;
959 ret = write(fd, &val, sizeof(val));
960 #else
961 char c = '\0';
962 ret = write(fd, &c, 1);
963 #endif
964 } while ((ret == -1) && (errno == EINTR));
966 return 0;
969 int tevent_common_wakeup(struct tevent_context *ev)
971 if (ev->wakeup_fde == NULL) {
972 return ENOTCONN;
975 return tevent_common_wakeup_fd(ev->wakeup_fd);
978 static void tevent_common_wakeup_fini(struct tevent_context *ev)
980 if (ev->wakeup_fde == NULL) {
981 return;
984 TALLOC_FREE(ev->wakeup_fde);
986 close(ev->wakeup_fd);
987 #ifndef HAVE_EVENTFD
988 close(ev->wakeup_read_fd);
989 #endif