summaryrefslogtreecommitdiffstats
path: root/ctdb/lib
diff options
context:
space:
mode:
authorAmitay Isaacs <amitay@gmail.com>2013-05-29 14:12:14 +1000
committerAmitay Isaacs <amitay@gmail.com>2013-05-29 17:47:16 +1000
commit2afa275a683d31ebf3b697821999939df99cdd8d (patch)
treed8460991cbfbceda9ec90d1ba52191e00d109150 /ctdb/lib
parent4c1dc871b9ebdb9a83ab7b4714d89e451ea0783a (diff)
downloadsamba-2afa275a683d31ebf3b697821999939df99cdd8d.tar.gz
samba-2afa275a683d31ebf3b697821999939df99cdd8d.tar.xz
samba-2afa275a683d31ebf3b697821999939df99cdd8d.zip
tevent: Sync to tevent 0.9.18 from upstream
(This used to be ctdb commit 82d61f77c01df0fbb42743593937b175ce22a445)
Diffstat (limited to 'ctdb/lib')
-rw-r--r--ctdb/lib/tevent/ABI/tevent-0.9.10.sigs73
-rw-r--r--ctdb/lib/tevent/ABI/tevent-0.9.11.sigs73
-rw-r--r--ctdb/lib/tevent/ABI/tevent-0.9.12.sigs74
-rw-r--r--ctdb/lib/tevent/ABI/tevent-0.9.13.sigs75
-rw-r--r--ctdb/lib/tevent/ABI/tevent-0.9.14.sigs78
-rw-r--r--ctdb/lib/tevent/ABI/tevent-0.9.17.sigs82
-rw-r--r--ctdb/lib/tevent/ABI/tevent-0.9.18.sigs83
-rw-r--r--ctdb/lib/tevent/ABI/tevent-0.9.9.sigs73
-rw-r--r--ctdb/lib/tevent/bindings.py62
-rw-r--r--ctdb/lib/tevent/doxy.config5
-rw-r--r--ctdb/lib/tevent/pytevent.c766
-rwxr-xr-xctdb/lib/tevent/release-script.sh48
-rw-r--r--ctdb/lib/tevent/testsuite.c701
-rw-r--r--ctdb/lib/tevent/tevent.c65
-rw-r--r--ctdb/lib/tevent/tevent.h13
-rw-r--r--ctdb/lib/tevent/tevent.pc.in2
-rw-r--r--ctdb/lib/tevent/tevent.py29
-rw-r--r--ctdb/lib/tevent/tevent_epoll.c625
-rw-r--r--ctdb/lib/tevent/tevent_immediate.c1
-rw-r--r--ctdb/lib/tevent/tevent_internal.h26
-rw-r--r--ctdb/lib/tevent/tevent_liboop.c20
-rw-r--r--ctdb/lib/tevent/tevent_poll.c567
-rw-r--r--ctdb/lib/tevent/tevent_select.c33
-rw-r--r--ctdb/lib/tevent/tevent_signal.c41
-rw-r--r--ctdb/lib/tevent/tevent_standard.c632
-rw-r--r--ctdb/lib/tevent/tevent_timed.c122
-rw-r--r--ctdb/lib/tevent/tevent_wakeup.c1
-rwxr-xr-xctdb/lib/tevent/wscript138
28 files changed, 3782 insertions, 726 deletions
diff --git a/ctdb/lib/tevent/ABI/tevent-0.9.10.sigs b/ctdb/lib/tevent/ABI/tevent-0.9.10.sigs
new file mode 100644
index 00000000000..9adaba579b8
--- /dev/null
+++ b/ctdb/lib/tevent/ABI/tevent-0.9.10.sigs
@@ -0,0 +1,73 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/ctdb/lib/tevent/ABI/tevent-0.9.11.sigs b/ctdb/lib/tevent/ABI/tevent-0.9.11.sigs
new file mode 100644
index 00000000000..9adaba579b8
--- /dev/null
+++ b/ctdb/lib/tevent/ABI/tevent-0.9.11.sigs
@@ -0,0 +1,73 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/ctdb/lib/tevent/ABI/tevent-0.9.12.sigs b/ctdb/lib/tevent/ABI/tevent-0.9.12.sigs
new file mode 100644
index 00000000000..df9b08dfd50
--- /dev/null
+++ b/ctdb/lib/tevent/ABI/tevent-0.9.12.sigs
@@ -0,0 +1,74 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/ctdb/lib/tevent/ABI/tevent-0.9.13.sigs b/ctdb/lib/tevent/ABI/tevent-0.9.13.sigs
new file mode 100644
index 00000000000..888ca0ee3c4
--- /dev/null
+++ b/ctdb/lib/tevent/ABI/tevent-0.9.13.sigs
@@ -0,0 +1,75 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/ctdb/lib/tevent/ABI/tevent-0.9.14.sigs b/ctdb/lib/tevent/ABI/tevent-0.9.14.sigs
new file mode 100644
index 00000000000..13c461cc563
--- /dev/null
+++ b/ctdb/lib/tevent/ABI/tevent-0.9.14.sigs
@@ -0,0 +1,78 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/ctdb/lib/tevent/ABI/tevent-0.9.17.sigs b/ctdb/lib/tevent/ABI/tevent-0.9.17.sigs
new file mode 100644
index 00000000000..ea7f9446e14
--- /dev/null
+++ b/ctdb/lib/tevent/ABI/tevent-0.9.17.sigs
@@ -0,0 +1,82 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/ctdb/lib/tevent/ABI/tevent-0.9.18.sigs b/ctdb/lib/tevent/ABI/tevent-0.9.18.sigs
new file mode 100644
index 00000000000..70d20b6816b
--- /dev/null
+++ b/ctdb/lib/tevent/ABI/tevent-0.9.18.sigs
@@ -0,0 +1,83 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_req_oom: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_running: bool (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/ctdb/lib/tevent/ABI/tevent-0.9.9.sigs b/ctdb/lib/tevent/ABI/tevent-0.9.9.sigs
new file mode 100644
index 00000000000..9adaba579b8
--- /dev/null
+++ b/ctdb/lib/tevent/ABI/tevent-0.9.9.sigs
@@ -0,0 +1,73 @@
+_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *)
+_tevent_loop_once: int (struct tevent_context *, const char *)
+_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *)
+_tevent_loop_wait: int (struct tevent_context *, const char *)
+_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *)
+_tevent_req_callback_data: void *(struct tevent_req *)
+_tevent_req_cancel: bool (struct tevent_req *, const char *)
+_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *)
+_tevent_req_data: void *(struct tevent_req *)
+_tevent_req_done: void (struct tevent_req *, const char *)
+_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *)
+_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *)
+_tevent_req_notify_callback: void (struct tevent_req *, const char *)
+_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_backend_list: const char **(TALLOC_CTX *)
+tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *)
+tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *)
+tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *)
+tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *)
+tevent_common_check_signal: int (struct tevent_context *)
+tevent_common_context_destructor: int (struct tevent_context *)
+tevent_common_fd_destructor: int (struct tevent_fd *)
+tevent_common_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_common_loop_immediate: bool (struct tevent_context *)
+tevent_common_loop_timer_delay: struct timeval (struct tevent_context *)
+tevent_common_loop_wait: int (struct tevent_context *, const char *)
+tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *)
+tevent_context_init: struct tevent_context *(TALLOC_CTX *)
+tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *)
+tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...)
+tevent_fd_get_flags: uint16_t (struct tevent_fd *)
+tevent_fd_set_auto_close: void (struct tevent_fd *)
+tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t)
+tevent_fd_set_flags: void (struct tevent_fd *, uint16_t)
+tevent_loop_allow_nesting: void (struct tevent_context *)
+tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *)
+tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *)
+tevent_queue_length: size_t (struct tevent_queue *)
+tevent_queue_start: void (struct tevent_queue *)
+tevent_queue_stop: void (struct tevent_queue *)
+tevent_re_initialise: int (struct tevent_context *)
+tevent_register_backend: bool (const char *, const struct tevent_ops *)
+tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *)
+tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *)
+tevent_req_is_in_progress: bool (struct tevent_req *)
+tevent_req_poll: bool (struct tevent_req *, struct tevent_context *)
+tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *)
+tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *)
+tevent_req_received: void (struct tevent_req *)
+tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *)
+tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn)
+tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval)
+tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn)
+tevent_set_abort_fn: void (void (*)(const char *))
+tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *)
+tevent_set_debug_stderr: int (struct tevent_context *)
+tevent_set_default_backend: void (const char *)
+tevent_signal_support: bool (struct tevent_context *)
+tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
+tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
+tevent_timeval_current: struct timeval (void)
+tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t)
+tevent_timeval_is_zero: bool (const struct timeval *)
+tevent_timeval_set: struct timeval (uint32_t, uint32_t)
+tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *)
+tevent_timeval_zero: struct timeval (void)
+tevent_wakeup_recv: bool (struct tevent_req *)
+tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval)
diff --git a/ctdb/lib/tevent/bindings.py b/ctdb/lib/tevent/bindings.py
new file mode 100644
index 00000000000..1060caf28df
--- /dev/null
+++ b/ctdb/lib/tevent/bindings.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+#
+# Python integration for tevent - tests
+#
+# Copyright (C) Jelmer Vernooij 2010
+#
+# ** NOTE! The following LGPL license applies to the tevent
+# ** library. This does NOT imply that all of Samba is released
+# ** under the LGPL
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+import signal
+import _tevent
+from unittest import TestCase
+
+class BackendListTests(TestCase):
+
+ def test_backend_list(self):
+ self.assertTrue(isinstance(_tevent.backend_list(), list))
+
+
+class CreateContextTests(TestCase):
+
+ def test_by_name(self):
+ ctx = _tevent.Context(_tevent.backend_list()[0])
+ self.assertTrue(ctx is not None)
+
+ def test_no_name(self):
+ ctx = _tevent.Context()
+ self.assertTrue(ctx is not None)
+
+
+class ContextTests(TestCase):
+
+ def setUp(self):
+ super(ContextTests, self).setUp()
+ self.ctx = _tevent.Context()
+
+ def test_signal_support(self):
+ self.assertTrue(type(self.ctx.signal_support) is bool)
+
+ def test_reinitialise(self):
+ self.ctx.reinitialise()
+
+ def test_loop_wait(self):
+ self.ctx.loop_wait()
+
+ def test_add_signal(self):
+ sig = self.ctx.add_signal(signal.SIGINT, 0, lambda callback: None)
+ self.assertTrue(isinstance(sig, _tevent.Signal))
diff --git a/ctdb/lib/tevent/doxy.config b/ctdb/lib/tevent/doxy.config
index 578ecafc77b..0d67ae35928 100644
--- a/ctdb/lib/tevent/doxy.config
+++ b/ctdb/lib/tevent/doxy.config
@@ -627,10 +627,7 @@ EXCLUDE_SYMLINKS = NO
# against the file with absolute path, so to exclude all test directories
# for example use the pattern */test/*
-EXCLUDE_PATTERNS = */.git/* \
- */.svn/* \
- */cmake/* \
- */build/*
+EXCLUDE_PATTERNS = */.git/*
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
diff --git a/ctdb/lib/tevent/pytevent.c b/ctdb/lib/tevent/pytevent.c
new file mode 100644
index 00000000000..870f5aad610
--- /dev/null
+++ b/ctdb/lib/tevent/pytevent.c
@@ -0,0 +1,766 @@
+/*
+ Unix SMB/CIFS implementation.
+ Python bindings for tevent
+
+ Copyright (C) Jelmer Vernooij 2010
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+#include <tevent.h>
+
+void init_tevent(void);
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_context *ev;
+} TeventContext_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_queue *queue;
+} TeventQueue_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_req *req;
+} TeventReq_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_signal *signal;
+} TeventSignal_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_timer *timer;
+} TeventTimer_Object;
+
+typedef struct {
+ PyObject_HEAD
+ struct tevent_fd *fd;
+} TeventFd_Object;
+
+staticforward PyTypeObject TeventContext_Type;
+staticforward PyTypeObject TeventReq_Type;
+staticforward PyTypeObject TeventQueue_Type;
+staticforward PyTypeObject TeventSignal_Type;
+staticforward PyTypeObject TeventTimer_Type;
+staticforward PyTypeObject TeventFd_Type;
+
+static int py_context_init(struct tevent_context *ev)
+{
+ /* FIXME */
+ return 0;
+}
+
+static struct tevent_fd *py_add_fd(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int fd, uint16_t flags,
+ tevent_fd_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ /* FIXME */
+ return NULL;
+}
+
+static void py_set_fd_close_fn(struct tevent_fd *fde,
+ tevent_fd_close_fn_t close_fn)
+{
+ /* FIXME */
+}
+
+static uint16_t py_get_fd_flags(struct tevent_fd *fde)
+{
+ /* FIXME */
+ return 0;
+}
+
+static void py_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ /* FIXME */
+}
+
+/* timed_event functions */
+static struct tevent_timer *py_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ /* FIXME */
+ return NULL;
+}
+
+/* immediate event functions */
+static void py_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ /* FIXME */
+}
+
+/* signal functions */
+static struct tevent_signal *py_add_signal(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ int signum, int sa_flags,
+ tevent_signal_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ /* FIXME */
+ return NULL;
+}
+
+/* loop functions */
+static int py_loop_once(struct tevent_context *ev, const char *location)
+{
+ /* FIXME */
+ return 0;
+}
+
+static int py_loop_wait(struct tevent_context *ev, const char *location)
+{
+ /* FIXME */
+ return 0;
+}
+
+const static struct tevent_ops py_tevent_ops = {
+ .context_init = py_context_init,
+ .add_fd = py_add_fd,
+ .set_fd_close_fn = py_set_fd_close_fn,
+ .get_fd_flags = py_get_fd_flags,
+ .set_fd_flags = py_set_fd_flags,
+ .add_timer = py_add_timer,
+ .schedule_immediate = py_schedule_immediate,
+ .add_signal = py_add_signal,
+ .loop_wait = py_loop_wait,
+ .loop_once = py_loop_once,
+};
+
+static PyObject *py_register_backend(PyObject *self, PyObject *args)
+{
+ PyObject *name, *py_backend;
+
+ if (!PyArg_ParseTuple(args, "O", &py_backend))
+ return NULL;
+
+ name = PyObject_GetAttrString(py_backend, "name");
+ if (name == NULL) {
+ PyErr_SetNone(PyExc_AttributeError);
+ return NULL;
+ }
+
+ if (!PyString_Check(name)) {
+ PyErr_SetNone(PyExc_TypeError);
+ return NULL;
+ }
+
+ if (!tevent_register_backend(PyString_AsString(name), &py_tevent_ops)) { /* FIXME: What to do with backend */
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_context_reinitialise(TeventContext_Object *self)
+{
+ int ret = tevent_re_initialise(self->ev);
+ if (ret != 0) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_queue_stop(TeventQueue_Object *self)
+{
+ tevent_queue_stop(self->queue);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_queue_start(TeventQueue_Object *self)
+{
+ tevent_queue_start(self->queue);
+ Py_RETURN_NONE;
+}
+
+static void py_queue_trigger(struct tevent_req *req, void *private_data)
+{
+ PyObject *callback = private_data, *ret;
+
+ ret = PyObject_CallFunction(callback, "");
+ Py_XDECREF(ret);
+}
+
+static PyObject *py_tevent_queue_add(TeventQueue_Object *self, PyObject *args)
+{
+ TeventContext_Object *py_ev;
+ TeventReq_Object *py_req;
+ PyObject *trigger;
+ bool ret;
+
+ if (!PyArg_ParseTuple(args, "O!O!O",
+ &TeventContext_Type, &py_ev,
+ &TeventReq_Type, &py_req,
+ &trigger))
+ return NULL;
+
+ Py_INCREF(trigger);
+
+ ret = tevent_queue_add(self->queue, py_ev->ev, py_req->req,
+ py_queue_trigger, trigger);
+ if (!ret) {
+ PyErr_SetString(PyExc_RuntimeError, "queue add failed");
+ Py_DECREF(trigger);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_tevent_queue_methods[] = {
+ { "stop", (PyCFunction)py_tevent_queue_stop, METH_NOARGS,
+ "S.stop()" },
+ { "start", (PyCFunction)py_tevent_queue_start, METH_NOARGS,
+ "S.start()" },
+ { "add", (PyCFunction)py_tevent_queue_add, METH_VARARGS,
+ "S.add(ctx, req, trigger, baton)" },
+ { NULL },
+};
+
+static PyObject *py_tevent_context_wakeup_send(PyObject *self, PyObject *args)
+{
+ /* FIXME */
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_context_loop_wait(TeventContext_Object *self)
+{
+ if (tevent_loop_wait(self->ev) != 0) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_context_loop_once(TeventContext_Object *self)
+{
+ if (tevent_loop_once(self->ev) != 0) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+#ifdef TEVENT_DEPRECATED
+static bool py_tevent_finished(PyObject *callback)
+{
+ PyObject *py_ret;
+ bool ret;
+
+ py_ret = PyObject_CallFunction(callback, "");
+ if (py_ret == NULL)
+ return true;
+ ret = PyObject_IsTrue(py_ret);
+ Py_DECREF(py_ret);
+ return ret;
+}
+
+static PyObject *py_tevent_context_loop_until(TeventContext_Object *self, PyObject *args)
+{
+ PyObject *callback;
+ if (!PyArg_ParseTuple(args, "O", &callback))
+ return NULL;
+
+ if (tevent_loop_until(self->ev, py_tevent_finished, callback) != 0) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ if (PyErr_Occurred())
+ return NULL;
+
+ Py_RETURN_NONE;
+}
+#endif
+
+static void py_tevent_signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ PyObject *callback = (PyObject *)private_data, *ret;
+
+ ret = PyObject_CallFunction(callback, "ii", signum, count);
+ Py_XDECREF(ret);
+}
+
+static void py_tevent_signal_dealloc(TeventSignal_Object *self)
+{
+ talloc_free(self->signal);
+ PyObject_Del(self);
+}
+
+static PyTypeObject TeventSignal_Type = {
+ .tp_name = "tevent.Signal",
+ .tp_basicsize = sizeof(TeventSignal_Object),
+ .tp_dealloc = (destructor)py_tevent_signal_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+};
+
+static PyObject *py_tevent_context_add_signal(TeventContext_Object *self, PyObject *args)
+{
+ int signum, sa_flags;
+ PyObject *handler;
+ struct tevent_signal *sig;
+ TeventSignal_Object *ret;
+
+ if (!PyArg_ParseTuple(args, "iiO", &signum, &sa_flags, &handler))
+ return NULL;
+
+ Py_INCREF(handler);
+ sig = tevent_add_signal(self->ev, NULL, signum, sa_flags,
+ py_tevent_signal_handler, handler);
+
+ ret = PyObject_New(TeventSignal_Object, &TeventSignal_Type);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ talloc_free(sig);
+ return NULL;
+ }
+
+ ret->signal = sig;
+
+ return (PyObject *)ret;
+}
+
+static void py_timer_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ PyObject *callback = private_data, *ret;
+ ret = PyObject_CallFunction(callback, "l", te);
+ Py_XDECREF(ret);
+}
+
+static PyObject *py_tevent_context_add_timer(TeventContext_Object *self, PyObject *args)
+{
+ TeventTimer_Object *ret;
+ struct timeval next_event;
+ struct tevent_timer *timer;
+ PyObject *handler;
+ if (!PyArg_ParseTuple(args, "lO", &next_event, &handler))
+ return NULL;
+
+ timer = tevent_add_timer(self->ev, NULL, next_event, py_timer_handler,
+ handler);
+ if (timer == NULL) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ ret = PyObject_New(TeventTimer_Object, &TeventTimer_Type);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ talloc_free(timer);
+ return NULL;
+ }
+ ret->timer = timer;
+
+ return (PyObject *)ret;
+}
+
+static void py_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ PyObject *callback = private_data, *ret;
+
+ ret = PyObject_CallFunction(callback, "i", flags);
+ Py_XDECREF(ret);
+}
+
+static PyObject *py_tevent_context_add_fd(TeventContext_Object *self, PyObject *args)
+{
+ int fd, flags;
+ PyObject *handler;
+ struct tevent_fd *tfd;
+ TeventFd_Object *ret;
+
+ if (!PyArg_ParseTuple(args, "iiO", &fd, &flags, &handler))
+ return NULL;
+
+ tfd = tevent_add_fd(self->ev, NULL, fd, flags, py_fd_handler, handler);
+ if (tfd == NULL) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ ret = PyObject_New(TeventFd_Object, &TeventFd_Type);
+ if (ret == NULL) {
+ talloc_free(tfd);
+ return NULL;
+ }
+ ret->fd = tfd;
+
+ return (PyObject *)ret;
+}
+
+#ifdef TEVENT_DEPRECATED
+static PyObject *py_tevent_context_set_allow_nesting(TeventContext_Object *self)
+{
+ tevent_loop_allow_nesting(self->ev);
+ Py_RETURN_NONE;
+}
+#endif
+
+static PyMethodDef py_tevent_context_methods[] = {
+ { "reinitialise", (PyCFunction)py_tevent_context_reinitialise, METH_NOARGS,
+ "S.reinitialise()" },
+ { "wakeup_send", (PyCFunction)py_tevent_context_wakeup_send,
+ METH_VARARGS, "S.wakeup_send(wakeup_time) -> req" },
+ { "loop_wait", (PyCFunction)py_tevent_context_loop_wait,
+ METH_NOARGS, "S.loop_wait()" },
+ { "loop_once", (PyCFunction)py_tevent_context_loop_once,
+ METH_NOARGS, "S.loop_once()" },
+#ifdef TEVENT_DEPRECATED
+ { "loop_until", (PyCFunction)py_tevent_context_loop_until,
+ METH_VARARGS, "S.loop_until(callback)" },
+#endif
+ { "add_signal", (PyCFunction)py_tevent_context_add_signal,
+ METH_VARARGS, "S.add_signal(signum, sa_flags, handler) -> signal" },
+ { "add_timer", (PyCFunction)py_tevent_context_add_timer,
+ METH_VARARGS, "S.add_timer(next_event, handler) -> timer" },
+ { "add_fd", (PyCFunction)py_tevent_context_add_fd,
+ METH_VARARGS, "S.add_fd(fd, flags, handler) -> fd" },
+#ifdef TEVENT_DEPRECATED
+ { "allow_nesting", (PyCFunction)py_tevent_context_set_allow_nesting,
+ METH_NOARGS, "Whether to allow nested tevent loops." },
+#endif
+ { NULL },
+};
+
+static PyObject *py_tevent_req_wakeup_recv(PyObject *self)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_received(PyObject *self)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_is_error(PyObject *self)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_poll(PyObject *self)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_is_in_progress(PyObject *self)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyGetSetDef py_tevent_req_getsetters[] = {
+ { "in_progress", (getter)py_tevent_req_is_in_progress, NULL,
+ "Whether the request is in progress" },
+ { NULL }
+};
+
+static PyObject *py_tevent_req_post(PyObject *self, PyObject *args)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_set_error(PyObject *self, PyObject *args)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_done(PyObject *self)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_notify_callback(PyObject *self)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_set_endtime(PyObject *self, PyObject *args)
+{
+ /* FIXME */
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_tevent_req_cancel(TeventReq_Object *self)
+{
+ if (!tevent_req_cancel(self->req)) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef py_tevent_req_methods[] = {
+ { "wakeup_recv", (PyCFunction)py_tevent_req_wakeup_recv, METH_NOARGS,
+ "Wakeup received" },
+ { "received", (PyCFunction)py_tevent_req_received, METH_NOARGS,
+ "Receive finished" },
+ { "is_error", (PyCFunction)py_tevent_req_is_error, METH_NOARGS,
+ "is_error() -> (error, state)" },
+ { "poll", (PyCFunction)py_tevent_req_poll, METH_VARARGS,
+ "poll(ctx)" },
+ { "post", (PyCFunction)py_tevent_req_post, METH_VARARGS,
+ "post(ctx) -> req" },
+ { "set_error", (PyCFunction)py_tevent_req_set_error, METH_VARARGS,
+ "set_error(error)" },
+ { "done", (PyCFunction)py_tevent_req_done, METH_NOARGS,
+ "done()" },
+ { "notify_callback", (PyCFunction)py_tevent_req_notify_callback,
+ METH_NOARGS, "notify_callback()" },
+ { "set_endtime", (PyCFunction)py_tevent_req_set_endtime,
+ METH_VARARGS, "set_endtime(ctx, endtime)" },
+ { "cancel", (PyCFunction)py_tevent_req_cancel,
+ METH_NOARGS, "cancel()" },
+ { NULL }
+};
+
+static void py_tevent_req_dealloc(TeventReq_Object *self)
+{
+ talloc_free(self->req);
+ PyObject_DEL(self);
+}
+
+static PyTypeObject TeventReq_Type = {
+ .tp_name = "tevent.Request",
+ .tp_basicsize = sizeof(TeventReq_Object),
+ .tp_methods = py_tevent_req_methods,
+ .tp_dealloc = (destructor)py_tevent_req_dealloc,
+ .tp_getset = py_tevent_req_getsetters,
+ /* FIXME: .tp_new = py_tevent_req_new, */
+};
+
+static PyObject *py_tevent_queue_get_length(TeventQueue_Object *self)
+{
+ return PyInt_FromLong(tevent_queue_length(self->queue));
+}
+
+static PyGetSetDef py_tevent_queue_getsetters[] = {
+ { "length", (getter)py_tevent_queue_get_length,
+ NULL, "The number of elements in the queue." },
+ { NULL },
+};
+
+static void py_tevent_queue_dealloc(TeventQueue_Object *self)
+{
+ talloc_free(self->queue);
+ PyObject_Del(self);
+}
+
+static PyTypeObject TeventQueue_Type = {
+ .tp_name = "tevent.Queue",
+ .tp_basicsize = sizeof(TeventQueue_Object),
+ .tp_dealloc = (destructor)py_tevent_queue_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_getset = py_tevent_queue_getsetters,
+ .tp_methods = py_tevent_queue_methods,
+};
+
+static PyObject *py_tevent_context_signal_support(PyObject *_self)
+{
+ TeventContext_Object *self = (TeventContext_Object *)_self;
+ return PyBool_FromLong(tevent_signal_support(self->ev));
+}
+
+static PyGetSetDef py_tevent_context_getsetters[] = {
+ { "signal_support", (getter)py_tevent_context_signal_support,
+ NULL, "if this platform and tevent context support signal handling" },
+ { NULL }
+};
+
+static void py_tevent_context_dealloc(TeventContext_Object *self)
+{
+ talloc_free(self->ev);
+ PyObject_Del(self);
+}
+
+static PyObject *py_tevent_context_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ const char * const kwnames[] = { "name", NULL };
+ char *name = NULL;
+ struct tevent_context *ev;
+ TeventContext_Object *ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwnames, &name))
+ return NULL;
+
+ if (name == NULL) {
+ ev = tevent_context_init(NULL);
+ } else {
+ ev = tevent_context_init_byname(NULL, name);
+ }
+
+ if (ev == NULL) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ return NULL;
+ }
+
+ ret = PyObject_New(TeventContext_Object, type);
+ if (ret == NULL) {
+ PyErr_NoMemory();
+ talloc_free(ev);
+ return NULL;
+ }
+
+ ret->ev = ev;
+ return (PyObject *)ret;
+}
+
+static PyTypeObject TeventContext_Type = {
+ .tp_name = "tevent.Context",
+ .tp_new = py_tevent_context_new,
+ .tp_basicsize = sizeof(TeventContext_Object),
+ .tp_dealloc = (destructor)py_tevent_context_dealloc,
+ .tp_methods = py_tevent_context_methods,
+ .tp_getset = py_tevent_context_getsetters,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+};
+
+static PyObject *py_set_default_backend(PyObject *self, PyObject *args)
+{
+ char *backend_name;
+ if (!PyArg_ParseTuple(args, "s", &backend_name))
+ return NULL;
+
+ tevent_set_default_backend(backend_name);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_backend_list(PyObject *self)
+{
+ PyObject *ret;
+ int i;
+ const char **backends;
+
+ ret = PyList_New(0);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ backends = tevent_backend_list(NULL);
+ if (backends == NULL) {
+ PyErr_SetNone(PyExc_RuntimeError);
+ Py_DECREF(ret);
+ return NULL;
+ }
+ for (i = 0; backends[i]; i++) {
+ PyList_Append(ret, PyString_FromString(backends[i]));
+ }
+
+ talloc_free(backends);
+
+ return ret;
+}
+
+static PyMethodDef tevent_methods[] = {
+ { "register_backend", (PyCFunction)py_register_backend, METH_VARARGS,
+ "register_backend(backend)" },
+ { "set_default_backend", (PyCFunction)py_set_default_backend,
+ METH_VARARGS, "set_default_backend(backend)" },
+ { "backend_list", (PyCFunction)py_backend_list,
+ METH_NOARGS, "backend_list() -> list" },
+ { NULL },
+};
+
+void init_tevent(void)
+{
+ PyObject *m;
+
+ if (PyType_Ready(&TeventContext_Type) < 0)
+ return;
+
+ if (PyType_Ready(&TeventQueue_Type) < 0)
+ return;
+
+ if (PyType_Ready(&TeventReq_Type) < 0)
+ return;
+
+ if (PyType_Ready(&TeventSignal_Type) < 0)
+ return;
+
+ if (PyType_Ready(&TeventTimer_Type) < 0)
+ return;
+
+ if (PyType_Ready(&TeventFd_Type) < 0)
+ return;
+
+ m = Py_InitModule3("_tevent", tevent_methods, "Tevent integration for twisted.");
+ if (m == NULL)
+ return;
+
+ Py_INCREF(&TeventContext_Type);
+ PyModule_AddObject(m, "Context", (PyObject *)&TeventContext_Type);
+
+ Py_INCREF(&TeventQueue_Type);
+ PyModule_AddObject(m, "Queue", (PyObject *)&TeventQueue_Type);
+
+ Py_INCREF(&TeventReq_Type);
+ PyModule_AddObject(m, "Request", (PyObject *)&TeventReq_Type);
+
+ Py_INCREF(&TeventSignal_Type);
+ PyModule_AddObject(m, "Signal", (PyObject *)&TeventSignal_Type);
+
+ Py_INCREF(&TeventTimer_Type);
+ PyModule_AddObject(m, "Timer", (PyObject *)&TeventTimer_Type);
+
+ Py_INCREF(&TeventFd_Type);
+ PyModule_AddObject(m, "Fd", (PyObject *)&TeventFd_Type);
+
+ PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION));
+}
diff --git a/ctdb/lib/tevent/release-script.sh b/ctdb/lib/tevent/release-script.sh
new file mode 100755
index 00000000000..077f5629677
--- /dev/null
+++ b/ctdb/lib/tevent/release-script.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+if [ "$1" = "" ]; then
+ echo "Please provide version string, eg: 1.2.0"
+ exit 1
+fi
+
+if [ ! -d "lib/tevent" ]; then
+ echo "Run this script from the samba base directory."
+ exit 1
+fi
+
+git clean -f -x -d lib/tevent
+git clean -f -x -d lib/replace
+
+curbranch=`git-branch |grep "^*" | tr -d "* "`
+
+version=$1
+strver=`echo ${version} | tr "." "-"`
+
+# Checkout the release tag
+git branch -f tevent-release-script-${strver} tevent-${strver}
+if [ ! "$?" = "0" ]; then
+ echo "Unable to checkout tevent-${strver} release"
+ exit 1
+fi
+
+git checkout tevent-release-script-${strver}
+
+# Test configure agrees with us
+confver=`grep "^AC_INIT" lib/tevent/configure.ac | tr -d "AC_INIT(tevent, " | tr -d ")"`
+if [ ! "$confver" = "$version" ]; then
+ echo "Wrong version, requested release for ${version}, found ${confver}"
+ exit 1
+fi
+
+# Now build tarball
+cp -a lib/tevent tevent-${version}
+cp -a lib/replace tevent-${version}/libreplace
+pushd tevent-${version}
+./autogen.sh
+popd
+tar cvzf tevent-${version}.tar.gz tevent-${version}
+rm -fr tevent-${version}
+
+#Clean up
+git checkout $curbranch
+git branch -d tevent-release-script-${strver}
diff --git a/ctdb/lib/tevent/testsuite.c b/ctdb/lib/tevent/testsuite.c
index 6f2851e744d..8e3f4af51cc 100644
--- a/ctdb/lib/tevent/testsuite.c
+++ b/ctdb/lib/tevent/testsuite.c
@@ -1,9 +1,10 @@
-/*
+/*
Unix SMB/CIFS implementation.
testing of the events subsystem
Copyright (C) Stefan Metzmacher 2006-2009
+ Copyright (C) Jeremy Allison 2013
** NOTE! The following LGPL license applies to the tevent
** library. This does NOT imply that all of Samba is released
@@ -24,13 +25,19 @@
*/
#include "includes.h"
-#include "lib/events/events.h"
+#include "lib/tevent/tevent.h"
#include "system/filesys.h"
+#include "system/select.h"
+#include "system/network.h"
#include "torture/torture.h"
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#include <assert.h>
+#endif
static int fde_count;
-static void fde_handler(struct tevent_context *ev_ctx, struct tevent_fd *f,
+static void fde_handler_read(struct tevent_context *ev_ctx, struct tevent_fd *f,
uint16_t flags, void *private_data)
{
int *fd = (int *)private_data;
@@ -39,11 +46,38 @@ static void fde_handler(struct tevent_context *ev_ctx, struct tevent_fd *f,
kill(getpid(), SIGUSR1);
#endif
kill(getpid(), SIGALRM);
+
read(fd[0], &c, 1);
- write(fd[1], &c, 1);
fde_count++;
}
+static void fde_handler_write(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+ int *fd = (int *)private_data;
+ char c = 0;
+ write(fd[1], &c, 1);
+}
+
+
+/* These should never fire... */
+static void fde_handler_read_1(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+ struct torture_context *test = (struct torture_context *)private_data;
+ torture_comment(test, "fde_handler_read_1 should never fire !\n");
+ abort();
+}
+
+/* These should never fire... */
+static void fde_handler_write_1(struct tevent_context *ev_ctx, struct tevent_fd *f,
+ uint16_t flags, void *private_data)
+{
+ struct torture_context *test = (struct torture_context *)private_data;
+ torture_comment(test, "fde_handler_write_1 should never fire !\n");
+ abort();
+}
+
static void finished_handler(struct tevent_context *ev_ctx, struct tevent_timer *te,
struct timeval tval, void *private_data)
{
@@ -65,17 +99,21 @@ static bool test_event_context(struct torture_context *test,
int fd[2] = { -1, -1 };
const char *backend = (const char *)test_data;
int alarm_count=0, info_count=0;
- struct tevent_fd *fde;
+ struct tevent_fd *fde_read;
+ struct tevent_fd *fde_read_1;
+ struct tevent_fd *fde_write;
+ struct tevent_fd *fde_write_1;
#ifdef SA_RESTART
struct tevent_signal *se1 = NULL;
#endif
+#ifdef SA_RESETHAND
struct tevent_signal *se2 = NULL;
+#endif
#ifdef SA_SIGINFO
struct tevent_signal *se3 = NULL;
#endif
int finished=0;
struct timeval t;
- char c = 0;
ev_ctx = tevent_context_init_byname(test, backend);
if (ev_ctx == NULL) {
@@ -83,7 +121,8 @@ static bool test_event_context(struct torture_context *test,
return true;
}
- torture_comment(test, "Testing event backend '%s'\n", backend);
+ torture_comment(test, "backend '%s' - %s\n",
+ backend, __FUNCTION__);
/* reset globals */
fde_count = 0;
@@ -91,25 +130,35 @@ static bool test_event_context(struct torture_context *test,
/* create a pipe */
pipe(fd);
- fde = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_READ,
- fde_handler, fd);
- tevent_fd_set_auto_close(fde);
+ fde_read = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_READ,
+ fde_handler_read, fd);
+ fde_write_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_WRITE,
+ fde_handler_write_1, test);
+
+ fde_write = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_WRITE,
+ fde_handler_write, fd);
+ fde_read_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_READ,
+ fde_handler_read_1, test);
+
+ tevent_fd_set_auto_close(fde_read);
+ tevent_fd_set_auto_close(fde_write);
tevent_add_timer(ev_ctx, ev_ctx, timeval_current_ofs(2,0),
finished_handler, &finished);
#ifdef SA_RESTART
se1 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count);
+ torture_assert(test, se1 != NULL, "failed to setup se1");
#endif
#ifdef SA_RESETHAND
se2 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESETHAND, count_handler, &alarm_count);
+ torture_assert(test, se2 != NULL, "failed to setup se2");
#endif
#ifdef SA_SIGINFO
se3 = tevent_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count);
+ torture_assert(test, se3 != NULL, "failed to setup se3");
#endif
- write(fd[1], &c, 1);
-
t = timeval_current();
while (!finished) {
errno = 0;
@@ -119,8 +168,10 @@ static bool test_event_context(struct torture_context *test,
}
}
- talloc_free(fde);
- close(fd[1]);
+ talloc_free(fde_read);
+ talloc_free(fde_write);
+ talloc_free(fde_read_1);
+ talloc_free(fde_write_1);
while (alarm_count < fde_count+1) {
if (tevent_loop_once(ev_ctx) == -1) {
@@ -136,6 +187,14 @@ static bool test_event_context(struct torture_context *test,
torture_assert_int_equal(test, alarm_count, 1+fde_count, "alarm count mismatch");
+#ifdef SA_RESETHAND
+ /*
+ * we do not call talloc_free(se2)
+ * because it is already gone,
+ * after triggering the event handler.
+ */
+#endif
+
#ifdef SA_SIGINFO
talloc_free(se3);
torture_assert_int_equal(test, info_count, fde_count, "info count mismatch");
@@ -146,6 +205,597 @@ static bool test_event_context(struct torture_context *test,
return true;
}
+struct test_event_fd1_state {
+ struct torture_context *tctx;
+ const char *backend;
+ struct tevent_context *ev;
+ int sock[2];
+ struct tevent_timer *te;
+ struct tevent_fd *fde0;
+ struct tevent_fd *fde1;
+ bool got_write;
+ bool got_read;
+ bool drain;
+ bool drain_done;
+ unsigned loop_count;
+ bool finished;
+ const char *error;
+};
+
+static void test_event_fd1_fde_handler(struct tevent_context *ev_ctx,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct test_event_fd1_state *state =
+ (struct test_event_fd1_state *)private_data;
+
+ if (state->drain_done) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (state->drain) {
+ ssize_t ret;
+ uint8_t c = 0;
+
+ if (!(flags & TEVENT_FD_READ)) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ ret = read(state->sock[0], &c, 1);
+ if (ret == 1) {
+ return;
+ }
+
+ /*
+ * end of test...
+ */
+ tevent_fd_set_flags(fde, 0);
+ state->drain_done = true;
+ return;
+ }
+
+ if (!state->got_write) {
+ uint8_t c = 0;
+
+ if (flags != TEVENT_FD_WRITE) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ state->got_write = true;
+
+ /*
+ * we write to the other socket...
+ */
+ write(state->sock[1], &c, 1);
+ TEVENT_FD_NOT_WRITEABLE(fde);
+ TEVENT_FD_READABLE(fde);
+ return;
+ }
+
+ if (!state->got_read) {
+ if (flags != TEVENT_FD_READ) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ state->got_read = true;
+
+ TEVENT_FD_NOT_READABLE(fde);
+ return;
+ }
+
+ state->finished = true;
+ state->error = __location__;
+ return;
+}
+
+static void test_event_fd1_finished(struct tevent_context *ev_ctx,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_event_fd1_state *state =
+ (struct test_event_fd1_state *)private_data;
+
+ if (state->drain_done) {
+ state->finished = true;
+ return;
+ }
+
+ if (!state->got_write) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (!state->got_read) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ state->loop_count++;
+ if (state->loop_count > 3) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ state->got_write = false;
+ state->got_read = false;
+
+ tevent_fd_set_flags(state->fde0, TEVENT_FD_WRITE);
+
+ if (state->loop_count > 2) {
+ state->drain = true;
+ TALLOC_FREE(state->fde1);
+ TEVENT_FD_READABLE(state->fde0);
+ }
+
+ state->te = tevent_add_timer(state->ev, state->ev,
+ timeval_current_ofs(0,2000),
+ test_event_fd1_finished, state);
+}
+
+static bool test_event_fd1(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_event_fd1_state state;
+
+ ZERO_STRUCT(state);
+ state.tctx = tctx;
+ state.backend = (const char *)test_data;
+
+ state.ev = tevent_context_init_byname(tctx, state.backend);
+ if (state.ev == NULL) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "event backend '%s' not supported\n",
+ state.backend));
+ return true;
+ }
+
+ tevent_set_debug_stderr(state.ev);
+ torture_comment(tctx, "backend '%s' - %s\n",
+ state.backend, __FUNCTION__);
+
+ /*
+ * This tests the following:
+ *
+ * It monitors the state of state.sock[0]
+ * with tevent_fd, but we never read/write on state.sock[0]
+ * while state.sock[1] * is only used to write a few bytes.
+ *
+ * We have a loop:
+ * - we wait only for TEVENT_FD_WRITE on state.sock[0]
+ * - we write 1 byte to state.sock[1]
+ * - we wait only for TEVENT_FD_READ on state.sock[0]
+ * - we disable events on state.sock[0]
+ * - the timer event restarts the loop
+ * Then we close state.sock[1]
+ * We have a loop:
+ * - we wait for TEVENT_FD_READ/WRITE on state.sock[0]
+ * - we try to read 1 byte
+ * - if the read gets an error of returns 0
+ * we disable the event handler
+ * - the timer finishes the test
+ */
+ state.sock[0] = -1;
+ state.sock[1] = -1;
+ socketpair(AF_UNIX, SOCK_STREAM, 0, state.sock);
+
+ state.te = tevent_add_timer(state.ev, state.ev,
+ timeval_current_ofs(0,1000),
+ test_event_fd1_finished, &state);
+ state.fde0 = tevent_add_fd(state.ev, state.ev,
+ state.sock[0], TEVENT_FD_WRITE,
+ test_event_fd1_fde_handler, &state);
+ /* state.fde1 is only used to auto close */
+ state.fde1 = tevent_add_fd(state.ev, state.ev,
+ state.sock[1], 0,
+ test_event_fd1_fde_handler, &state);
+
+ tevent_fd_set_auto_close(state.fde0);
+ tevent_fd_set_auto_close(state.fde1);
+
+ while (!state.finished) {
+ errno = 0;
+ if (tevent_loop_once(state.ev) == -1) {
+ talloc_free(state.ev);
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "Failed event loop %s\n",
+ strerror(errno)));
+ }
+ }
+
+ talloc_free(state.ev);
+
+ torture_assert(tctx, state.error == NULL, talloc_asprintf(tctx,
+ "%s", state.error));
+
+ return true;
+}
+
+struct test_event_fd2_state {
+ struct torture_context *tctx;
+ const char *backend;
+ struct tevent_context *ev;
+ struct tevent_timer *te;
+ struct test_event_fd2_sock {
+ struct test_event_fd2_state *state;
+ int fd;
+ struct tevent_fd *fde;
+ size_t num_written;
+ size_t num_read;
+ bool got_full;
+ } sock0, sock1;
+ bool finished;
+ const char *error;
+};
+
+static void test_event_fd2_sock_handler(struct tevent_context *ev_ctx,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct test_event_fd2_sock *cur_sock =
+ (struct test_event_fd2_sock *)private_data;
+ struct test_event_fd2_state *state = cur_sock->state;
+ struct test_event_fd2_sock *oth_sock = NULL;
+ uint8_t v = 0, c;
+ ssize_t ret;
+
+ if (cur_sock == &state->sock0) {
+ oth_sock = &state->sock1;
+ } else {
+ oth_sock = &state->sock0;
+ }
+
+ if (oth_sock->num_written == 1) {
+ if (flags != (TEVENT_FD_READ | TEVENT_FD_WRITE)) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ }
+
+ if (cur_sock->num_read == oth_sock->num_written) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (!(flags & TEVENT_FD_READ)) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+
+ if (oth_sock->num_read > 0) {
+ /*
+ * There should be room to write a byte again
+ */
+ if (!(flags & TEVENT_FD_WRITE)) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ }
+
+ if ((flags & TEVENT_FD_WRITE) && !cur_sock->got_full) {
+ v = (uint8_t)cur_sock->num_written;
+ ret = write(cur_sock->fd, &v, 1);
+ if (ret != 1) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ cur_sock->num_written++;
+ if (cur_sock->num_written > 0x80000000) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ return;
+ }
+
+ if (!cur_sock->got_full) {
+ cur_sock->got_full = true;
+
+ if (!oth_sock->got_full) {
+ /*
+ * cur_sock is full,
+ * lets wait for oth_sock
+ * to be filled
+ */
+ tevent_fd_set_flags(cur_sock->fde, 0);
+ return;
+ }
+
+ /*
+ * oth_sock waited for cur_sock,
+ * lets restart it
+ */
+ tevent_fd_set_flags(oth_sock->fde,
+ TEVENT_FD_READ|TEVENT_FD_WRITE);
+ }
+
+ ret = read(cur_sock->fd, &v, 1);
+ if (ret != 1) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ c = (uint8_t)cur_sock->num_read;
+ if (c != v) {
+ state->finished = true;
+ state->error = __location__;
+ return;
+ }
+ cur_sock->num_read++;
+
+ if (cur_sock->num_read < oth_sock->num_written) {
+ /* there is more to read */
+ return;
+ }
+ /*
+ * we read everything, we need to remove TEVENT_FD_WRITE
+ * to avoid spinning
+ */
+ TEVENT_FD_NOT_WRITEABLE(cur_sock->fde);
+
+ if (oth_sock->num_read == cur_sock->num_written) {
+ /*
+ * both directions are finished
+ */
+ state->finished = true;
+ }
+
+ return;
+}
+
+static void test_event_fd2_finished(struct tevent_context *ev_ctx,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_event_fd2_state *state =
+ (struct test_event_fd2_state *)private_data;
+
+ /*
+ * this should never be triggered
+ */
+ state->finished = true;
+ state->error = __location__;
+}
+
+static bool test_event_fd2(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_event_fd2_state state;
+ int sock[2];
+ uint8_t c = 0;
+
+ ZERO_STRUCT(state);
+ state.tctx = tctx;
+ state.backend = (const char *)test_data;
+
+ state.ev = tevent_context_init_byname(tctx, state.backend);
+ if (state.ev == NULL) {
+ torture_skip(tctx, talloc_asprintf(tctx,
+ "event backend '%s' not supported\n",
+ state.backend));
+ return true;
+ }
+
+ tevent_set_debug_stderr(state.ev);
+ torture_comment(tctx, "backend '%s' - %s\n",
+ state.backend, __FUNCTION__);
+
+ /*
+ * This tests the following
+ *
+ * - We write 1 byte to each socket
+ * - We wait for TEVENT_FD_READ/WRITE on both sockets
+ * - When we get TEVENT_FD_WRITE we write 1 byte
+ * until both socket buffers are full, which
+ * means both sockets only get TEVENT_FD_READ.
+ * - Then we read 1 byte until we have consumed
+ * all bytes the other end has written.
+ */
+ sock[0] = -1;
+ sock[1] = -1;
+ socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+
+ /*
+ * the timer should never expire
+ */
+ state.te = tevent_add_timer(state.ev, state.ev,
+ timeval_current_ofs(600, 0),
+ test_event_fd2_finished, &state);
+ state.sock0.state = &state;
+ state.sock0.fd = sock[0];
+ state.sock0.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock0.fd,
+ TEVENT_FD_READ | TEVENT_FD_WRITE,
+ test_event_fd2_sock_handler,
+ &state.sock0);
+ state.sock1.state = &state;
+ state.sock1.fd = sock[1];
+ state.sock1.fde = tevent_add_fd(state.ev, state.ev,
+ state.sock1.fd,
+ TEVENT_FD_READ | TEVENT_FD_WRITE,
+ test_event_fd2_sock_handler,
+ &state.sock1);
+
+ tevent_fd_set_auto_close(state.sock0.fde);
+ tevent_fd_set_auto_close(state.sock1.fde);
+
+ write(state.sock0.fd, &c, 1);
+ state.sock0.num_written++;
+ write(state.sock1.fd, &c, 1);
+ state.sock1.num_written++;
+
+ while (!state.finished) {
+ errno = 0;
+ if (tevent_loop_once(state.ev) == -1) {
+ talloc_free(state.ev);
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "Failed event loop %s\n",
+ strerror(errno)));
+ }
+ }
+
+ talloc_free(state.ev);
+
+ torture_assert(tctx, state.error == NULL, talloc_asprintf(tctx,
+ "%s", state.error));
+
+ return true;
+}
+
+#ifdef HAVE_PTHREAD
+
+static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
+static bool do_shutdown = false;
+
+static void test_event_threaded_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&threaded_mutex);
+ assert(ret == 0);
+}
+
+static void test_event_threaded_unlock(void)
+{
+ int ret;
+ ret = pthread_mutex_unlock(&threaded_mutex);
+ assert(ret == 0);
+}
+
+static void test_event_threaded_trace(enum tevent_trace_point point,
+ void *private_data)
+{
+ switch (point) {
+ case TEVENT_TRACE_BEFORE_WAIT:
+ test_event_threaded_unlock();
+ break;
+ case TEVENT_TRACE_AFTER_WAIT:
+ test_event_threaded_lock();
+ break;
+ case TEVENT_TRACE_BEFORE_LOOP_ONCE:
+ case TEVENT_TRACE_AFTER_LOOP_ONCE:
+ break;
+ }
+}
+
+static void test_event_threaded_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ return;
+}
+
+static void *test_event_poll_thread(void *private_data)
+{
+ struct tevent_context *ev = (struct tevent_context *)private_data;
+
+ test_event_threaded_lock();
+
+ while (true) {
+ int ret;
+ ret = tevent_loop_once(ev);
+ assert(ret == 0);
+ if (do_shutdown) {
+ test_event_threaded_unlock();
+ return NULL;
+ }
+ }
+
+}
+
+static void test_event_threaded_read_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ int *pfd = (int *)private_data;
+ char c;
+ ssize_t nread;
+
+ if ((flags & TEVENT_FD_READ) == 0) {
+ return;
+ }
+
+ do {
+ nread = read(*pfd, &c, 1);
+ } while ((nread == -1) && (errno == EINTR));
+
+ assert(nread == 1);
+}
+
+static bool test_event_context_threaded(struct torture_context *test,
+ const void *test_data)
+{
+ struct tevent_context *ev;
+ struct tevent_timer *te;
+ struct tevent_fd *fde;
+ pthread_t poll_thread;
+ int fds[2];
+ int ret;
+ char c = 0;
+
+ ev = tevent_context_init_byname(test, "poll_mt");
+ torture_assert(test, ev != NULL, "poll_mt not supported");
+
+ tevent_set_trace_callback(ev, test_event_threaded_trace, NULL);
+
+ te = tevent_add_timer(ev, ev, timeval_current_ofs(5, 0),
+ test_event_threaded_timer, NULL);
+ torture_assert(test, te != NULL, "Could not add timer");
+
+ ret = pthread_create(&poll_thread, NULL, test_event_poll_thread, ev);
+ torture_assert(test, ret == 0, "Could not create poll thread");
+
+ ret = pipe(fds);
+ torture_assert(test, ret == 0, "Could not create pipe");
+
+ poll(NULL, 0, 100);
+
+ test_event_threaded_lock();
+
+ fde = tevent_add_fd(ev, ev, fds[0], TEVENT_FD_READ,
+ test_event_threaded_read_handler, &fds[0]);
+ torture_assert(test, fde != NULL, "Could not add fd event");
+
+ test_event_threaded_unlock();
+
+ poll(NULL, 0, 100);
+
+ write(fds[1], &c, 1);
+
+ poll(NULL, 0, 100);
+
+ test_event_threaded_lock();
+ do_shutdown = true;
+ test_event_threaded_unlock();
+
+ write(fds[1], &c, 1);
+
+ ret = pthread_join(poll_thread, NULL);
+ torture_assert(test, ret == 0, "pthread_join failed");
+
+ return true;
+}
+
+#endif
+
struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
{
struct torture_suite *suite = torture_suite_create(mem_ctx, "event");
@@ -153,10 +803,31 @@ struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
int i;
for (i=0;list && list[i];i++) {
- torture_suite_add_simple_tcase_const(suite, list[i],
+ struct torture_suite *backend_suite;
+
+ backend_suite = torture_suite_create(mem_ctx, list[i]);
+
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "context",
test_event_context,
(const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "fd1",
+ test_event_fd1,
+ (const void *)list[i]);
+ torture_suite_add_simple_tcase_const(backend_suite,
+ "fd2",
+ test_event_fd2,
+ (const void *)list[i]);
+
+ torture_suite_add_suite(suite, backend_suite);
}
+#ifdef HAVE_PTHREAD
+ torture_suite_add_simple_tcase_const(suite, "threaded_poll_mt",
+ test_event_context_threaded,
+ NULL);
+#endif
+
return suite;
}
diff --git a/ctdb/lib/tevent/tevent.c b/ctdb/lib/tevent/tevent.c
index 6c6c6e7f8cc..be0afd453bb 100644
--- a/ctdb/lib/tevent/tevent.c
+++ b/ctdb/lib/tevent/tevent.c
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/CIFS implementation.
main select loop and event handling
Copyright (C) Andrew Tridgell 2003
@@ -112,12 +112,43 @@ void tevent_set_default_backend(const char *backend)
*/
static void tevent_backend_init(void)
{
+ static bool done;
+
+ if (done) {
+ return;
+ }
+
+ done = true;
+
tevent_select_init();
tevent_poll_init();
- tevent_standard_init();
+ tevent_poll_mt_init();
#ifdef HAVE_EPOLL
tevent_epoll_init();
#endif
+ tevent_standard_init();
+}
+
+_PRIVATE_ const struct tevent_ops *tevent_find_ops_byname(const char *name)
+{
+ struct tevent_ops_list *e;
+
+ tevent_backend_init();
+
+ if (name == NULL) {
+ name = tevent_default_backend;
+ }
+ if (name == NULL) {
+ name = "standard";
+ }
+
+ for (e = tevent_backends; e != NULL; e = e->next) {
+ if (0 == strcmp(e->name, name)) {
+ return e->ops;
+ }
+ }
+
+ return NULL;
}
/*
@@ -159,6 +190,7 @@ int tevent_common_context_destructor(struct tevent_context *ev)
DLIST_REMOVE(ev->fd_events, fd);
}
+ ev->last_zero_timer = NULL;
for (te = ev->timer_events; te; te = tn) {
tn = te->next;
te->event_ctx = NULL;
@@ -242,23 +274,14 @@ struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
const char *name)
{
- struct tevent_ops_list *e;
-
- tevent_backend_init();
+ const struct tevent_ops *ops;
- if (name == NULL) {
- name = tevent_default_backend;
- }
- if (name == NULL) {
- name = "standard";
+ ops = tevent_find_ops_byname(name);
+ if (ops == NULL) {
+ return NULL;
}
- for (e=tevent_backends;e;e=e->next) {
- if (strcmp(name, e->name) == 0) {
- return tevent_context_init_ops(mem_ctx, e->ops, NULL);
- }
- }
- return NULL;
+ return tevent_context_init_ops(mem_ctx, ops, NULL);
}
@@ -445,7 +468,7 @@ void tevent_loop_set_nesting_hook(struct tevent_context *ev,
tevent_nesting_hook hook,
void *private_data)
{
- if (ev->nesting.hook_fn &&
+ if (ev->nesting.hook_fn &&
(ev->nesting.hook_fn != hook ||
ev->nesting.hook_private != private_data)) {
/* the way the nesting hook code is currently written
@@ -471,7 +494,7 @@ static void tevent_abort_nesting(struct tevent_context *ev, const char *location
}
/*
- do a single event loop using the events defined in ev
+ do a single event loop using the events defined in ev
*/
int _tevent_loop_once(struct tevent_context *ev, const char *location)
{
@@ -503,7 +526,9 @@ int _tevent_loop_once(struct tevent_context *ev, const char *location)
}
}
+ tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
ret = ev->ops->loop_once(ev, location);
+ tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
if (ev->nesting.level > 0) {
if (ev->nesting.hook_fn) {
@@ -563,7 +588,9 @@ int _tevent_loop_until(struct tevent_context *ev,
}
while (!finished(private_data)) {
+ tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
ret = ev->ops->loop_once(ev, location);
+ tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
if (ret != 0) {
break;
}
@@ -630,7 +657,7 @@ int _tevent_loop_wait(struct tevent_context *ev, const char *location)
/*
re-initialise a tevent context. This leaves you with the same
event context, but all events are wiped and the structure is
- re-initialised. This is most useful after a fork()
+ re-initialised. This is most useful after a fork()
zero is returned on success, non-zero on failure
*/
diff --git a/ctdb/lib/tevent/tevent.h b/ctdb/lib/tevent/tevent.h
index 60bc92ad272..6b4d371e4c5 100644
--- a/ctdb/lib/tevent/tevent.h
+++ b/ctdb/lib/tevent/tevent.h
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/CIFS implementation.
generalised event loop handling
@@ -524,6 +524,17 @@ enum tevent_trace_point {
* Corresponds to a trace point just after waiting
*/
TEVENT_TRACE_AFTER_WAIT,
+#define TEVENT_HAS_LOOP_ONCE_TRACE_POINTS 1
+ /**
+ * Corresponds to a trace point just before calling
+ * the loop_once() backend function.
+ */
+ TEVENT_TRACE_BEFORE_LOOP_ONCE,
+ /**
+ * Corresponds to a trace point right after the
+ * loop_once() backend function has returned.
+ */
+ TEVENT_TRACE_AFTER_LOOP_ONCE,
};
typedef void (*tevent_trace_callback_t)(enum tevent_trace_point,
diff --git a/ctdb/lib/tevent/tevent.pc.in b/ctdb/lib/tevent/tevent.pc.in
index 9adcffb0030..1091ff00f1e 100644
--- a/ctdb/lib/tevent/tevent.pc.in
+++ b/ctdb/lib/tevent/tevent.pc.in
@@ -8,5 +8,5 @@ Description: An event system library
Version: @PACKAGE_VERSION@
Requires: talloc
Libs: -L${libdir} -ltevent
-Cflags: -I${includedir}
+Cflags: @LIB_RPATH@ -I${includedir}
URL: http://samba.org/
diff --git a/ctdb/lib/tevent/tevent.py b/ctdb/lib/tevent/tevent.py
new file mode 100644
index 00000000000..c296544eb41
--- /dev/null
+++ b/ctdb/lib/tevent/tevent.py
@@ -0,0 +1,29 @@
+#!/usr/bin/python
+#
+# Python integration for tevent
+#
+# Copyright (C) Jelmer Vernooij 2011
+#
+# ** NOTE! The following LGPL license applies to the tevent
+# ** library. This does NOT imply that all of Samba is released
+# ** under the LGPL
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+from _tevent import (
+ __version__,
+ backend_list,
+ Context,
+ Signal,
+ )
diff --git a/ctdb/lib/tevent/tevent_epoll.c b/ctdb/lib/tevent/tevent_epoll.c
index a7fb8b1baaf..599c190658c 100644
--- a/ctdb/lib/tevent/tevent_epoll.c
+++ b/ctdb/lib/tevent/tevent_epoll.c
@@ -1,10 +1,11 @@
-/*
+/*
Unix SMB/CIFS implementation.
main select loop and event handling - epoll implementation
Copyright (C) Andrew Tridgell 2003-2005
- Copyright (C) Stefan Metzmacher 2005-2009
+ Copyright (C) Stefan Metzmacher 2005-2013
+ Copyright (C) Jeremy Allison 2013
** NOTE! The following LGPL license applies to the tevent
** library. This does NOT imply that all of Samba is released
@@ -39,16 +40,140 @@ struct epoll_event_context {
int epoll_fd;
pid_t pid;
+
+ bool panic_force_replay;
+ bool *panic_state;
+ bool (*panic_fallback)(struct tevent_context *ev, bool replay);
};
+#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
+#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1)
+#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
+#define EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX (1<<3)
+
+#ifdef TEST_PANIC_FALLBACK
+
+static int epoll_create_panic_fallback(struct epoll_event_context *epoll_ev,
+ int size)
+{
+ if (epoll_ev->panic_fallback == NULL) {
+ return epoll_create(size);
+ }
+
+ /* 50% of the time, fail... */
+ if ((random() % 2) == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return epoll_create(size);
+}
+
+static int epoll_ctl_panic_fallback(struct epoll_event_context *epoll_ev,
+ int epfd, int op, int fd,
+ struct epoll_event *event)
+{
+ if (epoll_ev->panic_fallback == NULL) {
+ return epoll_ctl(epfd, op, fd, event);
+ }
+
+ /* 50% of the time, fail... */
+ if ((random() % 2) == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return epoll_ctl(epfd, op, fd, event);
+}
+
+static int epoll_wait_panic_fallback(struct epoll_event_context *epoll_ev,
+ int epfd,
+ struct epoll_event *events,
+ int maxevents,
+ int timeout)
+{
+ if (epoll_ev->panic_fallback == NULL) {
+ return epoll_wait(epfd, events, maxevents, timeout);
+ }
+
+ /* 50% of the time, fail... */
+ if ((random() % 2) == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return epoll_wait(epfd, events, maxevents, timeout);
+}
+
+#define epoll_create(_size) \
+ epoll_create_panic_fallback(epoll_ev, _size)
+#define epoll_ctl(_epfd, _op, _fd, _event) \
+ epoll_ctl_panic_fallback(epoll_ev,_epfd, _op, _fd, _event)
+#define epoll_wait(_epfd, _events, _maxevents, _timeout) \
+ epoll_wait_panic_fallback(epoll_ev, _epfd, _events, _maxevents, _timeout)
+#endif
+
+/*
+ called to set the panic fallback function.
+*/
+_PRIVATE_ bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
+ bool (*panic_fallback)(struct tevent_context *ev,
+ bool replay))
+{
+ struct epoll_event_context *epoll_ev;
+
+ if (ev->additional_data == NULL) {
+ return false;
+ }
+
+ epoll_ev = talloc_get_type(ev->additional_data,
+ struct epoll_event_context);
+ if (epoll_ev == NULL) {
+ return false;
+ }
+ epoll_ev->panic_fallback = panic_fallback;
+ return true;
+}
+
/*
called when a epoll call fails
*/
-static void epoll_panic(struct epoll_event_context *epoll_ev, const char *reason)
+static void epoll_panic(struct epoll_event_context *epoll_ev,
+ const char *reason, bool replay)
{
- tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
- "%s (%s) - calling abort()\n", reason, strerror(errno));
- abort();
+ struct tevent_context *ev = epoll_ev->ev;
+ bool (*panic_fallback)(struct tevent_context *ev, bool replay);
+
+ panic_fallback = epoll_ev->panic_fallback;
+
+ if (epoll_ev->panic_state != NULL) {
+ *epoll_ev->panic_state = true;
+ }
+
+ if (epoll_ev->panic_force_replay) {
+ replay = true;
+ }
+
+ TALLOC_FREE(ev->additional_data);
+
+ if (panic_fallback == NULL) {
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "%s (%s) replay[%u] - calling abort()\n",
+ reason, strerror(errno), (unsigned)replay);
+ abort();
+ }
+
+ tevent_debug(ev, TEVENT_DEBUG_ERROR,
+ "%s (%s) replay[%u] - calling panic_fallback\n",
+ reason, strerror(errno), (unsigned)replay);
+
+ if (!panic_fallback(ev, replay)) {
+ /* Fallback failed. */
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "%s (%s) replay[%u] - calling abort()\n",
+ reason, strerror(errno), (unsigned)replay);
+ abort();
+ }
}
/*
@@ -95,16 +220,18 @@ static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
return 0;
}
-static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
+static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
/*
reopen the epoll handle when our pid changes
- see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
+ see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
demonstration of why this is needed
*/
static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
{
struct tevent_fd *fde;
+ bool *caller_panic_state = epoll_ev->panic_state;
+ bool panic_triggered = false;
if (epoll_ev->pid == getpid()) {
return;
@@ -113,8 +240,7 @@ static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
close(epoll_ev->epoll_fd);
epoll_ev->epoll_fd = epoll_create(64);
if (epoll_ev->epoll_fd == -1) {
- tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
- "Failed to recreate epoll handle after fork\n");
+ epoll_panic(epoll_ev, "epoll_create() failed", false);
return;
}
@@ -124,14 +250,113 @@ static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
}
epoll_ev->pid = getpid();
+ epoll_ev->panic_state = &panic_triggered;
for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
- epoll_add_event(epoll_ev, fde);
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ epoll_update_event(epoll_ev, fde);
+
+ if (panic_triggered) {
+ if (caller_panic_state != NULL) {
+ *caller_panic_state = true;
+ }
+ return;
+ }
}
+ epoll_ev->panic_state = NULL;
}
-#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
-#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1)
-#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
+/*
+ epoll cannot add the same file descriptor twice, once
+ with read, once with write which is allowed by the
+ tevent backend. Multiplex the existing fde, flag it
+ as such so we can search for the correct fde on
+ event triggering.
+*/
+
+static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
+ struct tevent_fd *add_fde)
+{
+ struct epoll_event event;
+ struct tevent_fd *mpx_fde;
+ int ret;
+
+ /* Find the existing fde that caused the EEXIST error. */
+ for (mpx_fde = epoll_ev->ev->fd_events; mpx_fde; mpx_fde = mpx_fde->next) {
+ if (mpx_fde->fd != add_fde->fd) {
+ continue;
+ }
+
+ if (mpx_fde == add_fde) {
+ continue;
+ }
+
+ break;
+ }
+ if (mpx_fde == NULL) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "can't find multiplex fde for fd[%d]",
+ add_fde->fd);
+ return -1;
+ }
+
+ if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
+ /* Logic error. Can't have more than 2 multiplexed fde's. */
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "multiplex fde for fd[%d] is already multiplexed\n",
+ mpx_fde->fd);
+ return -1;
+ }
+
+ /*
+ * The multiplex fde must have the same fd, and also
+ * already have an epoll event attached.
+ */
+ if (!(mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) {
+ /* Logic error. Can't have more than 2 multiplexed fde's. */
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
+ "multiplex fde for fd[%d] has no event\n",
+ mpx_fde->fd);
+ return -1;
+ }
+
+ /* Modify the mpx_fde to add in the new flags. */
+ ZERO_STRUCT(event);
+ event.events = epoll_map_flags(mpx_fde->flags);
+ event.events |= epoll_map_flags(add_fde->flags);
+ event.data.ptr = mpx_fde;
+ ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, mpx_fde->fd, &event);
+ if (ret != 0 && errno == EBADF) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
+ "EPOLL_CTL_MOD EBADF for "
+ "add_fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
+ add_fde, mpx_fde, add_fde->fd);
+ DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->event_ctx = NULL;
+ DLIST_REMOVE(epoll_ev->ev->fd_events, add_fde);
+ add_fde->event_ctx = NULL;
+ return 0;
+ } else if (ret != 0) {
+ return ret;
+ }
+
+ /*
+ * Make each fde->additional_data pointers point at each other
+ * so we can look them up from each other. They are now paired.
+ */
+ mpx_fde->additional_data = (struct tevent_fd *)add_fde;
+ add_fde->additional_data = (struct tevent_fd *)mpx_fde;
+
+ /* Now flag both fde's as being multiplexed. */
+ mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
+ add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
+
+ /* we need to keep the GOT_ERROR flag */
+ if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR) {
+ add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+ }
+
+ return 0;
+}
/*
add the epoll event to the given fd_event
@@ -139,26 +364,70 @@ static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
{
struct epoll_event event;
+ int ret;
+ struct tevent_fd *mpx_fde = NULL;
- if (epoll_ev->epoll_fd == -1) return;
-
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
- /* if we don't want events yet, don't add an epoll_event */
- if (fde->flags == 0) return;
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
+ /*
+ * This is a multiplexed fde, we need to include both
+ * flags in the modified event.
+ */
+ mpx_fde = talloc_get_type_abort(fde->additional_data,
+ struct tevent_fd);
+
+ mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ }
ZERO_STRUCT(event);
event.events = epoll_map_flags(fde->flags);
+ if (mpx_fde != NULL) {
+ event.events |= epoll_map_flags(mpx_fde->flags);
+ }
event.data.ptr = fde;
- if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
- epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed");
+ ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event);
+ if (ret != 0 && errno == EBADF) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
+ "EPOLL_CTL_ADD EBADF for "
+ "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
+ fde, mpx_fde, fde->fd);
+ DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
+ fde->event_ctx = NULL;
+ if (mpx_fde != NULL) {
+ DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->event_ctx = NULL;
+ }
+ return;
+ } else if (ret != 0 && errno == EEXIST && mpx_fde == NULL) {
+ ret = epoll_add_multiplex_fd(epoll_ev, fde);
+ if (ret != 0) {
+ epoll_panic(epoll_ev, "epoll_add_multiplex_fd failed",
+ false);
+ return;
+ }
+ } else if (ret != 0) {
+ epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
+ return;
}
- fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
/* only if we want to read we want to tell the event handler about errors */
if (fde->flags & TEVENT_FD_READ) {
fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
}
+
+ if (mpx_fde == NULL) {
+ return;
+ }
+
+ mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ /* only if we want to read we want to tell the event handler about errors */
+ if (mpx_fde->flags & TEVENT_FD_READ) {
+ mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ }
}
/*
@@ -167,23 +436,50 @@ static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_
static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
{
struct epoll_event event;
+ int ret;
+ struct tevent_fd *mpx_fde = NULL;
- if (epoll_ev->epoll_fd == -1) return;
-
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
- /* if there's no epoll_event, we don't need to delete it */
- if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
+ /*
+ * This is a multiplexed fde, we need to modify both events.
+ */
+ mpx_fde = talloc_get_type_abort(fde->additional_data,
+ struct tevent_fd);
+
+ mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ }
ZERO_STRUCT(event);
- event.events = epoll_map_flags(fde->flags);
- event.data.ptr = fde;
- if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) {
- tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
- "epoll_del_event failed! probable early close bug (%s)\n",
- strerror(errno));
+ ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
+ if (ret != 0 && errno == ENOENT) {
+ /*
+ * This can happen after a epoll_check_reopen
+ * within epoll_event_fd_destructor.
+ */
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_TRACE,
+ "EPOLL_CTL_DEL ignoring ENOENT for fd[%d]\n",
+ fde->fd);
+ return;
+ } else if (ret != 0 && errno == EBADF) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
+ "EPOLL_CTL_DEL EBADF for "
+ "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
+ fde, mpx_fde, fde->fd);
+ DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
+ fde->event_ctx = NULL;
+ if (mpx_fde != NULL) {
+ DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->event_ctx = NULL;
+ }
+ return;
+ } else if (ret != 0) {
+ epoll_panic(epoll_ev, "EPOLL_CTL_DEL failed", false);
+ return;
}
- fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
}
/*
@@ -191,33 +487,88 @@ static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_
*/
static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
{
+ struct tevent_fd *mpx_fde = NULL;
struct epoll_event event;
- if (epoll_ev->epoll_fd == -1) return;
+ int ret;
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
+ /*
+ * This is a multiplexed fde, we need to include both
+ * flags in the modified event.
+ */
+ mpx_fde = talloc_get_type_abort(fde->additional_data,
+ struct tevent_fd);
+
+ mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ }
+
ZERO_STRUCT(event);
event.events = epoll_map_flags(fde->flags);
+ if (mpx_fde != NULL) {
+ event.events |= epoll_map_flags(mpx_fde->flags);
+ }
event.data.ptr = fde;
- if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
- epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed");
+ ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event);
+ if (ret != 0 && errno == EBADF) {
+ tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
+ "EPOLL_CTL_MOD EBADF for "
+ "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
+ fde, mpx_fde, fde->fd);
+ DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
+ fde->event_ctx = NULL;
+ if (mpx_fde != NULL) {
+ DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
+ mpx_fde->event_ctx = NULL;
+ }
+ return;
+ } else if (ret != 0) {
+ epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
+ return;
}
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
/* only if we want to read we want to tell the event handler about errors */
if (fde->flags & TEVENT_FD_READ) {
fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
}
+
+ if (mpx_fde == NULL) {
+ return;
+ }
+
+ mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ /* only if we want to read we want to tell the event handler about errors */
+ if (mpx_fde->flags & TEVENT_FD_READ) {
+ mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ }
}
-static void epoll_change_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
+static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
{
bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
bool want_read = (fde->flags & TEVENT_FD_READ);
bool want_write= (fde->flags & TEVENT_FD_WRITE);
+ struct tevent_fd *mpx_fde = NULL;
- if (epoll_ev->epoll_fd == -1) return;
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
+ /*
+ * work out what the multiplexed fde wants.
+ */
+ mpx_fde = talloc_get_type_abort(fde->additional_data,
+ struct tevent_fd);
- fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ if (mpx_fde->flags & TEVENT_FD_READ) {
+ want_read = true;
+ }
+
+ if (mpx_fde->flags & TEVENT_FD_WRITE) {
+ want_write = true;
+ }
+ }
/* there's already an event */
if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
@@ -225,7 +576,7 @@ static void epoll_change_event(struct epoll_event_context *epoll_ev, struct teve
epoll_mod_event(epoll_ev, fde);
return;
}
- /*
+ /*
* if we want to match the select behavior, we need to remove the epoll_event
* when the caller isn't interested in events.
*
@@ -243,6 +594,38 @@ static void epoll_change_event(struct epoll_event_context *epoll_ev, struct teve
}
/*
+ Cope with epoll returning EPOLLHUP|EPOLLERR on an event.
+ Return true if there's nothing else to do, false if
+ this event needs further handling.
+*/
+static bool epoll_handle_hup_or_err(struct epoll_event_context *epoll_ev,
+ struct tevent_fd *fde)
+{
+ if (fde == NULL) {
+ /* Nothing to do if no event. */
+ return true;
+ }
+
+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+ /*
+ * if we only wait for TEVENT_FD_WRITE, we should not tell the
+ * event handler about it, and remove the epoll_event,
+ * as we only report errors when waiting for read events,
+ * to match the select() behavior
+ */
+ if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
+ /*
+ * Do the same as the poll backend and
+ * remove the writeable flag.
+ */
+ fde->flags &= ~TEVENT_FD_WRITE;
+ return true;
+ }
+ /* This has TEVENT_FD_READ set, we're not finished. */
+ return false;
+}
+
+/*
event loop handling using epoll
*/
static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
@@ -251,11 +634,10 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
#define MAXEVENTS 1
struct epoll_event events[MAXEVENTS];
int timeout = -1;
-
- if (epoll_ev->epoll_fd == -1) return -1;
+ int wait_errno;
if (tvalp) {
- /* it's better to trigger timed events a bit later than to early */
+ /* it's better to trigger timed events a bit later than too early */
timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
}
@@ -266,16 +648,17 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
+ wait_errno = errno;
tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
- if (ret == -1 && errno == EINTR && epoll_ev->ev->signal_events) {
+ if (ret == -1 && wait_errno == EINTR && epoll_ev->ev->signal_events) {
if (tevent_common_check_signal(epoll_ev->ev)) {
return 0;
}
}
- if (ret == -1 && errno != EINTR) {
- epoll_panic(epoll_ev, "epoll_wait() failed");
+ if (ret == -1 && wait_errno != EINTR) {
+ epoll_panic(epoll_ev, "epoll_wait() failed", true);
return -1;
}
@@ -286,30 +669,69 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
}
for (i=0;i<ret;i++) {
- struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
+ struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
struct tevent_fd);
uint16_t flags = 0;
+ struct tevent_fd *mpx_fde = NULL;
if (fde == NULL) {
- epoll_panic(epoll_ev, "epoll_wait() gave bad data");
+ epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
return -1;
}
- if (events[i].events & (EPOLLHUP|EPOLLERR)) {
- fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
/*
- * if we only wait for TEVENT_FD_WRITE, we should not tell the
- * event handler about it, and remove the epoll_event,
- * as we only report errors when waiting for read events,
- * to match the select() behavior
+ * Save off the multiplexed event in case we need
+ * to use it to call the handler function.
*/
- if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
- epoll_del_event(epoll_ev, fde);
+ mpx_fde = talloc_get_type_abort(fde->additional_data,
+ struct tevent_fd);
+ }
+ if (events[i].events & (EPOLLHUP|EPOLLERR)) {
+ bool handled_fde = epoll_handle_hup_or_err(epoll_ev, fde);
+ bool handled_mpx = epoll_handle_hup_or_err(epoll_ev, mpx_fde);
+
+ if (handled_fde && handled_mpx) {
+ epoll_update_event(epoll_ev, fde);
continue;
}
+
+ if (!handled_mpx) {
+ /*
+ * If the mpx event was the one that needs
+ * further handling, it's the TEVENT_FD_READ
+ * event so switch over and call that handler.
+ */
+ fde = mpx_fde;
+ mpx_fde = NULL;
+ }
flags |= TEVENT_FD_READ;
}
if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
+
+ if (flags & TEVENT_FD_WRITE) {
+ if (fde->flags & TEVENT_FD_WRITE) {
+ mpx_fde = NULL;
+ }
+ if (mpx_fde && mpx_fde->flags & TEVENT_FD_WRITE) {
+ fde = mpx_fde;
+ mpx_fde = NULL;
+ }
+ }
+
+ if (mpx_fde) {
+ /* Ensure we got the right fde. */
+ if ((flags & fde->flags) == 0) {
+ fde = mpx_fde;
+ mpx_fde = NULL;
+ }
+ }
+
+ /*
+ * make sure we only pass the flags
+ * the handler is expecting.
+ */
+ flags &= fde->flags;
if (flags) {
fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
break;
@@ -327,6 +749,12 @@ static int epoll_event_context_init(struct tevent_context *ev)
int ret;
struct epoll_event_context *epoll_ev;
+ /*
+ * We might be called during tevent_re_initialise()
+ * which means we need to free our old additional_data.
+ */
+ TALLOC_FREE(ev->additional_data);
+
epoll_ev = talloc_zero(ev, struct epoll_event_context);
if (!epoll_ev) return -1;
epoll_ev->ev = ev;
@@ -349,16 +777,58 @@ static int epoll_event_fd_destructor(struct tevent_fd *fde)
{
struct tevent_context *ev = fde->event_ctx;
struct epoll_event_context *epoll_ev = NULL;
+ bool panic_triggered = false;
+ struct tevent_fd *mpx_fde = NULL;
+ int flags = fde->flags;
+
+ if (ev == NULL) {
+ return tevent_common_fd_destructor(fde);
+ }
- if (ev) {
- epoll_ev = talloc_get_type(ev->additional_data,
- struct epoll_event_context);
+ epoll_ev = talloc_get_type_abort(ev->additional_data,
+ struct epoll_event_context);
- epoll_check_reopen(epoll_ev);
+ /*
+ * we must remove the event from the list
+ * otherwise a panic fallback handler may
+ * reuse invalid memory
+ */
+ DLIST_REMOVE(ev->fd_events, fde);
- epoll_del_event(epoll_ev, fde);
+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
+ mpx_fde = talloc_get_type_abort(fde->additional_data,
+ struct tevent_fd);
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
+ mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
+
+ fde->additional_data = NULL;
+ mpx_fde->additional_data = NULL;
+
+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ }
+
+ epoll_ev->panic_state = &panic_triggered;
+ epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ return tevent_common_fd_destructor(fde);
+ }
+
+ if (mpx_fde != NULL) {
+ epoll_update_event(epoll_ev, mpx_fde);
+ if (panic_triggered) {
+ return tevent_common_fd_destructor(fde);
+ }
}
+ fde->flags = 0;
+ epoll_update_event(epoll_ev, fde);
+ fde->flags = flags;
+ if (panic_triggered) {
+ return tevent_common_fd_destructor(fde);
+ }
+ epoll_ev->panic_state = NULL;
+
return tevent_common_fd_destructor(fde);
}
@@ -376,8 +846,7 @@ static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CT
struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
struct epoll_event_context);
struct tevent_fd *fde;
-
- epoll_check_reopen(epoll_ev);
+ bool panic_triggered = false;
fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
handler, private_data,
@@ -386,7 +855,14 @@ static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CT
talloc_set_destructor(fde, epoll_event_fd_destructor);
- epoll_add_event(epoll_ev, fde);
+ epoll_ev->panic_state = &panic_triggered;
+ epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ return fde;
+ }
+ epoll_ev->panic_state = NULL;
+
+ epoll_update_event(epoll_ev, fde);
return fde;
}
@@ -398,6 +874,7 @@ static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
{
struct tevent_context *ev;
struct epoll_event_context *epoll_ev;
+ bool panic_triggered = false;
if (fde->flags == flags) return;
@@ -406,19 +883,25 @@ static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
fde->flags = flags;
+ epoll_ev->panic_state = &panic_triggered;
epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ return;
+ }
+ epoll_ev->panic_state = NULL;
- epoll_change_event(epoll_ev, fde);
+ epoll_update_event(epoll_ev, fde);
}
/*
- do a single event loop using the events defined in ev
+ do a single event loop using the events defined in ev
*/
static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
{
struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
- struct epoll_event_context);
+ struct epoll_event_context);
struct timeval tval;
+ bool panic_triggered = false;
if (ev->signal_events &&
tevent_common_check_signal(ev)) {
@@ -435,7 +918,15 @@ static int epoll_event_loop_once(struct tevent_context *ev, const char *location
return 0;
}
+ epoll_ev->panic_state = &panic_triggered;
+ epoll_ev->panic_force_replay = true;
epoll_check_reopen(epoll_ev);
+ if (panic_triggered) {
+ errno = EINVAL;
+ return -1;
+ }
+ epoll_ev->panic_force_replay = false;
+ epoll_ev->panic_state = NULL;
return epoll_event_loop(epoll_ev, &tval);
}
@@ -446,7 +937,7 @@ static const struct tevent_ops epoll_event_ops = {
.set_fd_close_fn = tevent_common_fd_set_close_fn,
.get_fd_flags = tevent_common_fd_get_flags,
.set_fd_flags = epoll_event_set_fd_flags,
- .add_timer = tevent_common_add_timer,
+ .add_timer = tevent_common_add_timer_v2,
.schedule_immediate = tevent_common_schedule_immediate,
.add_signal = tevent_common_add_signal,
.loop_once = epoll_event_loop_once,
diff --git a/ctdb/lib/tevent/tevent_immediate.c b/ctdb/lib/tevent/tevent_immediate.c
index d5e76889394..1ac293e1758 100644
--- a/ctdb/lib/tevent/tevent_immediate.c
+++ b/ctdb/lib/tevent/tevent_immediate.c
@@ -136,3 +136,4 @@ bool tevent_common_loop_immediate(struct tevent_context *ev)
return true;
}
+
diff --git a/ctdb/lib/tevent/tevent_internal.h b/ctdb/lib/tevent/tevent_internal.h
index 21b5aea1ece..b239e7403a7 100644
--- a/ctdb/lib/tevent/tevent_internal.h
+++ b/ctdb/lib/tevent/tevent_internal.h
@@ -1,10 +1,10 @@
-/*
+/*
Unix SMB/CIFS implementation.
generalised event loop handling
INTERNAL STRUCTS. THERE ARE NO API GUARANTEES.
- External users should only ever have to include this header when
+ External users should only ever have to include this header when
implementing new tevent backends.
Copyright (C) Stefan Metzmacher 2005-2009
@@ -263,8 +263,16 @@ struct tevent_context {
tevent_trace_callback_t callback;
void *private_data;
} tracing;
+
+ /*
+ * an optimization pointer into timer_events
+ * used by used by common code via
+ * tevent_common_add_timer_v2()
+ */
+ struct tevent_timer *last_zero_timer;
};
+const struct tevent_ops *tevent_find_ops_byname(const char *name);
int tevent_common_context_destructor(struct tevent_context *ev);
int tevent_common_loop_wait(struct tevent_context *ev,
@@ -291,6 +299,13 @@ struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
void *private_data,
const char *handler_name,
const char *location);
+struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
void tevent_common_schedule_immediate(struct tevent_immediate *im,
@@ -315,9 +330,16 @@ void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se);
bool tevent_standard_init(void);
bool tevent_select_init(void);
bool tevent_poll_init(void);
+void tevent_poll_event_add_fd_internal(struct tevent_context *ev,
+ struct tevent_fd *fde);
+bool tevent_poll_mt_init(void);
#ifdef HAVE_EPOLL
bool tevent_epoll_init(void);
+bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
+ bool (*panic_fallback)(struct tevent_context *ev,
+ bool replay));
#endif
+
void tevent_trace_point_callback(struct tevent_context *ev,
enum tevent_trace_point);
diff --git a/ctdb/lib/tevent/tevent_liboop.c b/ctdb/lib/tevent/tevent_liboop.c
index c8af5ab0762..68be76bacae 100644
--- a/ctdb/lib/tevent/tevent_liboop.c
+++ b/ctdb/lib/tevent/tevent_liboop.c
@@ -1,7 +1,7 @@
-/*
+/*
Unix SMB/CIFS implementation.
main select loop and event handling
- wrapper for http://liboop.org/
+ wrapper for http://git.lysator.liu.se/liboop/
Copyright (C) Stefan Metzmacher 2005
@@ -29,12 +29,12 @@
#include <oop.h>
/*
- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
NOTE: this code compiles fine, but is completely *UNTESTED*
and is only committed as an example
- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
static int oop_event_context_destructor(struct tevent_context *ev)
@@ -79,7 +79,7 @@ static void *oop_event_fd_handler(oop_source *oop, int fd, oop_event oop_type, v
return OOP_CONTINUE;
case OOP_WRITE:
fde->handler(fde->event_ctx, fde, EVENT_FD_WRITE, fde->private_data);
- return OOP_CONTINUE;
+ return OOP_CONTINUE;
case OOP_EXCEPTION:
return OOP_ERROR;
case OOP_NUM_EVENTS:
@@ -123,7 +123,7 @@ static struct tevent_fd *oop_event_add_fd(struct tevent_context *ev, TALLOC_CTX
struct tevent_fd *fde;
oop_source_sys *oop_sys = ev->additional_data;
oop_source *oop = oop_sys_source(oop_sys);
-
+
fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd);
if (!fde) return NULL;
@@ -219,9 +219,9 @@ static int oop_event_timed_destructor(struct tevent_timer *te)
return NULL on failure (memory allocation error)
*/
static struct tevent_timer *oop_event_add_timed(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
- struct timeval next_event,
- event_timed_handler_t handler,
- void *private_data)
+ struct timeval next_event,
+ event_timed_handler_t handler,
+ void *private_data)
{
oop_source_sys *oop_sys = ev->additional_data;
oop_source *oop = oop_sys_source(oop_sys);
@@ -244,7 +244,7 @@ static struct tevent_timer *oop_event_add_timed(struct tevent_context *ev, TALLO
}
/*
- do a single event loop using the events defined in ev
+ do a single event loop using the events defined in ev
*/
static int oop_event_loop_once(struct tevent_context *ev)
{
diff --git a/ctdb/lib/tevent/tevent_poll.c b/ctdb/lib/tevent/tevent_poll.c
index 7ae3c42188d..92fcc441ac9 100644
--- a/ctdb/lib/tevent/tevent_poll.c
+++ b/ctdb/lib/tevent/tevent_poll.c
@@ -34,40 +34,195 @@ struct poll_event_context {
struct tevent_context *ev;
/*
+ * A DLIST for fresh fde's added by poll_event_add_fd but not
+ * picked up yet by poll_event_loop_once
+ */
+ struct tevent_fd *fresh;
+ /*
+ * A DLIST for disabled fde's.
+ */
+ struct tevent_fd *disabled;
+ /*
+ * one or more events were deleted or disabled
+ */
+ bool deleted;
+
+ /*
* These two arrays are maintained together.
*/
struct pollfd *fds;
- struct tevent_fd **fd_events;
- uint64_t num_fds;
+ struct tevent_fd **fdes;
+ unsigned num_fds;
+
+ /*
+ * Signal fd to wake the poll() thread
+ */
+ int signal_fd;
/* information for exiting from the event loop */
int exit_code;
};
+static int poll_event_context_destructor(struct poll_event_context *poll_ev)
+{
+ struct tevent_fd *fd, *fn;
+
+ for (fd = poll_ev->fresh; fd; fd = fn) {
+ fn = fd->next;
+ fd->event_ctx = NULL;
+ DLIST_REMOVE(poll_ev->fresh, fd);
+ }
+
+ for (fd = poll_ev->disabled; fd; fd = fn) {
+ fn = fd->next;
+ fd->event_ctx = NULL;
+ DLIST_REMOVE(poll_ev->disabled, fd);
+ }
+
+ if (poll_ev->signal_fd == -1) {
+ /*
+ * Non-threaded, no signal pipe
+ */
+ return 0;
+ }
+
+ close(poll_ev->signal_fd);
+ poll_ev->signal_fd = -1;
+
+ if (poll_ev->num_fds == 0) {
+ return 0;
+ }
+ if (poll_ev->fds[0].fd != -1) {
+ close(poll_ev->fds[0].fd);
+ poll_ev->fds[0].fd = -1;
+ }
+ return 0;
+}
+
/*
- create a select_event_context structure.
+ create a poll_event_context structure.
*/
static int poll_event_context_init(struct tevent_context *ev)
{
struct poll_event_context *poll_ev;
+ /*
+ * we might be called during tevent_re_initialise()
+ * which means we need to free our old additional_data
+ * in order to detach old fd events from the
+ * poll_ev->fresh list
+ */
+ TALLOC_FREE(ev->additional_data);
+
poll_ev = talloc_zero(ev, struct poll_event_context);
if (poll_ev == NULL) {
return -1;
}
poll_ev->ev = ev;
+ poll_ev->signal_fd = -1;
ev->additional_data = poll_ev;
+ talloc_set_destructor(poll_ev, poll_event_context_destructor);
+ return 0;
+}
+
+static bool set_nonblock(int fd)
+{
+ int val;
+
+ val = fcntl(fd, F_GETFL, 0);
+ if (val == -1) {
+ return false;
+ }
+ val |= O_NONBLOCK;
+
+ return (fcntl(fd, F_SETFL, val) != -1);
+}
+
+static int poll_event_context_init_mt(struct tevent_context *ev)
+{
+ struct poll_event_context *poll_ev;
+ struct pollfd *pfd;
+ int fds[2];
+ int ret;
+
+ ret = poll_event_context_init(ev);
+ if (ret == -1) {
+ return ret;
+ }
+
+ poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+
+ poll_ev->fds = talloc_zero(poll_ev, struct pollfd);
+ if (poll_ev->fds == NULL) {
+ return -1;
+ }
+
+ ret = pipe(fds);
+ if (ret == -1) {
+ return -1;
+ }
+
+ if (!set_nonblock(fds[0]) || !set_nonblock(fds[1])) {
+ close(fds[0]);
+ close(fds[1]);
+ return -1;
+ }
+
+ poll_ev->signal_fd = fds[1];
+
+ pfd = &poll_ev->fds[0];
+ pfd->fd = fds[0];
+ pfd->events = (POLLIN|POLLHUP);
+
+ poll_ev->num_fds = 1;
+
+ talloc_set_destructor(poll_ev, poll_event_context_destructor);
+
return 0;
}
+static void poll_event_wake_pollthread(struct poll_event_context *poll_ev)
+{
+ char c;
+ ssize_t ret;
+
+ if (poll_ev->signal_fd == -1) {
+ return;
+ }
+ c = 0;
+ do {
+ ret = write(poll_ev->signal_fd, &c, sizeof(c));
+ } while ((ret == -1) && (errno == EINTR));
+}
+
+static void poll_event_drain_signal_fd(struct poll_event_context *poll_ev)
+{
+ char buf[16];
+ ssize_t ret;
+ int fd;
+
+ if (poll_ev->signal_fd == -1) {
+ return;
+ }
+
+ if (poll_ev->num_fds < 1) {
+ return;
+ }
+ fd = poll_ev->fds[0].fd;
+
+ do {
+ ret = read(fd, buf, sizeof(buf));
+ } while (ret == sizeof(buf));
+}
+
/*
destroy an fd_event
*/
static int poll_event_fd_destructor(struct tevent_fd *fde)
{
struct tevent_context *ev = fde->event_ctx;
- struct poll_event_context *poll_ev = NULL;
- struct tevent_fd *moved_fde;
+ struct poll_event_context *poll_ev;
uint64_t del_idx = fde->additional_flags;
if (ev == NULL) {
@@ -77,16 +232,60 @@ static int poll_event_fd_destructor(struct tevent_fd *fde)
poll_ev = talloc_get_type_abort(
ev->additional_data, struct poll_event_context);
- moved_fde = poll_ev->fd_events[poll_ev->num_fds-1];
- poll_ev->fd_events[del_idx] = moved_fde;
- poll_ev->fds[del_idx] = poll_ev->fds[poll_ev->num_fds-1];
- moved_fde->additional_flags = del_idx;
+ if (del_idx == UINT64_MAX) {
+ struct tevent_fd **listp =
+ (struct tevent_fd **)fde->additional_data;
+
+ DLIST_REMOVE((*listp), fde);
+ goto done;
+ }
- poll_ev->num_fds -= 1;
+ poll_ev->fdes[del_idx] = NULL;
+ poll_ev->deleted = true;
+ poll_event_wake_pollthread(poll_ev);
done:
return tevent_common_fd_destructor(fde);
}
+static void poll_event_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ struct poll_event_context *poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+
+ tevent_common_schedule_immediate(im, ev, handler, private_data,
+ handler_name, location);
+ poll_event_wake_pollthread(poll_ev);
+}
+
+/*
+ Private function called by "standard" backend fallback.
+ Note this only allows fallback to "poll" backend, not "poll-mt".
+*/
+_PRIVATE_ void tevent_poll_event_add_fd_internal(struct tevent_context *ev,
+ struct tevent_fd *fde)
+{
+ struct poll_event_context *poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+ struct tevent_fd **listp;
+
+ if (fde->flags != 0) {
+ listp = &poll_ev->fresh;
+ } else {
+ listp = &poll_ev->disabled;
+ }
+
+ fde->additional_flags = UINT64_MAX;
+ fde->additional_data = listp;
+
+ DLIST_ADD((*listp), fde);
+ talloc_set_destructor(fde, poll_event_fd_destructor);
+}
+
/*
add a fd based event
return NULL on failure (memory allocation error)
@@ -101,83 +300,193 @@ static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
{
struct poll_event_context *poll_ev = talloc_get_type_abort(
ev->additional_data, struct poll_event_context);
- struct pollfd *pfd;
struct tevent_fd *fde;
- fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
- handler, private_data,
- handler_name, location);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ fde = talloc(mem_ctx ? mem_ctx : ev, struct tevent_fd);
if (fde == NULL) {
return NULL;
}
+ fde->event_ctx = ev;
+ fde->fd = fd;
+ fde->flags = flags;
+ fde->handler = handler;
+ fde->close_fn = NULL;
+ fde->private_data = private_data;
+ fde->handler_name = handler_name;
+ fde->location = location;
+ fde->additional_flags = UINT64_MAX;
+ fde->additional_data = NULL;
+
+ tevent_poll_event_add_fd_internal(ev, fde);
+ poll_event_wake_pollthread(poll_ev);
- /* we allocate 16 slots to avoid a lot of reallocations */
- if (talloc_array_length(poll_ev->fds) == poll_ev->num_fds) {
- struct pollfd *tmp_fds;
- struct tevent_fd **tmp_fd_events;
- tmp_fds = talloc_realloc(
- poll_ev, poll_ev->fds, struct pollfd,
- poll_ev->num_fds + 16);
- if (tmp_fds == NULL) {
- TALLOC_FREE(fde);
- return NULL;
- }
- poll_ev->fds = tmp_fds;
+ /*
+ * poll_event_loop_poll will take care of the rest in
+ * poll_event_setup_fresh
+ */
+ return fde;
+}
- tmp_fd_events = talloc_realloc(
- poll_ev, poll_ev->fd_events, struct tevent_fd *,
- poll_ev->num_fds + 16);
- if (tmp_fd_events == NULL) {
- TALLOC_FREE(fde);
- return NULL;
- }
- poll_ev->fd_events = tmp_fd_events;
+/*
+ set the fd event flags
+*/
+static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
+{
+ struct tevent_context *ev = fde->event_ctx;
+ struct poll_event_context *poll_ev;
+ uint64_t idx = fde->additional_flags;
+ uint16_t pollflags;
+
+ if (ev == NULL) {
+ return;
}
+ poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+
+ fde->flags = flags;
+
+ if (idx == UINT64_MAX) {
+ struct tevent_fd **listp =
+ (struct tevent_fd **)fde->additional_data;
- pfd = &poll_ev->fds[poll_ev->num_fds];
+ /*
+ * We move it between the fresh and disabled lists.
+ */
+ DLIST_REMOVE((*listp), fde);
+ tevent_poll_event_add_fd_internal(ev, fde);
+ poll_event_wake_pollthread(poll_ev);
+ return;
+ }
- pfd->fd = fd;
+ if (fde->flags == 0) {
+ /*
+ * We need to remove it from the array
+ * and move it to the disabled list.
+ */
+ poll_ev->fdes[idx] = NULL;
+ poll_ev->deleted = true;
+ DLIST_REMOVE(ev->fd_events, fde);
+ tevent_poll_event_add_fd_internal(ev, fde);
+ poll_event_wake_pollthread(poll_ev);
+ return;
+ }
- pfd->events = 0;
- pfd->revents = 0;
+ pollflags = 0;
if (flags & TEVENT_FD_READ) {
- pfd->events |= (POLLIN|POLLHUP);
+ pollflags |= (POLLIN|POLLHUP);
}
if (flags & TEVENT_FD_WRITE) {
- pfd->events |= (POLLOUT);
+ pollflags |= (POLLOUT);
}
+ poll_ev->fds[idx].events = pollflags;
- fde->additional_flags = poll_ev->num_fds;
- poll_ev->fd_events[poll_ev->num_fds] = fde;
+ poll_event_wake_pollthread(poll_ev);
+}
- poll_ev->num_fds += 1;
+static bool poll_event_setup_fresh(struct tevent_context *ev,
+ struct poll_event_context *poll_ev)
+{
+ struct tevent_fd *fde, *next;
+ unsigned num_fresh, num_fds;
- talloc_set_destructor(fde, poll_event_fd_destructor);
+ if (poll_ev->deleted) {
+ unsigned first_fd = (poll_ev->signal_fd != -1) ? 1 : 0;
+ unsigned i;
- return fde;
-}
+ for (i=first_fd; i < poll_ev->num_fds;) {
+ fde = poll_ev->fdes[i];
+ if (fde != NULL) {
+ i++;
+ continue;
+ }
-/*
- set the fd event flags
-*/
-static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
-{
- struct poll_event_context *poll_ev = talloc_get_type_abort(
- fde->event_ctx->additional_data, struct poll_event_context);
- uint64_t idx = fde->additional_flags;
- uint16_t pollflags = 0;
+ /*
+ * This fde was talloc_free()'ed. Delete it
+ * from the arrays
+ */
+ poll_ev->num_fds -= 1;
+ if (poll_ev->num_fds == i) {
+ break;
+ }
+ poll_ev->fds[i] = poll_ev->fds[poll_ev->num_fds];
+ poll_ev->fdes[i] = poll_ev->fdes[poll_ev->num_fds];
+ if (poll_ev->fdes[i] != NULL) {
+ poll_ev->fdes[i]->additional_flags = i;
+ }
+ }
+ }
+ poll_ev->deleted = false;
- if (flags & TEVENT_FD_READ) {
- pollflags |= (POLLIN|POLLHUP);
+ if (poll_ev->fresh == NULL) {
+ return true;
}
- if (flags & TEVENT_FD_WRITE) {
- pollflags |= (POLLOUT);
+
+ num_fresh = 0;
+ for (fde = poll_ev->fresh; fde; fde = fde->next) {
+ num_fresh += 1;
}
+ num_fds = poll_ev->num_fds + num_fresh;
- poll_ev->fds[idx].events = pollflags;
+ /*
+ * We check the length of fdes here. It is the last one
+ * enlarged, so if the realloc for poll_fd->fdes fails,
+ * poll_fd->fds will have at least the size of poll_fd->fdes
+ */
- fde->flags = flags;
+ if (num_fds >= talloc_array_length(poll_ev->fdes)) {
+ struct pollfd *tmp_fds;
+ struct tevent_fd **tmp_fdes;
+ unsigned array_length;
+
+ array_length = (num_fds + 15) & ~15; /* round up to 16 */
+
+ tmp_fds = talloc_realloc(
+ poll_ev, poll_ev->fds, struct pollfd, array_length);
+ if (tmp_fds == NULL) {
+ return false;
+ }
+ poll_ev->fds = tmp_fds;
+
+ tmp_fdes = talloc_realloc(
+ poll_ev, poll_ev->fdes, struct tevent_fd *,
+ array_length);
+ if (tmp_fdes == NULL) {
+ return false;
+ }
+ poll_ev->fdes = tmp_fdes;
+ }
+
+ for (fde = poll_ev->fresh; fde; fde = next) {
+ struct pollfd *pfd;
+
+ pfd = &poll_ev->fds[poll_ev->num_fds];
+
+ pfd->fd = fde->fd;
+ pfd->events = 0;
+ pfd->revents = 0;
+
+ if (fde->flags & TEVENT_FD_READ) {
+ pfd->events |= (POLLIN|POLLHUP);
+ }
+ if (fde->flags & TEVENT_FD_WRITE) {
+ pfd->events |= (POLLOUT);
+ }
+
+ fde->additional_flags = poll_ev->num_fds;
+ poll_ev->fdes[poll_ev->num_fds] = fde;
+
+ next = fde->next;
+ DLIST_REMOVE(poll_ev->fresh, fde);
+ DLIST_ADD(ev->fd_events, fde);
+
+ poll_ev->num_fds += 1;
+ }
+ return true;
}
/*
@@ -188,9 +497,11 @@ static int poll_event_loop_poll(struct tevent_context *ev,
{
struct poll_event_context *poll_ev = talloc_get_type_abort(
ev->additional_data, struct poll_event_context);
- struct tevent_fd *fde;
int pollrtn;
int timeout = -1;
+ int poll_errno;
+ struct tevent_fd *fde = NULL;
+ unsigned i;
if (ev->signal_events && tevent_common_check_signal(ev)) {
return 0;
@@ -201,27 +512,22 @@ static int poll_event_loop_poll(struct tevent_context *ev,
timeout += (tvalp->tv_usec + 999) / 1000;
}
+ poll_event_drain_signal_fd(poll_ev);
+
+ if (!poll_event_setup_fresh(ev, poll_ev)) {
+ return -1;
+ }
+
tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
+ poll_errno = errno;
tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
- if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
+ if (pollrtn == -1 && poll_errno == EINTR && ev->signal_events) {
tevent_common_check_signal(ev);
return 0;
}
- if (pollrtn == -1 && errno == EBADF) {
- /* the socket is dead! this should never
- happen as the socket should have first been
- made readable and that should have removed
- the event, so this must be a bug. This is a
- fatal error. */
- tevent_debug(ev, TEVENT_DEBUG_FATAL,
- "ERROR: EBADF on poll_event_loop_once\n");
- poll_ev->exit_code = EBADF;
- return -1;
- }
-
if (pollrtn == 0 && tvalp) {
/* we don't care about a possible delay here */
tevent_common_loop_timer_delay(ev);
@@ -240,11 +546,35 @@ static int poll_event_loop_poll(struct tevent_context *ev,
the handler to remove itself when called */
for (fde = ev->fd_events; fde; fde = fde->next) {
+ unsigned idx = fde->additional_flags;
struct pollfd *pfd;
- uint64_t pfd_idx = fde->additional_flags;
uint16_t flags = 0;
- pfd = &poll_ev->fds[pfd_idx];
+ if (idx == UINT64_MAX) {
+ continue;
+ }
+
+ pfd = &poll_ev->fds[idx];
+
+ if (pfd->revents & POLLNVAL) {
+ /*
+ * the socket is dead! this should never
+ * happen as the socket should have first been
+ * made readable and that should have removed
+ * the event, so this must be a bug.
+ *
+ * We ignore it here to match the epoll
+ * behavior.
+ */
+ tevent_debug(ev, TEVENT_DEBUG_ERROR,
+ "POLLNVAL on fde[%p] fd[%d] - disabling\n",
+ fde, pfd->fd);
+ poll_ev->fdes[idx] = NULL;
+ poll_ev->deleted = true;
+ DLIST_REMOVE(ev->fd_events, fde);
+ fde->event_ctx = NULL;
+ continue;
+ }
if (pfd->revents & (POLLHUP|POLLERR)) {
/* If we only wait for TEVENT_FD_WRITE, we
@@ -264,9 +594,38 @@ static int poll_event_loop_poll(struct tevent_context *ev,
if (pfd->revents & POLLOUT) {
flags |= TEVENT_FD_WRITE;
}
+ /*
+ * Note that fde->flags could be changed when using
+ * the poll_mt backend together with threads,
+ * that why we need to check pfd->revents and fde->flags
+ */
+ flags &= fde->flags;
if (flags != 0) {
+ DLIST_DEMOTE(ev->fd_events, fde, struct tevent_fd);
fde->handler(ev, fde, flags, fde->private_data);
- break;
+ return 0;
+ }
+ }
+
+ for (i = 0; i < poll_ev->num_fds; i++) {
+ if (poll_ev->fds[i].revents & POLLNVAL) {
+ /*
+ * the socket is dead! this should never
+ * happen as the socket should have first been
+ * made readable and that should have removed
+ * the event, so this must be a bug or
+ * a race in the poll_mt usage.
+ */
+ fde = poll_ev->fdes[i];
+ tevent_debug(ev, TEVENT_DEBUG_WARNING,
+ "POLLNVAL on dangling fd[%d] fde[%p] - disabling\n",
+ poll_ev->fds[i].fd, fde);
+ poll_ev->fdes[i] = NULL;
+ poll_ev->deleted = true;
+ if (fde != NULL) {
+ DLIST_REMOVE(ev->fd_events, fde);
+ fde->event_ctx = NULL;
+ }
}
}
@@ -299,20 +658,68 @@ static int poll_event_loop_once(struct tevent_context *ev,
return poll_event_loop_poll(ev, &tval);
}
+static int poll_event_loop_wait(struct tevent_context *ev,
+ const char *location)
+{
+ struct poll_event_context *poll_ev = talloc_get_type_abort(
+ ev->additional_data, struct poll_event_context);
+
+ /*
+ * loop as long as we have events pending
+ */
+ while (ev->fd_events ||
+ ev->timer_events ||
+ ev->immediate_events ||
+ ev->signal_events ||
+ poll_ev->fresh ||
+ poll_ev->disabled) {
+ int ret;
+ ret = _tevent_loop_once(ev, location);
+ if (ret != 0) {
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "_tevent_loop_once() failed: %d - %s\n",
+ ret, strerror(errno));
+ return ret;
+ }
+ }
+
+ tevent_debug(ev, TEVENT_DEBUG_WARNING,
+ "poll_event_loop_wait() out of events\n");
+ return 0;
+}
+
static const struct tevent_ops poll_event_ops = {
.context_init = poll_event_context_init,
.add_fd = poll_event_add_fd,
.set_fd_close_fn = tevent_common_fd_set_close_fn,
.get_fd_flags = tevent_common_fd_get_flags,
.set_fd_flags = poll_event_set_fd_flags,
- .add_timer = tevent_common_add_timer,
+ .add_timer = tevent_common_add_timer_v2,
.schedule_immediate = tevent_common_schedule_immediate,
.add_signal = tevent_common_add_signal,
.loop_once = poll_event_loop_once,
- .loop_wait = tevent_common_loop_wait,
+ .loop_wait = poll_event_loop_wait,
};
_PRIVATE_ bool tevent_poll_init(void)
{
return tevent_register_backend("poll", &poll_event_ops);
}
+
+static const struct tevent_ops poll_event_mt_ops = {
+ .context_init = poll_event_context_init_mt,
+ .add_fd = poll_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = poll_event_set_fd_flags,
+ .add_timer = tevent_common_add_timer_v2,
+ .schedule_immediate = poll_event_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = poll_event_loop_once,
+ .loop_wait = poll_event_loop_wait,
+};
+
+_PRIVATE_ bool tevent_poll_mt_init(void)
+{
+ return tevent_register_backend("poll_mt", &poll_event_mt_ops);
+}
diff --git a/ctdb/lib/tevent/tevent_select.c b/ctdb/lib/tevent/tevent_select.c
index 47ad13ee582..bfce246e22d 100644
--- a/ctdb/lib/tevent/tevent_select.c
+++ b/ctdb/lib/tevent/tevent_select.c
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/CIFS implementation.
main select loop and event handling
Copyright (C) Andrew Tridgell 2003-2005
@@ -47,6 +47,12 @@ static int select_event_context_init(struct tevent_context *ev)
{
struct select_event_context *select_ev;
+ /*
+ * We might be called during tevent_re_initialise()
+ * which means we need to free our old additional_data.
+ */
+ TALLOC_FREE(ev->additional_data);
+
select_ev = talloc_zero(ev, struct select_event_context);
if (!select_ev) return -1;
select_ev->ev = ev;
@@ -138,6 +144,7 @@ static int select_event_loop_select(struct select_event_context *select_ev, stru
fd_set r_fds, w_fds;
struct tevent_fd *fde;
int selrtn;
+ int select_errno;
/* we maybe need to recalculate the maxfd */
if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
@@ -150,6 +157,10 @@ static int select_event_loop_select(struct select_event_context *select_ev, stru
/* setup any fd events */
for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
+ tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL,
+ "ERROR: EBADF fd[%d] >= %d "
+ "select_event_loop_once\n",
+ fde->fd, FD_SETSIZE);
errno = EBADF;
return -1;
}
@@ -169,15 +180,16 @@ static int select_event_loop_select(struct select_event_context *select_ev, stru
tevent_trace_point_callback(select_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
+ select_errno = errno;
tevent_trace_point_callback(select_ev->ev, TEVENT_TRACE_AFTER_WAIT);
- if (selrtn == -1 && errno == EINTR &&
+ if (selrtn == -1 && select_errno == EINTR &&
select_ev->ev->signal_events) {
tevent_common_check_signal(select_ev->ev);
return 0;
}
- if (selrtn == -1 && errno == EBADF) {
+ if (selrtn == -1 && select_errno == EBADF) {
/* the socket is dead! this should never
happen as the socket should have first been
made readable and that should have removed
@@ -202,9 +214,14 @@ static int select_event_loop_select(struct select_event_context *select_ev, stru
for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
uint16_t flags = 0;
- if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
- if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
+ if (FD_ISSET(fde->fd, &r_fds) && (fde->flags & TEVENT_FD_READ)) {
+ flags |= TEVENT_FD_READ;
+ }
+ if (FD_ISSET(fde->fd, &w_fds) && (fde->flags & TEVENT_FD_WRITE)) {
+ flags |= TEVENT_FD_WRITE;
+ }
if (flags) {
+ DLIST_DEMOTE(select_ev->ev->fd_events, fde, struct tevent_fd);
fde->handler(select_ev->ev, fde, flags, fde->private_data);
break;
}
@@ -215,12 +232,12 @@ static int select_event_loop_select(struct select_event_context *select_ev, stru
}
/*
- do a single event loop using the events defined in ev
+ do a single event loop using the events defined in ev
*/
static int select_event_loop_once(struct tevent_context *ev, const char *location)
{
struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
- struct select_event_context);
+ struct select_event_context);
struct timeval tval;
if (ev->signal_events &&
@@ -247,7 +264,7 @@ static const struct tevent_ops select_event_ops = {
.set_fd_close_fn = tevent_common_fd_set_close_fn,
.get_fd_flags = tevent_common_fd_get_flags,
.set_fd_flags = tevent_common_fd_set_flags,
- .add_timer = tevent_common_add_timer,
+ .add_timer = tevent_common_add_timer_v2,
.schedule_immediate = tevent_common_schedule_immediate,
.add_signal = tevent_common_add_signal,
.loop_once = select_event_loop_once,
diff --git a/ctdb/lib/tevent/tevent_signal.c b/ctdb/lib/tevent/tevent_signal.c
index 56bcef91502..b5a56ef03aa 100644
--- a/ctdb/lib/tevent/tevent_signal.c
+++ b/ctdb/lib/tevent/tevent_signal.c
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/CIFS implementation.
common events code for signal events
@@ -30,8 +30,6 @@
#include "tevent_internal.h"
#include "tevent_util.h"
-#define TEVENT_NUM_SIGNALS 64
-
/* maximum number of SA_SIGINFO signals to hold in the queue.
NB. This *MUST* be a power of 2, in order for the ring buffer
wrap to work correctly. Thanks to Petr Vandrovec <petr@vandrovec.name>
@@ -121,10 +119,39 @@ static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
if (count+1 == TEVENT_SA_INFO_QUEUE_COUNT) {
/* we've filled the info array - block this signal until
these ones are delivered */
+#ifdef HAVE_UCONTEXT_T
+ /*
+ * This is the only way for this to work.
+ * By default signum is blocked inside this
+ * signal handler using a temporary mask,
+ * but what we really need to do now is
+ * block it in the callers mask, so it
+ * stays blocked when the temporary signal
+ * handler mask is replaced when we return
+ * from here. The callers mask can be found
+ * in the ucontext_t passed in as the
+ * void *uctx argument.
+ */
+ ucontext_t *ucp = (ucontext_t *)uctx;
+ sigaddset(&ucp->uc_sigmask, signum);
+#else
+ /*
+ * WARNING !!! WARNING !!!!
+ *
+ * This code doesn't work.
+ * By default signum is blocked inside this
+ * signal handler, but calling sigprocmask
+ * modifies the temporary signal mask being
+ * used *inside* this handler, which will be
+ * replaced by the callers signal mask once
+ * we return from here. See Samba
+ * bug #9550 for details.
+ */
sigset_t set;
sigemptyset(&set);
sigaddset(&set, signum);
sigprocmask(SIG_BLOCK, &set, NULL);
+#endif
TEVENT_SIG_INCREMENT(sig_state->sig_blocked[signum]);
}
}
@@ -175,7 +202,7 @@ static int tevent_signal_destructor(struct tevent_signal *se)
/*
this is part of the pipe hack needed to avoid the signal race condition
*/
-static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
+static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde,
uint16_t flags, void *_private)
{
char c[16];
@@ -284,7 +311,7 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
sig_state->oldact[signum] = talloc(sig_state, struct sigaction);
if (sig_state->oldact[signum] == NULL) {
talloc_free(se);
- return NULL;
+ return NULL;
}
if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
talloc_free(se);
@@ -328,7 +355,7 @@ int tevent_common_check_signal(struct tevent_context *ev)
if (!sig_state || !TEVENT_SIG_PENDING(sig_state->got_signal)) {
return 0;
}
-
+
for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) {
struct tevent_common_signal_list *sl, *next;
struct tevent_sigcounter counter = sig_state->signal_count[i];
@@ -377,7 +404,7 @@ int tevent_common_check_signal(struct tevent_context *ev)
uint32_t ofs = (counter.seen + j)
% TEVENT_SA_INFO_QUEUE_COUNT;
se->handler(ev, se, i, 1,
- (void*)&sig_state->sig_info[i][ofs],
+ (void*)&sig_state->sig_info[i][ofs],
se->private_data);
if (!exists) {
break;
diff --git a/ctdb/lib/tevent/tevent_standard.c b/ctdb/lib/tevent/tevent_standard.c
index 6c34854f6c7..258499484a2 100644
--- a/ctdb/lib/tevent/tevent_standard.c
+++ b/ctdb/lib/tevent/tevent_standard.c
@@ -1,8 +1,8 @@
-/*
+/*
Unix SMB/CIFS implementation.
main select loop and event handling
- Copyright (C) Andrew Tridgell 2003-2005
- Copyright (C) Stefan Metzmacher 2005-2009
+ Copyright (C) Stefan Metzmacher 2013
+ Copyright (C) Jeremy Allison 2013
** NOTE! The following LGPL license applies to the tevent
** library. This does NOT imply that all of Samba is released
@@ -26,565 +26,207 @@
This is SAMBA's default event loop code
- we try to use epoll if configure detected support for it
- otherwise we use select()
+ otherwise we use poll()
- if epoll is broken on the system or the kernel doesn't support it
- at runtime we fallback to select()
+ at runtime we fallback to poll()
*/
#include "replace.h"
-#include "system/filesys.h"
-#include "system/select.h"
#include "tevent.h"
#include "tevent_util.h"
#include "tevent_internal.h"
-struct std_event_context {
- /* a pointer back to the generic event_context */
- struct tevent_context *ev;
-
- /* the maximum file descriptor number in fd_events */
- int maxfd;
-
- /* information for exiting from the event loop */
- int exit_code;
-
- /* when using epoll this is the handle from epoll_create */
- int epoll_fd;
-
- /* our pid at the time the epoll_fd was created */
- pid_t pid;
+struct std_event_glue {
+ const struct tevent_ops *epoll_ops;
+ const struct tevent_ops *poll_ops;
+ struct tevent_ops *glue_ops;
+ bool fallback_replay;
};
-/* use epoll if it is available */
-#if HAVE_EPOLL
-/*
- called when a epoll call fails, and we should fallback
- to using select
-*/
-static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason)
-{
- tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
- "%s (%s) - falling back to select()\n",
- reason, strerror(errno));
- close(std_ev->epoll_fd);
- std_ev->epoll_fd = -1;
- talloc_set_destructor(std_ev, NULL);
-}
-
-/*
- map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
-*/
-static uint32_t epoll_map_flags(uint16_t flags)
-{
- uint32_t ret = 0;
- if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
- if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
- return ret;
-}
+static int std_event_context_init(struct tevent_context *ev);
-/*
- free the epoll fd
-*/
-static int epoll_ctx_destructor(struct std_event_context *std_ev)
-{
- if (std_ev->epoll_fd != -1) {
- close(std_ev->epoll_fd);
- }
- std_ev->epoll_fd = -1;
- return 0;
-}
+static const struct tevent_ops std_event_ops = {
+ .context_init = std_event_context_init,
+};
/*
- init the epoll fd
+ If this function gets called. epoll failed at runtime.
+ Move us to using poll instead. If we return false here,
+ caller should abort().
*/
-static void epoll_init_ctx(struct std_event_context *std_ev)
-{
- std_ev->epoll_fd = epoll_create(64);
- if (std_ev->epoll_fd == -1) {
- tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
- "Failed to create epoll handle.\n");
- return;
- }
-
- if (!ev_set_close_on_exec(std_ev->epoll_fd)) {
- tevent_debug(std_ev->ev, TEVENT_DEBUG_WARNING,
- "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
- }
-
- std_ev->pid = getpid();
- talloc_set_destructor(std_ev, epoll_ctx_destructor);
-}
-
-static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde);
-
-/*
- reopen the epoll handle when our pid changes
- see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
- demonstration of why this is needed
- */
-static void epoll_check_reopen(struct std_event_context *std_ev)
+static bool std_fallback_to_poll(struct tevent_context *ev, bool replay)
{
+ void *glue_ptr = talloc_parent(ev->ops);
+ struct std_event_glue *glue =
+ talloc_get_type_abort(glue_ptr,
+ struct std_event_glue);
+ int ret;
struct tevent_fd *fde;
+ struct tevent_fd *fde_next;
- if (std_ev->pid == getpid()) {
- return;
- }
+ glue->fallback_replay = replay;
- close(std_ev->epoll_fd);
- std_ev->epoll_fd = epoll_create(64);
- if (std_ev->epoll_fd == -1) {
- tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
- "Failed to recreate epoll handle after fork\n");
- return;
- }
+ /* First switch all the ops to poll. */
+ glue->epoll_ops = NULL;
- if (!ev_set_close_on_exec(std_ev->epoll_fd)) {
- tevent_debug(std_ev->ev, TEVENT_DEBUG_WARNING,
- "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
- }
+ /*
+ * Set custom_ops the same as poll.
+ */
+ *glue->glue_ops = *glue->poll_ops;
+ glue->glue_ops->context_init = std_event_context_init;
- std_ev->pid = getpid();
- for (fde=std_ev->ev->fd_events;fde;fde=fde->next) {
- epoll_add_event(std_ev, fde);
+ /* Next initialize the poll backend. */
+ ret = glue->poll_ops->context_init(ev);
+ if (ret != 0) {
+ return false;
}
-}
-
-#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
-#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1)
-#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
-
-/*
- add the epoll event to the given fd_event
-*/
-static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde)
-{
- struct epoll_event event;
- if (std_ev->epoll_fd == -1) return;
-
- fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
- /* if we don't want events yet, don't add an epoll_event */
- if (fde->flags == 0) return;
+ /*
+ * Now we have to change all the existing file descriptor
+ * events from the epoll backend to the poll backend.
+ */
+ for (fde = ev->fd_events; fde; fde = fde_next) {
+ /*
+ * We must remove this fde off the ev->fd_events list.
+ */
+ fde_next = fde->next;
- ZERO_STRUCT(event);
- event.events = epoll_map_flags(fde->flags);
- event.data.ptr = fde;
- if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
- epoll_fallback_to_select(std_ev, "EPOLL_CTL_ADD failed");
- }
- fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ /* Remove from the ev->fd_events list. */
+ DLIST_REMOVE(ev->fd_events, fde);
- /* only if we want to read we want to tell the event handler about errors */
- if (fde->flags & TEVENT_FD_READ) {
- fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ /* Re-add this event as a poll backend event. */
+ tevent_poll_event_add_fd_internal(ev, fde);
}
-}
-
-/*
- delete the epoll event for given fd_event
-*/
-static void epoll_del_event(struct std_event_context *std_ev, struct tevent_fd *fde)
-{
- struct epoll_event event;
- if (std_ev->epoll_fd == -1) return;
-
- fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
- /* if there's no epoll_event, we don't need to delete it */
- if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
-
- ZERO_STRUCT(event);
- event.events = epoll_map_flags(fde->flags);
- event.data.ptr = fde;
- epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
- fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
+ return true;
}
-/*
- change the epoll event to the given fd_event
-*/
-static void epoll_mod_event(struct std_event_context *std_ev, struct tevent_fd *fde)
+static int std_event_loop_once(struct tevent_context *ev, const char *location)
{
- struct epoll_event event;
- if (std_ev->epoll_fd == -1) return;
-
- fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
+ void *glue_ptr = talloc_parent(ev->ops);
+ struct std_event_glue *glue =
+ talloc_get_type_abort(glue_ptr,
+ struct std_event_glue);
+ int ret;
- ZERO_STRUCT(event);
- event.events = epoll_map_flags(fde->flags);
- event.data.ptr = fde;
- if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
- epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed");
+ ret = glue->epoll_ops->loop_once(ev, location);
+ if (glue->epoll_ops != NULL) {
+ /* No fallback */
+ return ret;
}
- /* only if we want to read we want to tell the event handler about errors */
- if (fde->flags & TEVENT_FD_READ) {
- fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
- }
-}
-
-static void epoll_change_event(struct std_event_context *std_ev, struct tevent_fd *fde)
-{
- bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
- bool want_read = (fde->flags & TEVENT_FD_READ);
- bool want_write= (fde->flags & TEVENT_FD_WRITE);
-
- if (std_ev->epoll_fd == -1) return;
-
- fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
-
- /* there's already an event */
- if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
- if (want_read || (want_write && !got_error)) {
- epoll_mod_event(std_ev, fde);
- return;
- }
+ if (!glue->fallback_replay) {
/*
- * if we want to match the select behavior, we need to remove the epoll_event
- * when the caller isn't interested in events.
- *
- * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
+ * The problem happened while modifying an event.
+ * An event handler was triggered in this case
+ * and there is no need to call loop_once() again.
*/
- epoll_del_event(std_ev, fde);
- return;
+ return ret;
}
- /* there's no epoll_event attached to the fde */
- if (want_read || (want_write && !got_error)) {
- epoll_add_event(std_ev, fde);
- return;
- }
+ return glue->poll_ops->loop_once(ev, location);
}
-/*
- event loop handling using epoll
-*/
-static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp)
+static int std_event_loop_wait(struct tevent_context *ev, const char *location)
{
- int ret, i;
-#define MAXEVENTS 1
- struct epoll_event events[MAXEVENTS];
- int timeout = -1;
+ void *glue_ptr = talloc_parent(ev->ops);
+ struct std_event_glue *glue =
+ talloc_get_type_abort(glue_ptr,
+ struct std_event_glue);
+ int ret;
- if (std_ev->epoll_fd == -1) return -1;
-
- if (tvalp) {
- /* it's better to trigger timed events a bit later than to early */
- timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
- }
-
- if (std_ev->ev->signal_events &&
- tevent_common_check_signal(std_ev->ev)) {
- return 0;
- }
-
- tevent_trace_point_callback(std_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
- ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout);
- tevent_trace_point_callback(std_ev->ev, TEVENT_TRACE_AFTER_WAIT);
-
- if (ret == -1 && errno == EINTR && std_ev->ev->signal_events) {
- if (tevent_common_check_signal(std_ev->ev)) {
- return 0;
- }
- }
-
- if (ret == -1 && errno != EINTR) {
- epoll_fallback_to_select(std_ev, "epoll_wait() failed");
- return -1;
- }
-
- if (ret == 0 && tvalp) {
- /* we don't care about a possible delay here */
- tevent_common_loop_timer_delay(std_ev->ev);
- return 0;
+ ret = glue->epoll_ops->loop_wait(ev, location);
+ if (glue->epoll_ops != NULL) {
+ /* No fallback */
+ return ret;
}
- for (i=0;i<ret;i++) {
- struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
- struct tevent_fd);
- uint16_t flags = 0;
-
- if (fde == NULL) {
- epoll_fallback_to_select(std_ev, "epoll_wait() gave bad data");
- return -1;
- }
- if (events[i].events & (EPOLLHUP|EPOLLERR)) {
- fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
- /*
- * if we only wait for TEVENT_FD_WRITE, we should not tell the
- * event handler about it, and remove the epoll_event,
- * as we only report errors when waiting for read events,
- * to match the select() behavior
- */
- if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
- epoll_del_event(std_ev, fde);
- continue;
- }
- flags |= TEVENT_FD_READ;
- }
- if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
- if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
- if (flags) {
- fde->handler(std_ev->ev, fde, flags, fde->private_data);
- break;
- }
- }
-
- return 0;
+ return glue->poll_ops->loop_wait(ev, location);
}
-#else
-#define epoll_init_ctx(std_ev)
-#define epoll_add_event(std_ev,fde)
-#define epoll_del_event(std_ev,fde)
-#define epoll_change_event(std_ev,fde)
-#define epoll_event_loop(std_ev,tvalp) (-1)
-#define epoll_check_reopen(std_ev)
-#endif
-
/*
- create a std_event_context structure.
+ Initialize the epoll backend and allow it to call a
+ switch function if epoll fails at runtime.
*/
static int std_event_context_init(struct tevent_context *ev)
{
- struct std_event_context *std_ev;
-
- std_ev = talloc_zero(ev, struct std_event_context);
- if (!std_ev) return -1;
- std_ev->ev = ev;
- std_ev->epoll_fd = -1;
+ struct std_event_glue *glue;
+ int ret;
- epoll_init_ctx(std_ev);
+ /*
+ * If this is the first initialization
+ * we need to set up the allocated ops
+ * pointers.
+ */
- ev->additional_data = std_ev;
- return 0;
-}
-
-/*
- recalculate the maxfd
-*/
-static void calc_maxfd(struct std_event_context *std_ev)
-{
- struct tevent_fd *fde;
-
- std_ev->maxfd = 0;
- for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
- if (fde->fd > std_ev->maxfd) {
- std_ev->maxfd = fde->fd;
+ if (ev->ops == &std_event_ops) {
+ glue = talloc_zero(ev, struct std_event_glue);
+ if (glue == NULL) {
+ return -1;
}
- }
-}
-
-/* to mark the ev->maxfd invalid
- * this means we need to recalculate it
- */
-#define EVENT_INVALID_MAXFD (-1)
+ glue->epoll_ops = tevent_find_ops_byname("epoll");
-/*
- destroy an fd_event
-*/
-static int std_event_fd_destructor(struct tevent_fd *fde)
-{
- struct tevent_context *ev = fde->event_ctx;
- struct std_event_context *std_ev = NULL;
-
- if (ev) {
- std_ev = talloc_get_type(ev->additional_data,
- struct std_event_context);
-
- epoll_check_reopen(std_ev);
-
- if (std_ev->maxfd == fde->fd) {
- std_ev->maxfd = EVENT_INVALID_MAXFD;
+ glue->poll_ops = tevent_find_ops_byname("poll");
+ if (glue->poll_ops == NULL) {
+ return -1;
}
- epoll_del_event(std_ev, fde);
- }
-
- return tevent_common_fd_destructor(fde);
-}
-
-/*
- add a fd based event
- return NULL on failure (memory allocation error)
-*/
-static struct tevent_fd *std_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
- int fd, uint16_t flags,
- tevent_fd_handler_t handler,
- void *private_data,
- const char *handler_name,
- const char *location)
-{
- struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
- struct std_event_context);
- struct tevent_fd *fde;
-
- epoll_check_reopen(std_ev);
-
- fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
- handler, private_data,
- handler_name, location);
- if (!fde) return NULL;
-
- if ((std_ev->maxfd != EVENT_INVALID_MAXFD)
- && (fde->fd > std_ev->maxfd)) {
- std_ev->maxfd = fde->fd;
- }
- talloc_set_destructor(fde, std_event_fd_destructor);
-
- epoll_add_event(std_ev, fde);
-
- return fde;
-}
-
-/*
- set the fd event flags
-*/
-static void std_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
-{
- struct tevent_context *ev;
- struct std_event_context *std_ev;
-
- if (fde->flags == flags) return;
-
- ev = fde->event_ctx;
- std_ev = talloc_get_type(ev->additional_data, struct std_event_context);
-
- fde->flags = flags;
-
- epoll_check_reopen(std_ev);
-
- epoll_change_event(std_ev, fde);
-}
-
-/*
- event loop handling using select()
-*/
-static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp)
-{
- fd_set r_fds, w_fds;
- struct tevent_fd *fde;
- int selrtn;
-
- /* we maybe need to recalculate the maxfd */
- if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
- calc_maxfd(std_ev);
- }
-
- FD_ZERO(&r_fds);
- FD_ZERO(&w_fds);
-
- /* setup any fd events */
- for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
- if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
- std_ev->exit_code = EBADF;
+ /*
+ * Allocate space for our custom ops.
+ * Allocate as a child of our epoll_ops pointer
+ * so we can easily get to it using talloc_parent.
+ */
+ glue->glue_ops = talloc_zero(glue, struct tevent_ops);
+ if (glue->glue_ops == NULL) {
+ talloc_free(glue);
return -1;
}
- if (fde->flags & TEVENT_FD_READ) {
- FD_SET(fde->fd, &r_fds);
- }
- if (fde->flags & TEVENT_FD_WRITE) {
- FD_SET(fde->fd, &w_fds);
- }
- }
-
- if (std_ev->ev->signal_events &&
- tevent_common_check_signal(std_ev->ev)) {
- return 0;
- }
-
- selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
-
- if (selrtn == -1 && errno == EINTR &&
- std_ev->ev->signal_events) {
- tevent_common_check_signal(std_ev->ev);
- return 0;
- }
-
- if (selrtn == -1 && errno == EBADF) {
- /* the socket is dead! this should never
- happen as the socket should have first been
- made readable and that should have removed
- the event, so this must be a bug. This is a
- fatal error. */
- tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
- "ERROR: EBADF on std_event_loop_once\n");
- std_ev->exit_code = EBADF;
- return -1;
- }
- if (selrtn == 0 && tvalp) {
- /* we don't care about a possible delay here */
- tevent_common_loop_timer_delay(std_ev->ev);
- return 0;
+ ev->ops = glue->glue_ops;
+ } else {
+ void *glue_ptr = talloc_parent(ev->ops);
+ glue = talloc_get_type_abort(glue_ptr, struct std_event_glue);
}
- if (selrtn > 0) {
- /* at least one file descriptor is ready - check
- which ones and call the handler, being careful to allow
- the handler to remove itself when called */
- for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
- uint16_t flags = 0;
-
- if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
- if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
- if (flags & fde->flags) {
- fde->handler(std_ev->ev, fde, flags, fde->private_data);
- break;
- }
+ if (glue->epoll_ops != NULL) {
+ /*
+ * Set custom_ops the same as epoll,
+ * except re-init using std_event_context_init()
+ * and use std_event_loop_once() to add the
+ * ability to fallback to a poll backend on
+ * epoll runtime error.
+ */
+ *glue->glue_ops = *glue->epoll_ops;
+ glue->glue_ops->context_init = std_event_context_init;
+ glue->glue_ops->loop_once = std_event_loop_once;
+ glue->glue_ops->loop_wait = std_event_loop_wait;
+
+ ret = glue->epoll_ops->context_init(ev);
+ if (ret == -1) {
+ goto fallback;
}
- }
-
- return 0;
-}
-
-/*
- do a single event loop using the events defined in ev
-*/
-static int std_event_loop_once(struct tevent_context *ev, const char *location)
-{
- struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
- struct std_event_context);
- struct timeval tval;
-
- if (ev->signal_events &&
- tevent_common_check_signal(ev)) {
- return 0;
- }
-
- if (ev->immediate_events &&
- tevent_common_loop_immediate(ev)) {
- return 0;
- }
+#ifdef HAVE_EPOLL
+ if (!tevent_epoll_set_panic_fallback(ev, std_fallback_to_poll)) {
+ TALLOC_FREE(ev->additional_data);
+ goto fallback;
+ }
+#endif
- tval = tevent_common_loop_timer_delay(ev);
- if (tevent_timeval_is_zero(&tval)) {
- return 0;
+ return ret;
}
- epoll_check_reopen(std_ev);
+fallback:
+ glue->epoll_ops = NULL;
- if (epoll_event_loop(std_ev, &tval) == 0) {
- return 0;
- }
+ /*
+ * Set custom_ops the same as poll.
+ */
+ *glue->glue_ops = *glue->poll_ops;
+ glue->glue_ops->context_init = std_event_context_init;
- return std_event_loop_select(std_ev, &tval);
+ return glue->poll_ops->context_init(ev);
}
-static const struct tevent_ops std_event_ops = {
- .context_init = std_event_context_init,
- .add_fd = std_event_add_fd,
- .set_fd_close_fn = tevent_common_fd_set_close_fn,
- .get_fd_flags = tevent_common_fd_get_flags,
- .set_fd_flags = std_event_set_fd_flags,
- .add_timer = tevent_common_add_timer,
- .schedule_immediate = tevent_common_schedule_immediate,
- .add_signal = tevent_common_add_signal,
- .loop_once = std_event_loop_once,
- .loop_wait = tevent_common_loop_wait,
-};
-
-
_PRIVATE_ bool tevent_standard_init(void)
{
return tevent_register_backend("standard", &std_event_ops);
diff --git a/ctdb/lib/tevent/tevent_timed.c b/ctdb/lib/tevent/tevent_timed.c
index cc25428f187..920d39fe063 100644
--- a/ctdb/lib/tevent/tevent_timed.c
+++ b/ctdb/lib/tevent/tevent_timed.c
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/CIFS implementation.
common events code for timed events
@@ -31,7 +31,7 @@
#include "tevent_util.h"
/**
- compare two timeval structures.
+ compare two timeval structures.
Return -1 if tv1 < tv2
Return 0 if tv1 == tv2
Return 1 if tv1 > tv2
@@ -133,13 +133,18 @@ struct timeval tevent_timeval_current_ofs(uint32_t secs, uint32_t usecs)
*/
static int tevent_common_timed_destructor(struct tevent_timer *te)
{
+ if (te->event_ctx == NULL) {
+ return 0;
+ }
+
tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
"Destroying timer event %p \"%s\"\n",
te, te->handler_name);
- if (te->event_ctx) {
- DLIST_REMOVE(te->event_ctx->timer_events, te);
+ if (te->event_ctx->last_zero_timer == te) {
+ te->event_ctx->last_zero_timer = DLIST_PREV(te);
}
+ DLIST_REMOVE(te->event_ctx->timer_events, te);
return 0;
}
@@ -153,14 +158,17 @@ static int tevent_common_timed_deny_destructor(struct tevent_timer *te)
add a timed event
return NULL on failure (memory allocation error)
*/
-struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
- struct timeval next_event,
- tevent_timer_handler_t handler,
- void *private_data,
- const char *handler_name,
- const char *location)
+static struct tevent_timer *tevent_common_add_timer_internal(
+ struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location,
+ bool optimize_zero)
{
- struct tevent_timer *te, *last_te, *cur_te;
+ struct tevent_timer *te, *prev_te, *cur_te;
te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
if (te == NULL) return NULL;
@@ -173,18 +181,52 @@ struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev, TALLOC_C
te->location = location;
te->additional_data = NULL;
+ if (ev->timer_events == NULL) {
+ ev->last_zero_timer = NULL;
+ }
+
/* keep the list ordered */
- last_te = NULL;
- for (cur_te = ev->timer_events; cur_te; cur_te = cur_te->next) {
- /* if the new event comes before the current one break */
- if (tevent_timeval_compare(&te->next_event, &cur_te->next_event) < 0) {
+ prev_te = NULL;
+ if (optimize_zero && tevent_timeval_is_zero(&te->next_event)) {
+ /*
+ * Some callers use zero tevent_timer
+ * instead of tevent_immediate events.
+ *
+ * As these can happen very often,
+ * we remember the last zero timer
+ * in the list.
+ */
+ prev_te = ev->last_zero_timer;
+ ev->last_zero_timer = te;
+ } else {
+ /*
+ * we traverse the list from the tail
+ * because it's much more likely that
+ * timers are added at the end of the list
+ */
+ for (cur_te = DLIST_TAIL(ev->timer_events);
+ cur_te != NULL;
+ cur_te = DLIST_PREV(cur_te))
+ {
+ int ret;
+
+ /*
+ * if the new event comes before the current
+ * we continue searching
+ */
+ ret = tevent_timeval_compare(&te->next_event,
+ &cur_te->next_event);
+ if (ret < 0) {
+ continue;
+ }
+
break;
}
- last_te = cur_te;
+ prev_te = cur_te;
}
- DLIST_ADD_AFTER(ev->timer_events, te, last_te);
+ DLIST_ADD_AFTER(ev->timer_events, te, prev_te);
talloc_set_destructor(te, tevent_common_timed_destructor);
@@ -194,6 +236,44 @@ struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev, TALLOC_C
return te;
}
+struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ /*
+ * do not use optimization, there are broken Samba
+ * versions which use tevent_common_add_timer()
+ * without using tevent_common_loop_timer_delay(),
+ * it just uses DLIST_REMOVE(ev->timer_events, te)
+ * and would leave ev->last_zero_timer behind.
+ */
+ return tevent_common_add_timer_internal(ev, mem_ctx, next_event,
+ handler, private_data,
+ handler_name, location,
+ false);
+}
+
+struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ struct timeval next_event,
+ tevent_timer_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ /*
+ * Here we turn on last_zero_timer optimization
+ */
+ return tevent_common_add_timer_internal(ev, mem_ctx, next_event,
+ handler, private_data,
+ handler_name, location,
+ true);
+}
+
/*
do a single event loop using the events defined in ev
@@ -242,8 +322,15 @@ struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
/* We need to remove the timer from the list before calling the
* handler because in a semi-async inner event loop called from the
* handler we don't want to come across this event again -- vl */
+ if (ev->last_zero_timer == te) {
+ ev->last_zero_timer = DLIST_PREV(te);
+ }
DLIST_REMOVE(ev->timer_events, te);
+ tevent_debug(te->event_ctx, TEVENT_DEBUG_TRACE,
+ "Running timer event %p \"%s\"\n",
+ te, te->handler_name);
+
/*
* If the timed event was registered for a zero current_time,
* then we pass a zero timeval here too! To avoid the
@@ -265,3 +352,4 @@ struct timeval tevent_common_loop_timer_delay(struct tevent_context *ev)
return tevent_timeval_zero();
}
+
diff --git a/ctdb/lib/tevent/tevent_wakeup.c b/ctdb/lib/tevent/tevent_wakeup.c
index d7cac06afba..82c3942ba8e 100644
--- a/ctdb/lib/tevent/tevent_wakeup.c
+++ b/ctdb/lib/tevent/tevent_wakeup.c
@@ -67,3 +67,4 @@ bool tevent_wakeup_recv(struct tevent_req *req)
return false;
}
+
diff --git a/ctdb/lib/tevent/wscript b/ctdb/lib/tevent/wscript
new file mode 100755
index 00000000000..02bddb80d86
--- /dev/null
+++ b/ctdb/lib/tevent/wscript
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+
+APPNAME = 'tevent'
+VERSION = '0.9.18'
+
+blddir = 'bin'
+
+import sys, os
+
+# find the buildtools directory
+srcdir = '.'
+while not os.path.exists(srcdir+'/buildtools') and len(srcdir.split('/')) < 5:
+ srcdir = '../' + srcdir
+sys.path.insert(0, srcdir + '/buildtools/wafsamba')
+
+import wafsamba, samba_dist, Options, Logs
+
+samba_dist.DIST_DIRS('lib/tevent:. lib/replace:lib/replace lib/talloc:lib/talloc buildtools:buildtools')
+
+def set_options(opt):
+ opt.BUILTIN_DEFAULT('replace')
+ opt.PRIVATE_EXTENSION_DEFAULT('tevent', noextension='tevent')
+ opt.RECURSE('lib/replace')
+ opt.RECURSE('lib/talloc')
+ if opt.IN_LAUNCH_DIR():
+ opt.add_option('--disable-python',
+ help=("disable the pytevent module"),
+ action="store_true", dest='disable_python', default=False)
+
+
+def configure(conf):
+ conf.RECURSE('lib/replace')
+ conf.RECURSE('lib/talloc')
+
+ conf.env.standalone_tevent = conf.IN_LAUNCH_DIR()
+
+ if not conf.env.standalone_tevent:
+ if conf.CHECK_BUNDLED_SYSTEM_PKG('tevent', minversion=VERSION,
+ onlyif='talloc', implied_deps='replace talloc'):
+ conf.define('USING_SYSTEM_TEVENT', 1)
+ if conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytevent', 'tevent', minversion=VERSION):
+ conf.define('USING_SYSTEM_PYTEVENT', 1)
+
+ if conf.CHECK_FUNCS('epoll_create', headers='sys/epoll.h'):
+ conf.DEFINE('HAVE_EPOLL', 1)
+
+ tevent_num_signals = 64
+ v = conf.CHECK_VALUEOF('NSIG', headers='signal.h')
+ if v is not None:
+ tevent_num_signals = max(tevent_num_signals, v)
+ v = conf.CHECK_VALUEOF('_NSIG', headers='signal.h')
+ if v is not None:
+ tevent_num_signals = max(tevent_num_signals, v)
+ v = conf.CHECK_VALUEOF('SIGRTMAX', headers='signal.h')
+ if v is not None:
+ tevent_num_signals = max(tevent_num_signals, v)
+ v = conf.CHECK_VALUEOF('SIGRTMIN', headers='signal.h')
+ if v is not None:
+ tevent_num_signals = max(tevent_num_signals, v*2)
+
+ if not conf.CONFIG_SET('USING_SYSTEM_TEVENT'):
+ conf.DEFINE('TEVENT_NUM_SIGNALS', tevent_num_signals)
+
+ conf.env.disable_python = getattr(Options.options, 'disable_python', False)
+
+ if not conf.env.disable_python:
+ # also disable if we don't have the python libs installed
+ conf.find_program('python', var='PYTHON')
+ conf.check_tool('python')
+ conf.check_python_version((2,4,2))
+ conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=False)
+ if not conf.env.HAVE_PYTHON_H:
+ Logs.warn('Disabling pytevent as python devel libs not found')
+ conf.env.disable_python = True
+
+ conf.SAMBA_CONFIG_H()
+
+ conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS()
+
+def build(bld):
+ bld.RECURSE('lib/replace')
+ bld.RECURSE('lib/talloc')
+
+ SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c
+ tevent_queue.c tevent_req.c tevent_select.c
+ tevent_poll.c
+ tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c'''
+
+ if bld.CONFIG_SET('HAVE_EPOLL'):
+ SRC += ' tevent_epoll.c'
+
+ if bld.env.standalone_tevent:
+ bld.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig'
+ private_library = False
+ else:
+ private_library = True
+
+ if not bld.CONFIG_SET('USING_SYSTEM_TEVENT'):
+ bld.SAMBA_LIBRARY('tevent',
+ SRC,
+ deps='replace talloc',
+ enabled= not bld.CONFIG_SET('USING_SYSTEM_TEVENT'),
+ includes='.',
+ abi_directory='ABI',
+ abi_match='tevent_* _tevent_*',
+ vnum=VERSION,
+ public_headers='tevent.h',
+ public_headers_install=not private_library,
+ pc_files='tevent.pc',
+ private_library=private_library)
+
+ if not bld.CONFIG_SET('USING_SYSTEM_PYTEVENT') and not bld.env.disable_python:
+ bld.SAMBA_PYTHON('pytevent',
+ 'pytevent.c',
+ deps='tevent',
+ realname='_tevent.so',
+ cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
+ # install out various python scripts for use by make test
+ bld.SAMBA_SCRIPT('tevent_python',
+ pattern='tevent.py',
+ installdir='python')
+
+ bld.INSTALL_WILDCARD('${PYTHONARCHDIR}', 'tevent.py', flat=False)
+
+
+def test(ctx):
+ '''test tevent'''
+ print("The tevent testsuite is part of smbtorture in samba4")
+
+
+def dist():
+ '''makes a tarball for distribution'''
+ samba_dist.dist()
+
+def reconfigure(ctx):
+ '''reconfigure if config scripts have changed'''
+ import samba_utils
+ samba_utils.reconfigure(ctx)