diff options
author | Amitay Isaacs <amitay@gmail.com> | 2013-05-29 14:12:14 +1000 |
---|---|---|
committer | Amitay Isaacs <amitay@gmail.com> | 2013-05-29 17:47:16 +1000 |
commit | 2afa275a683d31ebf3b697821999939df99cdd8d (patch) | |
tree | d8460991cbfbceda9ec90d1ba52191e00d109150 /ctdb/lib | |
parent | 4c1dc871b9ebdb9a83ab7b4714d89e451ea0783a (diff) | |
download | samba-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')
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) |