mirror of
https://github.com/samba-team/samba.git
synced 2025-03-10 12:58:35 +03:00
tevent: Sync to tevent 0.9.18 from upstream
(This used to be ctdb commit 82d61f77c01df0fbb42743593937b175ce22a445)
This commit is contained in:
parent
4c1dc871b9
commit
2afa275a68
73
ctdb/lib/tevent/ABI/tevent-0.9.10.sigs
Normal file
73
ctdb/lib/tevent/ABI/tevent-0.9.10.sigs
Normal file
@ -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)
|
73
ctdb/lib/tevent/ABI/tevent-0.9.11.sigs
Normal file
73
ctdb/lib/tevent/ABI/tevent-0.9.11.sigs
Normal file
@ -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)
|
74
ctdb/lib/tevent/ABI/tevent-0.9.12.sigs
Normal file
74
ctdb/lib/tevent/ABI/tevent-0.9.12.sigs
Normal file
@ -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)
|
75
ctdb/lib/tevent/ABI/tevent-0.9.13.sigs
Normal file
75
ctdb/lib/tevent/ABI/tevent-0.9.13.sigs
Normal file
@ -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)
|
78
ctdb/lib/tevent/ABI/tevent-0.9.14.sigs
Normal file
78
ctdb/lib/tevent/ABI/tevent-0.9.14.sigs
Normal file
@ -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)
|
82
ctdb/lib/tevent/ABI/tevent-0.9.17.sigs
Normal file
82
ctdb/lib/tevent/ABI/tevent-0.9.17.sigs
Normal file
@ -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)
|
83
ctdb/lib/tevent/ABI/tevent-0.9.18.sigs
Normal file
83
ctdb/lib/tevent/ABI/tevent-0.9.18.sigs
Normal file
@ -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)
|
73
ctdb/lib/tevent/ABI/tevent-0.9.9.sigs
Normal file
73
ctdb/lib/tevent/ABI/tevent-0.9.9.sigs
Normal file
@ -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)
|
62
ctdb/lib/tevent/bindings.py
Normal file
62
ctdb/lib/tevent/bindings.py
Normal file
@ -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))
|
@ -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
|
||||
|
766
ctdb/lib/tevent/pytevent.c
Normal file
766
ctdb/lib/tevent/pytevent.c
Normal file
@ -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));
|
||||
}
|
48
ctdb/lib/tevent/release-script.sh
Executable file
48
ctdb/lib/tevent/release-script.sh
Executable file
@ -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}
|
@ -4,6 +4,7 @@
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
const struct tevent_ops *ops;
|
||||
|
||||
tevent_backend_init();
|
||||
|
||||
if (name == NULL) {
|
||||
name = tevent_default_backend;
|
||||
}
|
||||
if (name == NULL) {
|
||||
name = "standard";
|
||||
}
|
||||
|
||||
for (e=tevent_backends;e;e=e->next) {
|
||||
if (strcmp(name, e->name) == 0) {
|
||||
return tevent_context_init_ops(mem_ctx, e->ops, NULL);
|
||||
}
|
||||
}
|
||||
ops = tevent_find_ops_byname(name);
|
||||
if (ops == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tevent_context_init_ops(mem_ctx, ops, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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/
|
||||
|
29
ctdb/lib/tevent/tevent.py
Normal file
29
ctdb/lib/tevent/tevent.py
Normal file
@ -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,
|
||||
)
|
@ -4,7 +4,8 @@
|
||||
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));
|
||||
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,7 +220,7 @@ 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
|
||||
@ -105,6 +230,8 @@ static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_
|
||||
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);
|
||||
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");
|
||||
if (mpx_fde != NULL) {
|
||||
event.events |= epoll_map_flags(mpx_fde->flags);
|
||||
}
|
||||
event.data.ptr = fde;
|
||||
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) {
|
||||
@ -242,6 +593,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
|
||||
*/
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -289,27 +672,66 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
|
||||
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) {
|
||||
epoll_ev = talloc_get_type(ev->additional_data,
|
||||
if (ev == NULL) {
|
||||
return tevent_common_fd_destructor(fde);
|
||||
}
|
||||
|
||||
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,9 +883,14 @@ 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);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -419,6 +901,7 @@ 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 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,
|
||||
|
@ -136,3 +136,4 @@ bool tevent_common_loop_immediate(struct tevent_context *ev)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -33,41 +33,196 @@ struct poll_event_context {
|
||||
/* a pointer back to the generic 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;
|
||||
|
||||
poll_ev->num_fds -= 1;
|
||||
DLIST_REMOVE((*listp), fde);
|
||||
goto done;
|
||||
}
|
||||
|
||||
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,60 +300,34 @@ 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pfd = &poll_ev->fds[poll_ev->num_fds];
|
||||
|
||||
pfd->fd = fd;
|
||||
|
||||
pfd->events = 0;
|
||||
pfd->revents = 0;
|
||||
|
||||
if (flags & TEVENT_FD_READ) {
|
||||
pfd->events |= (POLLIN|POLLHUP);
|
||||
}
|
||||
if (flags & TEVENT_FD_WRITE) {
|
||||
pfd->events |= (POLLOUT);
|
||||
}
|
||||
|
||||
fde->additional_flags = poll_ev->num_fds;
|
||||
poll_ev->fd_events[poll_ev->num_fds] = fde;
|
||||
|
||||
poll_ev->num_fds += 1;
|
||||
|
||||
talloc_set_destructor(fde, poll_event_fd_destructor);
|
||||
tevent_poll_event_add_fd_internal(ev, fde);
|
||||
poll_event_wake_pollthread(poll_ev);
|
||||
|
||||
/*
|
||||
* poll_event_loop_poll will take care of the rest in
|
||||
* poll_event_setup_fresh
|
||||
*/
|
||||
return fde;
|
||||
}
|
||||
|
||||
@ -163,10 +336,46 @@ static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
|
||||
*/
|
||||
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);
|
||||
struct tevent_context *ev = fde->event_ctx;
|
||||
struct poll_event_context *poll_ev;
|
||||
uint64_t idx = fde->additional_flags;
|
||||
uint16_t pollflags = 0;
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pollflags = 0;
|
||||
|
||||
if (flags & TEVENT_FD_READ) {
|
||||
pollflags |= (POLLIN|POLLHUP);
|
||||
@ -174,10 +383,110 @@ static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
|
||||
if (flags & TEVENT_FD_WRITE) {
|
||||
pollflags |= (POLLOUT);
|
||||
}
|
||||
|
||||
poll_ev->fds[idx].events = pollflags;
|
||||
|
||||
fde->flags = flags;
|
||||
poll_event_wake_pollthread(poll_ev);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (poll_ev->deleted) {
|
||||
unsigned first_fd = (poll_ev->signal_fd != -1) ? 1 : 0;
|
||||
unsigned i;
|
||||
|
||||
for (i=first_fd; i < poll_ev->num_fds;) {
|
||||
fde = poll_ev->fdes[i];
|
||||
if (fde != NULL) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (poll_ev->fresh == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
num_fresh = 0;
|
||||
for (fde = poll_ev->fresh; fde; fde = fde->next) {
|
||||
num_fresh += 1;
|
||||
}
|
||||
num_fds = poll_ev->num_fds + num_fresh;
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
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,25 +512,20 @@ static int poll_event_loop_poll(struct tevent_context *ev,
|
||||
timeout += (tvalp->tv_usec + 999) / 1000;
|
||||
}
|
||||
|
||||
tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
|
||||
pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
|
||||
tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
|
||||
poll_event_drain_signal_fd(poll_ev);
|
||||
|
||||
if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
|
||||
tevent_common_check_signal(ev);
|
||||
return 0;
|
||||
if (!poll_event_setup_fresh(ev, poll_ev)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
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 && poll_errno == EINTR && ev->signal_events) {
|
||||
tevent_common_check_signal(ev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pollrtn == 0 && tvalp) {
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
@ -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,
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
@ -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,564 +26,206 @@
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
init the epoll fd
|
||||
*/
|
||||
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)
|
||||
{
|
||||
struct tevent_fd *fde;
|
||||
|
||||
if (std_ev->pid == getpid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
for (fde=std_ev->ev->fd_events;fde;fde=fde->next) {
|
||||
epoll_add_event(std_ev, fde);
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
change the epoll event to the given fd_event
|
||||
*/
|
||||
static void epoll_mod_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;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
/* 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 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
|
||||
*/
|
||||
epoll_del_event(std_ev, fde);
|
||||
return;
|
||||
}
|
||||
|
||||
/* there's no epoll_event attached to the fde */
|
||||
if (want_read || (want_write && !got_error)) {
|
||||
epoll_add_event(std_ev, fde);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
event loop handling using epoll
|
||||
*/
|
||||
static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp)
|
||||
{
|
||||
int ret, i;
|
||||
#define MAXEVENTS 1
|
||||
struct epoll_event events[MAXEVENTS];
|
||||
int timeout = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#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.
|
||||
*/
|
||||
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;
|
||||
|
||||
epoll_init_ctx(std_ev);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* to mark the ev->maxfd invalid
|
||||
* this means we need to recalculate it
|
||||
*/
|
||||
#define EVENT_INVALID_MAXFD (-1)
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
tval = tevent_common_loop_timer_delay(ev);
|
||||
if (tevent_timeval_is_zero(&tval)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
epoll_check_reopen(std_ev);
|
||||
|
||||
if (epoll_event_loop(std_ev, &tval) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return std_event_loop_select(std_ev, &tval);
|
||||
}
|
||||
static int std_event_context_init(struct tevent_context *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,
|
||||
};
|
||||
|
||||
/*
|
||||
If this function gets called. epoll failed at runtime.
|
||||
Move us to using poll instead. If we return false here,
|
||||
caller should abort().
|
||||
*/
|
||||
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;
|
||||
|
||||
glue->fallback_replay = replay;
|
||||
|
||||
/* First switch all the ops to poll. */
|
||||
glue->epoll_ops = NULL;
|
||||
|
||||
/*
|
||||
* Set custom_ops the same as poll.
|
||||
*/
|
||||
*glue->glue_ops = *glue->poll_ops;
|
||||
glue->glue_ops->context_init = std_event_context_init;
|
||||
|
||||
/* Next initialize the poll backend. */
|
||||
ret = glue->poll_ops->context_init(ev);
|
||||
if (ret != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* Remove from the ev->fd_events list. */
|
||||
DLIST_REMOVE(ev->fd_events, fde);
|
||||
|
||||
/* Re-add this event as a poll backend event. */
|
||||
tevent_poll_event_add_fd_internal(ev, fde);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int std_event_loop_once(struct tevent_context *ev, const char *location)
|
||||
{
|
||||
void *glue_ptr = talloc_parent(ev->ops);
|
||||
struct std_event_glue *glue =
|
||||
talloc_get_type_abort(glue_ptr,
|
||||
struct std_event_glue);
|
||||
int ret;
|
||||
|
||||
ret = glue->epoll_ops->loop_once(ev, location);
|
||||
if (glue->epoll_ops != NULL) {
|
||||
/* No fallback */
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!glue->fallback_replay) {
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
return glue->poll_ops->loop_once(ev, location);
|
||||
}
|
||||
|
||||
static int std_event_loop_wait(struct tevent_context *ev, const char *location)
|
||||
{
|
||||
void *glue_ptr = talloc_parent(ev->ops);
|
||||
struct std_event_glue *glue =
|
||||
talloc_get_type_abort(glue_ptr,
|
||||
struct std_event_glue);
|
||||
int ret;
|
||||
|
||||
ret = glue->epoll_ops->loop_wait(ev, location);
|
||||
if (glue->epoll_ops != NULL) {
|
||||
/* No fallback */
|
||||
return ret;
|
||||
}
|
||||
|
||||
return glue->poll_ops->loop_wait(ev, location);
|
||||
}
|
||||
/*
|
||||
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_glue *glue;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If this is the first initialization
|
||||
* we need to set up the allocated ops
|
||||
* pointers.
|
||||
*/
|
||||
|
||||
if (ev->ops == &std_event_ops) {
|
||||
glue = talloc_zero(ev, struct std_event_glue);
|
||||
if (glue == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
glue->epoll_ops = tevent_find_ops_byname("epoll");
|
||||
|
||||
glue->poll_ops = tevent_find_ops_byname("poll");
|
||||
if (glue->poll_ops == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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 (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;
|
||||
}
|
||||
#ifdef HAVE_EPOLL
|
||||
if (!tevent_epoll_set_panic_fallback(ev, std_fallback_to_poll)) {
|
||||
TALLOC_FREE(ev->additional_data);
|
||||
goto fallback;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
fallback:
|
||||
glue->epoll_ops = NULL;
|
||||
|
||||
/*
|
||||
* Set custom_ops the same as poll.
|
||||
*/
|
||||
*glue->glue_ops = *glue->poll_ops;
|
||||
glue->glue_ops->context_init = std_event_context_init;
|
||||
|
||||
return glue->poll_ops->context_init(ev);
|
||||
}
|
||||
|
||||
_PRIVATE_ bool tevent_standard_init(void)
|
||||
{
|
||||
|
@ -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,
|
||||
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)
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -67,3 +67,4 @@ bool tevent_wakeup_recv(struct tevent_req *req)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
138
ctdb/lib/tevent/wscript
Executable file
138
ctdb/lib/tevent/wscript
Executable file
@ -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)
|
Loading…
x
Reference in New Issue
Block a user