From fe93d0afcc1cede32ac9569abd8669ed011b1b8c Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Khan Date: Wed, 23 Oct 2024 09:57:03 -0700 Subject: [PATCH 01/72] Update CMake to 3.9 (#686) --- CMakeLists.txt | 6 +---- README.md | 2 +- source/future.c | 67 ++++++++++--------------------------------------- 3 files changed, 15 insertions(+), 60 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ad560ad4a..c0f030b98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,7 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.9) project(aws-c-io C) -if (POLICY CMP0069) - cmake_policy(SET CMP0069 NEW) # Enable LTO/IPO if available in the compiler, see AwsCFlags -endif() - if (DEFINED CMAKE_PREFIX_PATH) file(TO_CMAKE_PATH "${CMAKE_PREFIX_PATH}" CMAKE_PREFIX_PATH) endif() diff --git a/README.md b/README.md index c922bb306..1441d4aac 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This library is licensed under the Apache 2.0 License. ### Building -CMake 3.1+ is required to build. +CMake 3.9+ is required to build. `` must be an absolute path in the following instructions. diff --git a/source/future.c b/source/future.c index 96c88ef6a..47af607ce 100644 --- a/source/future.c +++ b/source/future.c @@ -56,6 +56,15 @@ struct aws_future_impl { }; static void s_future_impl_result_dtor(struct aws_future_impl *future, void *result_addr) { + +/* + * On ARM machines, the compiler complains about the array bounds warning for aws_future_bool, even though + * aws_future_bool will never go into any destroy or release branch. Disable the warning since it's a false positive. + */ +#ifndef _MSC_VER +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Warray-bounds" +#endif switch (future->type) { case AWS_FUTURE_T_BY_VALUE_WITH_CLEAN_UP: { future->result_dtor.clean_up(result_addr); @@ -79,6 +88,9 @@ static void s_future_impl_result_dtor(struct aws_future_impl *future, void *resu default: break; } +#ifndef _MSC_VER +# pragma GCC diagnostic pop +#endif } static void s_future_impl_destroy(void *user_data) { @@ -472,60 +484,7 @@ bool aws_future_impl_wait(const struct aws_future_impl *future, uint64_t timeout return is_done; } -// AWS_FUTURE_T_BY_VALUE_IMPLEMENTATION(aws_future_bool, bool) -struct aws_future_bool *aws_future_bool_new(struct aws_allocator *alloc) { - return (struct aws_future_bool *)aws_future_impl_new_by_value(alloc, sizeof(_Bool)); -} -void aws_future_bool_set_result(struct aws_future_bool *future, _Bool result) { - aws_future_impl_set_result_by_move((struct aws_future_impl *)future, &result); -} -_Bool aws_future_bool_get_result(const struct aws_future_bool *future) { - return *(_Bool *)aws_future_impl_get_result_address((const struct aws_future_impl *)future); -} -struct aws_future_bool *aws_future_bool_acquire(struct aws_future_bool *future) { - return (struct aws_future_bool *)aws_future_impl_acquire((struct aws_future_impl *)future); -} -struct aws_future_bool *aws_future_bool_release(struct aws_future_bool *future) { - return (struct aws_future_bool *)aws_future_impl_release((struct aws_future_impl *)future); -} -void aws_future_bool_set_error(struct aws_future_bool *future, int error_code) { - aws_future_impl_set_error((struct aws_future_impl *)future, error_code); -} -_Bool aws_future_bool_is_done(const struct aws_future_bool *future) { - return aws_future_impl_is_done((const struct aws_future_impl *)future); -} -int aws_future_bool_get_error(const struct aws_future_bool *future) { - return aws_future_impl_get_error((const struct aws_future_impl *)future); -} -void aws_future_bool_register_callback( - struct aws_future_bool *future, - aws_future_callback_fn *on_done, - void *user_data) { - aws_future_impl_register_callback((struct aws_future_impl *)future, on_done, user_data); -} -_Bool aws_future_bool_register_callback_if_not_done( - struct aws_future_bool *future, - aws_future_callback_fn *on_done, - void *user_data) { - return aws_future_impl_register_callback_if_not_done((struct aws_future_impl *)future, on_done, user_data); -} -void aws_future_bool_register_event_loop_callback( - struct aws_future_bool *future, - struct aws_event_loop *event_loop, - aws_future_callback_fn *on_done, - void *user_data) { - aws_future_impl_register_event_loop_callback((struct aws_future_impl *)future, event_loop, on_done, user_data); -} -void aws_future_bool_register_channel_callback( - struct aws_future_bool *future, - struct aws_channel *channel, - aws_future_callback_fn *on_done, - void *user_data) { - aws_future_impl_register_channel_callback((struct aws_future_impl *)future, channel, on_done, user_data); -} -_Bool aws_future_bool_wait(struct aws_future_bool *future, uint64_t timeout_ns) { - return aws_future_impl_wait((struct aws_future_impl *)future, timeout_ns); -} +AWS_FUTURE_T_BY_VALUE_IMPLEMENTATION(aws_future_bool, bool) AWS_FUTURE_T_BY_VALUE_IMPLEMENTATION(aws_future_size, size_t) From 7b7437b24d9fd8f5441e65e7f9dc0308fed7fa4e Mon Sep 17 00:00:00 2001 From: Ashish Dhingra <67916761+ashishdhingra@users.noreply.github.com> Date: Mon, 28 Oct 2024 10:45:54 -0700 Subject: [PATCH 02/72] chore: Modified bug issue template to add checkbox to report potential regression. (#671) Co-authored-by: Joseph Klix --- .github/ISSUE_TEMPLATE/bug-report.yml | 8 +++++ .../workflows/issue-regression-labeler.yml | 32 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 .github/workflows/issue-regression-labeler.yml diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 84f5c6c79..7ccddd01b 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -12,6 +12,14 @@ body: description: What is the problem? A clear and concise description of the bug. validations: required: true + - type: checkboxes + id: regression + attributes: + label: Regression Issue + description: What is a regression? If it worked in a previous version but doesn't in the latest version, it's considered a regression. In this case, please provide specific version number in the report. + options: + - label: Select this option if this issue appears to be a regression. + required: false - type: textarea id: expected attributes: diff --git a/.github/workflows/issue-regression-labeler.yml b/.github/workflows/issue-regression-labeler.yml new file mode 100644 index 000000000..bd000719d --- /dev/null +++ b/.github/workflows/issue-regression-labeler.yml @@ -0,0 +1,32 @@ +# Apply potential regression label on issues +name: issue-regression-label +on: + issues: + types: [opened, edited] +jobs: + add-regression-label: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Fetch template body + id: check_regression + uses: actions/github-script@v7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TEMPLATE_BODY: ${{ github.event.issue.body }} + with: + script: | + const regressionPattern = /\[x\] Select this option if this issue appears to be a regression\./i; + const template = `${process.env.TEMPLATE_BODY}` + const match = regressionPattern.test(template); + core.setOutput('is_regression', match); + - name: Manage regression label + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if [ "${{ steps.check_regression.outputs.is_regression }}" == "true" ]; then + gh issue edit ${{ github.event.issue.number }} --add-label "potential-regression" -R ${{ github.repository }} + else + gh issue edit ${{ github.event.issue.number }} --remove-label "potential-regression" -R ${{ github.repository }} + fi From e247ef89cdf170cadcb4c665fb0146e82cd6e135 Mon Sep 17 00:00:00 2001 From: Dmitriy Musatkin <63878209+DmitriyMusatkin@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:57:18 -0700 Subject: [PATCH 03/72] Fix s2n cleanup (#687) --- source/s2n/s2n_tls_channel_handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/s2n/s2n_tls_channel_handler.c b/source/s2n/s2n_tls_channel_handler.c index 018e6c069..e9560608e 100644 --- a/source/s2n/s2n_tls_channel_handler.c +++ b/source/s2n/s2n_tls_channel_handler.c @@ -255,7 +255,7 @@ void aws_tls_init_static_state(struct aws_allocator *alloc) { void aws_tls_clean_up_static_state(void) { /* only clean up s2n if we were the ones that initialized it */ if (!s_s2n_initialized_externally) { - s2n_cleanup(); + s2n_cleanup_final(); } } From 9d973027737bba6b404dd0b7aa0a279f5d3f7eab Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 30 Oct 2024 16:28:48 -0700 Subject: [PATCH 04/72] Checkpoint --- include/aws/io/event_loop.h | 384 +---------------------- include/aws/io/private/event_loop_impl.h | 337 ++++++++++++++++++++ 2 files changed, 351 insertions(+), 370 deletions(-) create mode 100644 include/aws/io/private/event_loop_impl.h diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index a3b552d6e..4c27160a5 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -6,287 +6,34 @@ * SPDX-License-Identifier: Apache-2.0. */ -#include -#include -#include - #include AWS_PUSH_SANE_WARNING_LEVEL -enum aws_io_event_type { - AWS_IO_EVENT_TYPE_READABLE = 1, - AWS_IO_EVENT_TYPE_WRITABLE = 2, - AWS_IO_EVENT_TYPE_REMOTE_HANG_UP = 4, - AWS_IO_EVENT_TYPE_CLOSED = 8, - AWS_IO_EVENT_TYPE_ERROR = 16, -}; - struct aws_event_loop; +struct aws_event_loop_group; struct aws_task; -struct aws_thread_options; -#if AWS_USE_IO_COMPLETION_PORTS +typedef void(aws_elg_shutdown_completion_callback)(void *); -struct aws_overlapped; - -typedef void(aws_event_loop_on_completion_fn)( - struct aws_event_loop *event_loop, - struct aws_overlapped *overlapped, - int status_code, - size_t num_bytes_transferred); - -/** - * The aws_win32_OVERLAPPED struct is layout-compatible with OVERLAPPED as defined in . It is used - * here to avoid pulling in a dependency on which would also bring along a lot of bad macros, such - * as redefinitions of GetMessage and GetObject. Note that the OVERLAPPED struct layout in the Windows SDK can - * never be altered without breaking binary compatibility for every existing third-party executable, so there - * is no need to worry about keeping this definition in sync. - */ -struct aws_win32_OVERLAPPED { - uintptr_t Internal; - uintptr_t InternalHigh; - union { - struct { - uint32_t Offset; - uint32_t OffsetHigh; - } s; - void *Pointer; - } u; - void *hEvent; +struct aws_event_loop_group_shutdown_options { + aws_elg_shutdown_completion_callback *shutdown_callback_fn; + void *shutdown_callback_user_data; }; -/** - * Use aws_overlapped when a handle connected to the event loop needs an OVERLAPPED struct. - * OVERLAPPED structs are needed to make OS-level async I/O calls. - * When the I/O completes, the assigned aws_event_loop_on_completion_fn is called from the event_loop's thread. - * While the I/O is pending, it is not safe to modify or delete aws_overlapped. - * Call aws_overlapped_init() before first use. If the aws_overlapped will be used multiple times, call - * aws_overlapped_reset() or aws_overlapped_init() between uses. - */ -struct aws_overlapped { - struct aws_win32_OVERLAPPED overlapped; - aws_event_loop_on_completion_fn *on_completion; - void *user_data; -}; - -#else /* !AWS_USE_IO_COMPLETION_PORTS */ - -typedef void(aws_event_loop_on_event_fn)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - void *user_data); - -#endif /* AWS_USE_IO_COMPLETION_PORTS */ - -struct aws_event_loop_vtable { - void (*destroy)(struct aws_event_loop *event_loop); - int (*run)(struct aws_event_loop *event_loop); - int (*stop)(struct aws_event_loop *event_loop); - int (*wait_for_stop_completion)(struct aws_event_loop *event_loop); - void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); - void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); - void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); -#if AWS_USE_IO_COMPLETION_PORTS - int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); -#else - int (*subscribe_to_io_events)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - aws_event_loop_on_event_fn *on_event, - void *user_data); -#endif - int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); - void (*free_io_event_resources)(void *user_data); - bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); +struct aws_event_loop_group_pin_options { + uint16_t cpu_group; }; -struct aws_event_loop { - struct aws_event_loop_vtable *vtable; - struct aws_allocator *alloc; - aws_io_clock_fn *clock; - struct aws_hash_table local_data; - struct aws_atomic_var current_load_factor; - uint64_t latest_tick_start; - size_t current_tick_latency_sum; - struct aws_atomic_var next_flush_time; - void *impl_data; -}; - -struct aws_event_loop_local_object; -typedef void(aws_event_loop_on_local_object_removed_fn)(struct aws_event_loop_local_object *); - -struct aws_event_loop_local_object { - const void *key; - void *object; - aws_event_loop_on_local_object_removed_fn *on_object_removed; -}; - -struct aws_event_loop_options { - aws_io_clock_fn *clock; - struct aws_thread_options *thread_options; -}; - -typedef struct aws_event_loop *(aws_new_event_loop_fn)( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options, - void *new_loop_user_data); - -struct aws_event_loop_group { - struct aws_allocator *allocator; - struct aws_array_list event_loops; - struct aws_ref_count ref_count; - struct aws_shutdown_callback_options shutdown_options; +struct aws_event_loop_group_options { + uint16_t loop_count; + aws_io_clock_fn *clock_override; + struct aws_shutdown_callback_options *shutdown_options; + struct aws_event_loop_group_pin_options *pin_options; }; AWS_EXTERN_C_BEGIN -#ifdef AWS_USE_IO_COMPLETION_PORTS -/** - * Prepares aws_overlapped for use, and sets a function to call when the overlapped operation completes. - */ -AWS_IO_API -void aws_overlapped_init( - struct aws_overlapped *overlapped, - aws_event_loop_on_completion_fn *on_completion, - void *user_data); - -/** - * Prepares aws_overlapped for re-use without changing the assigned aws_event_loop_on_completion_fn. - * Call aws_overlapped_init(), instead of aws_overlapped_reset(), to change the aws_event_loop_on_completion_fn. - */ -AWS_IO_API -void aws_overlapped_reset(struct aws_overlapped *overlapped); - -/** - * Casts an aws_overlapped pointer for use as a LPOVERLAPPED parameter to Windows API functions - */ -AWS_IO_API -struct _OVERLAPPED *aws_overlapped_to_windows_overlapped(struct aws_overlapped *overlapped); -#endif /* AWS_USE_IO_COMPLETION_PORTS */ - -/** - * Creates an instance of the default event loop implementation for the current architecture and operating system. - */ -AWS_IO_API -struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock); - -/** - * Creates an instance of the default event loop implementation for the current architecture and operating system using - * extendable options. - */ -AWS_IO_API -struct aws_event_loop *aws_event_loop_new_default_with_options( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options); - -/** - * Invokes the destroy() fn for the event loop implementation. - * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. - * If you do not want this function to block, call aws_event_loop_stop() manually first. - * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads - * must ensure their API calls to the event loop happen-before the call to destroy. - */ -AWS_IO_API -void aws_event_loop_destroy(struct aws_event_loop *event_loop); - -/** - * Initializes common event-loop data structures. - * This is only called from the *new() function of event loop implementations. - */ -AWS_IO_API -int aws_event_loop_init_base(struct aws_event_loop *event_loop, struct aws_allocator *alloc, aws_io_clock_fn *clock); - -/** - * Common cleanup code for all implementations. - * This is only called from the *destroy() function of event loop implementations. - */ -AWS_IO_API -void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); - -/** - * Fetches an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to - * by key. This function is not thread safe and should be called inside the event-loop's thread. - */ -AWS_IO_API -int aws_event_loop_fetch_local_object( - struct aws_event_loop *event_loop, - void *key, - struct aws_event_loop_local_object *obj); - -/** - * Puts an item object the event-loop's data store. Key will be taken as the memory address of the memory pointed to by - * key. The lifetime of item must live until remove or a put item overrides it. This function is not thread safe and - * should be called inside the event-loop's thread. - */ -AWS_IO_API -int aws_event_loop_put_local_object(struct aws_event_loop *event_loop, struct aws_event_loop_local_object *obj); - -/** - * Removes an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to - * by key. If removed_item is not null, the removed item will be moved to it if it exists. Otherwise, the default - * deallocation strategy will be used. This function is not thread safe and should be called inside the event-loop's - * thread. - */ -AWS_IO_API -int aws_event_loop_remove_local_object( - struct aws_event_loop *event_loop, - void *key, - struct aws_event_loop_local_object *removed_obj); - -/** - * Triggers the running of the event loop. This function must not block. The event loop is not active until this - * function is invoked. This function can be called again on an event loop after calling aws_event_loop_stop() and - * aws_event_loop_wait_for_stop_completion(). - */ -AWS_IO_API -int aws_event_loop_run(struct aws_event_loop *event_loop); - -/** - * Triggers the event loop to stop, but does not wait for the loop to stop completely. - * This function may be called from outside or inside the event loop thread. It is safe to call multiple times. - * This function is called from destroy(). - * - * If you do not call destroy(), an event loop can be run again by calling stop(), wait_for_stop_completion(), run(). - */ -AWS_IO_API -int aws_event_loop_stop(struct aws_event_loop *event_loop); - -/** - * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the - * event-loop load balancer to take into account load when vending another event-loop to a caller. - * - * Call this function at the beginning of your event-loop tick: after wake-up, but before processing any IO or tasks. - */ -AWS_IO_API -void aws_event_loop_register_tick_start(struct aws_event_loop *event_loop); - -/** - * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the - * event-loop load balancer to take into account load when vending another event-loop to a caller. - * - * Call this function at the end of your event-loop tick: after processing IO and tasks. - */ -AWS_IO_API -void aws_event_loop_register_tick_end(struct aws_event_loop *event_loop); - -/** - * Returns the current load factor (however that may be calculated). If the event-loop is not invoking - * aws_event_loop_register_tick_start() and aws_event_loop_register_tick_end(), this value will always be 0. - */ -AWS_IO_API -size_t aws_event_loop_get_load_factor(struct aws_event_loop *event_loop); - -/** - * Blocks until the event loop stops completely. - * If you want to call aws_event_loop_run() again, you must call this after aws_event_loop_stop(). - * It is not safe to call this function from inside the event loop thread. - */ -AWS_IO_API -int aws_event_loop_wait_for_stop_completion(struct aws_event_loop *event_loop); - /** * The event loop will schedule the task and run it on the event loop thread as soon as possible. * Note that cancelled tasks may execute outside the event loop thread. @@ -320,61 +67,6 @@ void aws_event_loop_schedule_task_future( AWS_IO_API void aws_event_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task); -#if AWS_USE_IO_COMPLETION_PORTS - -/** - * Associates an aws_io_handle with the event loop's I/O Completion Port. - * - * The handle must use aws_overlapped for all async operations requiring an OVERLAPPED struct. - * When the operation completes, the aws_overlapped's completion function will run on the event loop thread. - * Note that completion functions will not be invoked while the event loop is stopped. Users should wait for all async - * operations on connected handles to complete before cleaning up or destroying the event loop. - * - * A handle may only be connected to one event loop in its lifetime. - */ -AWS_IO_API -int aws_event_loop_connect_handle_to_io_completion_port( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle); - -#else /* !AWS_USE_IO_COMPLETION_PORTS */ - -/** - * Subscribes on_event to events on the event-loop for handle. events is a bitwise concatenation of the events that were - * received. The definition for these values can be found in aws_io_event_type. Currently, only - * AWS_IO_EVENT_TYPE_READABLE and AWS_IO_EVENT_TYPE_WRITABLE are honored. You always are registered for error conditions - * and closure. This function may be called from outside or inside the event loop thread. However, the unsubscribe - * function must be called inside the event-loop's thread. - */ -AWS_IO_API -int aws_event_loop_subscribe_to_io_events( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - aws_event_loop_on_event_fn *on_event, - void *user_data); - -#endif /* AWS_USE_IO_COMPLETION_PORTS */ - -/** - * Unsubscribes handle from event-loop notifications. - * This function is not thread safe and should be called inside the event-loop's thread. - * - * NOTE: if you are using io completion ports, this is a risky call. We use it in places, but only when we're certain - * there's no pending events. If you want to use it, it's your job to make sure you don't have pending events before - * calling it. - */ -AWS_IO_API -int aws_event_loop_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struct aws_io_handle *handle); - -/** - * Cleans up resources (user_data) associated with the I/O eventing subsystem for a given handle. This should only - * ever be necessary in the case where you are cleaning up an event loop during shutdown and its thread has already - * been joined. - */ -AWS_IO_API -void aws_event_loop_free_io_event_resources(struct aws_event_loop *event_loop, struct aws_io_handle *handle); - /** * Returns true if the event loop's thread is the same thread that called this function, otherwise false. */ @@ -388,59 +80,11 @@ AWS_IO_API int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_t *time_nanos); /** - * Creates an event loop group, with clock, number of loops to manage, and the function to call for creating a new - * event loop. */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options); - -/** Creates an event loop group, with clock, number of loops to manage, the function to call for creating a new - * event loop, and also pins all loops to hw threads on the same cpu_group (e.g. NUMA nodes). Note: - * If el_count exceeds the number of hw threads in the cpu_group it will be ignored on the assumption that if you - * care about NUMA, you don't want hyper-threads doing your IO and you especially don't want IO on a different node. - */ -AWS_IO_API -struct aws_event_loop_group *aws_event_loop_group_new_pinned_to_cpu_group( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - uint16_t cpu_group, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options); - -/** - * Initializes an event loop group with platform defaults. If max_threads == 0, then the - * loop count will be the number of available processors on the machine / 2 (to exclude hyper-threads). - * Otherwise, max_threads will be the number of event loops in the group. - */ -AWS_IO_API -struct aws_event_loop_group *aws_event_loop_group_new_default( - struct aws_allocator *alloc, - uint16_t max_threads, - const struct aws_shutdown_callback_options *shutdown_options); - -/** Creates an event loop group, with clock, number of loops to manage, the function to call for creating a new - * event loop, and also pins all loops to hw threads on the same cpu_group (e.g. NUMA nodes). Note: - * If el_count exceeds the number of hw threads in the cpu_group it will be clamped to the number of hw threads - * on the assumption that if you care about NUMA, you don't want hyper-threads doing your IO and you especially - * don't want IO on a different node. - * - * If max_threads == 0, then the - * loop count will be the number of available processors in the cpu_group / 2 (to exclude hyper-threads) - */ -AWS_IO_API -struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( - struct aws_allocator *alloc, - uint16_t max_threads, - uint16_t cpu_group, - const struct aws_shutdown_callback_options *shutdown_options); + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options); /** * Increments the reference count on the event loop group, allowing the caller to take a reference to it. diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h new file mode 100644 index 000000000..2ebfc40d4 --- /dev/null +++ b/include/aws/io/private/event_loop_impl.h @@ -0,0 +1,337 @@ +#ifndef AWS_IO_EVENT_LOOP_IMPL_H +#define AWS_IO_EVENT_LOOP_IMPL_H + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include + +#include +#include +#include + +AWS_PUSH_SANE_WARNING_LEVEL + +struct aws_event_loop; +struct aws_overlapped; + +typedef void(aws_event_loop_on_completion_fn)( + struct aws_event_loop *event_loop, + struct aws_overlapped *overlapped, + int status_code, + size_t num_bytes_transferred); + +/** + * The aws_win32_OVERLAPPED struct is layout-compatible with OVERLAPPED as defined in . It is used + * here to avoid pulling in a dependency on which would also bring along a lot of bad macros, such + * as redefinitions of GetMessage and GetObject. Note that the OVERLAPPED struct layout in the Windows SDK can + * never be altered without breaking binary compatibility for every existing third-party executable, so there + * is no need to worry about keeping this definition in sync. + */ +struct aws_win32_OVERLAPPED { + uintptr_t Internal; + uintptr_t InternalHigh; + union { + struct { + uint32_t Offset; + uint32_t OffsetHigh; + } s; + void *Pointer; + } u; + void *hEvent; +}; + +/** + * Use aws_overlapped when a handle connected to the event loop needs an OVERLAPPED struct. + * OVERLAPPED structs are needed to make OS-level async I/O calls. + * When the I/O completes, the assigned aws_event_loop_on_completion_fn is called from the event_loop's thread. + * While the I/O is pending, it is not safe to modify or delete aws_overlapped. + * Call aws_overlapped_init() before first use. If the aws_overlapped will be used multiple times, call + * aws_overlapped_reset() or aws_overlapped_init() between uses. + */ +struct aws_overlapped { + struct aws_win32_OVERLAPPED overlapped; + aws_event_loop_on_completion_fn *on_completion; + void *user_data; +}; + +typedef void(aws_event_loop_on_event_fn)( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + void *user_data); + +enum aws_io_event_type { + AWS_IO_EVENT_TYPE_READABLE = 1, + AWS_IO_EVENT_TYPE_WRITABLE = 2, + AWS_IO_EVENT_TYPE_REMOTE_HANG_UP = 4, + AWS_IO_EVENT_TYPE_CLOSED = 8, + AWS_IO_EVENT_TYPE_ERROR = 16, +}; + +struct aws_event_loop_vtable { + void (*destroy)(struct aws_event_loop *event_loop); + int (*run)(struct aws_event_loop *event_loop); + int (*stop)(struct aws_event_loop *event_loop); + int (*wait_for_stop_completion)(struct aws_event_loop *event_loop); + void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); + void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); + void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); + int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + int (*subscribe_to_io_events)( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + aws_event_loop_on_event_fn *on_event, + void *user_data); + int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + void (*free_io_event_resources)(void *user_data); + bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); +}; + + +struct aws_event_loop { + struct aws_event_loop_vtable *vtable; + struct aws_allocator *alloc; + aws_io_clock_fn *clock; + struct aws_hash_table local_data; + struct aws_atomic_var current_load_factor; + uint64_t latest_tick_start; + size_t current_tick_latency_sum; + struct aws_atomic_var next_flush_time; + void *impl_data; +}; + +struct aws_event_loop_local_object; +typedef void(aws_event_loop_on_local_object_removed_fn)(struct aws_event_loop_local_object *); + +struct aws_event_loop_local_object { + const void *key; + void *object; + aws_event_loop_on_local_object_removed_fn *on_object_removed; +}; + +struct aws_event_loop_options { + aws_io_clock_fn *clock; + struct aws_thread_options *thread_options; +}; + +typedef struct aws_event_loop *(aws_new_event_loop_fn)( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options, + void *new_loop_user_data); + +struct aws_event_loop_group { + struct aws_allocator *allocator; + struct aws_array_list event_loops; + struct aws_ref_count ref_count; + struct aws_shutdown_callback_options shutdown_options; +}; + +AWS_EXTERN_C_BEGIN + +#ifdef AWS_USE_IO_COMPLETION_PORTS + +/** + * Prepares aws_overlapped for use, and sets a function to call when the overlapped operation completes. + */ +AWS_IO_API +void aws_overlapped_init( + struct aws_overlapped *overlapped, + aws_event_loop_on_completion_fn *on_completion, + void *user_data); + +/** + * Prepares aws_overlapped for re-use without changing the assigned aws_event_loop_on_completion_fn. + * Call aws_overlapped_init(), instead of aws_overlapped_reset(), to change the aws_event_loop_on_completion_fn. + */ +AWS_IO_API +void aws_overlapped_reset(struct aws_overlapped *overlapped); + +/** + * Casts an aws_overlapped pointer for use as a LPOVERLAPPED parameter to Windows API functions + */ +AWS_IO_API +struct _OVERLAPPED *aws_overlapped_to_windows_overlapped(struct aws_overlapped *overlapped); + +/** + * Associates an aws_io_handle with the event loop's I/O Completion Port. + * + * The handle must use aws_overlapped for all async operations requiring an OVERLAPPED struct. + * When the operation completes, the aws_overlapped's completion function will run on the event loop thread. + * Note that completion functions will not be invoked while the event loop is stopped. Users should wait for all async + * operations on connected handles to complete before cleaning up or destroying the event loop. + * + * A handle may only be connected to one event loop in its lifetime. + */ +AWS_IO_API +int aws_event_loop_connect_handle_to_io_completion_port( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle); + +#else + +/** + * Subscribes on_event to events on the event-loop for handle. events is a bitwise concatenation of the events that were + * received. The definition for these values can be found in aws_io_event_type. Currently, only + * AWS_IO_EVENT_TYPE_READABLE and AWS_IO_EVENT_TYPE_WRITABLE are honored. You always are registered for error conditions + * and closure. This function may be called from outside or inside the event loop thread. However, the unsubscribe + * function must be called inside the event-loop's thread. + */ +AWS_IO_API +int aws_event_loop_subscribe_to_io_events( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + aws_event_loop_on_event_fn *on_event, + void *user_data); + +#endif /* AWS_USE_IO_COMPLETION_PORTS */ + + +/** + * Creates an instance of the default event loop implementation for the current architecture and operating system. + */ +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock); + +/** + * Creates an instance of the default event loop implementation for the current architecture and operating system using + * extendable options. + */ +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_default_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); + +/** + * Invokes the destroy() fn for the event loop implementation. + * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. + * If you do not want this function to block, call aws_event_loop_stop() manually first. + * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads + * must ensure their API calls to the event loop happen-before the call to destroy. + */ +AWS_IO_API +void aws_event_loop_destroy(struct aws_event_loop *event_loop); + +/** + * Initializes common event-loop data structures. + * This is only called from the *new() function of event loop implementations. + */ +AWS_IO_API +int aws_event_loop_init_base(struct aws_event_loop *event_loop, struct aws_allocator *alloc, aws_io_clock_fn *clock); + +/** + * Common cleanup code for all implementations. + * This is only called from the *destroy() function of event loop implementations. + */ +AWS_IO_API +void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); + +/** + * Fetches an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to + * by key. This function is not thread safe and should be called inside the event-loop's thread. + */ +AWS_IO_API +int aws_event_loop_fetch_local_object( + struct aws_event_loop *event_loop, + void *key, + struct aws_event_loop_local_object *obj); + +/** + * Puts an item object the event-loop's data store. Key will be taken as the memory address of the memory pointed to by + * key. The lifetime of item must live until remove or a put item overrides it. This function is not thread safe and + * should be called inside the event-loop's thread. + */ +AWS_IO_API +int aws_event_loop_put_local_object(struct aws_event_loop *event_loop, struct aws_event_loop_local_object *obj); + +/** + * Removes an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to + * by key. If removed_item is not null, the removed item will be moved to it if it exists. Otherwise, the default + * deallocation strategy will be used. This function is not thread safe and should be called inside the event-loop's + * thread. + */ +AWS_IO_API +int aws_event_loop_remove_local_object( + struct aws_event_loop *event_loop, + void *key, + struct aws_event_loop_local_object *removed_obj); + +/** + * Triggers the running of the event loop. This function must not block. The event loop is not active until this + * function is invoked. This function can be called again on an event loop after calling aws_event_loop_stop() and + * aws_event_loop_wait_for_stop_completion(). + */ +AWS_IO_API +int aws_event_loop_run(struct aws_event_loop *event_loop); + +/** + * Triggers the event loop to stop, but does not wait for the loop to stop completely. + * This function may be called from outside or inside the event loop thread. It is safe to call multiple times. + * This function is called from destroy(). + * + * If you do not call destroy(), an event loop can be run again by calling stop(), wait_for_stop_completion(), run(). + */ +AWS_IO_API +int aws_event_loop_stop(struct aws_event_loop *event_loop); + +/** + * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the + * event-loop load balancer to take into account load when vending another event-loop to a caller. + * + * Call this function at the beginning of your event-loop tick: after wake-up, but before processing any IO or tasks. + */ +AWS_IO_API +void aws_event_loop_register_tick_start(struct aws_event_loop *event_loop); + +/** + * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the + * event-loop load balancer to take into account load when vending another event-loop to a caller. + * + * Call this function at the end of your event-loop tick: after processing IO and tasks. + */ +AWS_IO_API +void aws_event_loop_register_tick_end(struct aws_event_loop *event_loop); + +/** + * Returns the current load factor (however that may be calculated). If the event-loop is not invoking + * aws_event_loop_register_tick_start() and aws_event_loop_register_tick_end(), this value will always be 0. + */ +AWS_IO_API +size_t aws_event_loop_get_load_factor(struct aws_event_loop *event_loop); + +/** + * Blocks until the event loop stops completely. + * If you want to call aws_event_loop_run() again, you must call this after aws_event_loop_stop(). + * It is not safe to call this function from inside the event loop thread. + */ +AWS_IO_API +int aws_event_loop_wait_for_stop_completion(struct aws_event_loop *event_loop); + +/** + * Unsubscribes handle from event-loop notifications. + * This function is not thread safe and should be called inside the event-loop's thread. + * + * NOTE: if you are using io completion ports, this is a risky call. We use it in places, but only when we're certain + * there's no pending events. If you want to use it, it's your job to make sure you don't have pending events before + * calling it. + */ +AWS_IO_API +int aws_event_loop_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + +/** + * Cleans up resources (user_data) associated with the I/O eventing subsystem for a given handle. This should only + * ever be necessary in the case where you are cleaning up an event loop during shutdown and its thread has already + * been joined. + */ +AWS_IO_API +void aws_event_loop_free_io_event_resources(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + +AWS_EXTERN_C_END + +AWS_POP_SANE_WARNING_LEVEL + +#endif /* AWS_IO_EVENT_LOOP_IMPL_H */ From 97818453694556ebf0258b1c8e3f7f8cea113fd9 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 30 Oct 2024 19:39:20 -0700 Subject: [PATCH 05/72] Updated with doc comments --- include/aws/io/event_loop.h | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 4c27160a5..acc66deae 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -16,19 +16,59 @@ struct aws_task; typedef void(aws_elg_shutdown_completion_callback)(void *); +/** + * Configuration for a callback to invoke when an event loop group has been completely + * cleaned up, which includes destroying any managed threads. + */ struct aws_event_loop_group_shutdown_options { + + /** + * Function to invoke when the event loop group is fully destroyed. + */ aws_elg_shutdown_completion_callback *shutdown_callback_fn; + + /** + * User data to invoke the shutdown callback with. + */ void *shutdown_callback_user_data; }; +/** + * Configuration to pin an event loop group to a particular CPU group + */ struct aws_event_loop_group_pin_options { + + /** + * CPU group id that threads in this event loop group should be bound to + */ uint16_t cpu_group; }; +/** + * Event loop group configuration options + */ struct aws_event_loop_group_options { + + /** + * How many event loops that event loop group should contain. For most group types, this implies + * the creation and management of an analagous amount of managed threads + */ uint16_t loop_count; + + /** + * Clock function that all event loops should use. If left null, the system's high resolution + * clock will be used. Useful for injection mock time implementations when testing. + */ aws_io_clock_fn *clock_override; + + /** + * Optional callback to invoke when the event loop group finishes destruction. + */ struct aws_shutdown_callback_options *shutdown_options; + + /** + * Optional configuration to control how the event loop group's threads bind to CPU groups + */ struct aws_event_loop_group_pin_options *pin_options; }; @@ -80,6 +120,7 @@ AWS_IO_API int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_t *time_nanos); /** + * Creation function for event loop groups. */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new( @@ -101,9 +142,15 @@ struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_ AWS_IO_API void aws_event_loop_group_release(struct aws_event_loop_group *el_group); +/** + * Returns the event loop at a particular index. If the index is out of bounds, null is returned. + */ AWS_IO_API struct aws_event_loop *aws_event_loop_group_get_loop_at(struct aws_event_loop_group *el_group, size_t index); +/** + * Gets the number of event loops managed by an event loop group. + */ AWS_IO_API size_t aws_event_loop_group_get_loop_count(struct aws_event_loop_group *el_group); @@ -116,6 +163,7 @@ AWS_IO_API struct aws_event_loop *aws_event_loop_group_get_next_loop(struct aws_event_loop_group *el_group); AWS_EXTERN_C_END + AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_IO_EVENT_LOOP_H */ From 754c56db839ed8c292a5ce34fe4ea9080fae3b79 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 30 Oct 2024 20:15:38 -0700 Subject: [PATCH 06/72] Creation API --- include/aws/io/private/event_loop_impl.h | 66 +++++++------ source/event_loop.c | 115 +++++------------------ 2 files changed, 60 insertions(+), 121 deletions(-) diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 2ebfc40d4..e852aba82 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -58,10 +58,10 @@ struct aws_overlapped { }; typedef void(aws_event_loop_on_event_fn)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - void *user_data); + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + void *user_data); enum aws_io_event_type { AWS_IO_EVENT_TYPE_READABLE = 1, @@ -81,17 +81,16 @@ struct aws_event_loop_vtable { void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); int (*subscribe_to_io_events)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - aws_event_loop_on_event_fn *on_event, - void *user_data); + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + aws_event_loop_on_event_fn *on_event, + void *user_data); int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); void (*free_io_event_resources)(void *user_data); bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); }; - struct aws_event_loop { struct aws_event_loop_vtable *vtable; struct aws_allocator *alloc; @@ -118,10 +117,9 @@ struct aws_event_loop_options { struct aws_thread_options *thread_options; }; -typedef struct aws_event_loop *(aws_new_event_loop_fn)( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options, - void *new_loop_user_data); +typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, + const struct aws_event_loop_options *options, + void *new_loop_user_data); struct aws_event_loop_group { struct aws_allocator *allocator; @@ -139,9 +137,9 @@ AWS_EXTERN_C_BEGIN */ AWS_IO_API void aws_overlapped_init( - struct aws_overlapped *overlapped, - aws_event_loop_on_completion_fn *on_completion, - void *user_data); + struct aws_overlapped *overlapped, + aws_event_loop_on_completion_fn *on_completion, + void *user_data); /** * Prepares aws_overlapped for re-use without changing the assigned aws_event_loop_on_completion_fn. @@ -182,15 +180,14 @@ int aws_event_loop_connect_handle_to_io_completion_port( */ AWS_IO_API int aws_event_loop_subscribe_to_io_events( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - aws_event_loop_on_event_fn *on_event, - void *user_data); + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + aws_event_loop_on_event_fn *on_event, + void *user_data); #endif /* AWS_USE_IO_COMPLETION_PORTS */ - /** * Creates an instance of the default event loop implementation for the current architecture and operating system. */ @@ -203,8 +200,8 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a */ AWS_IO_API struct aws_event_loop *aws_event_loop_new_default_with_options( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options); + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); /** * Invokes the destroy() fn for the event loop implementation. @@ -236,9 +233,9 @@ void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); */ AWS_IO_API int aws_event_loop_fetch_local_object( - struct aws_event_loop *event_loop, - void *key, - struct aws_event_loop_local_object *obj); + struct aws_event_loop *event_loop, + void *key, + struct aws_event_loop_local_object *obj); /** * Puts an item object the event-loop's data store. Key will be taken as the memory address of the memory pointed to by @@ -256,9 +253,9 @@ int aws_event_loop_put_local_object(struct aws_event_loop *event_loop, struct aw */ AWS_IO_API int aws_event_loop_remove_local_object( - struct aws_event_loop *event_loop, - void *key, - struct aws_event_loop_local_object *removed_obj); + struct aws_event_loop *event_loop, + void *key, + struct aws_event_loop_local_object *removed_obj); /** * Triggers the running of the event loop. This function must not block. The event loop is not active until this @@ -330,6 +327,13 @@ int aws_event_loop_unsubscribe_from_io_events(struct aws_event_loop *event_loop, AWS_IO_API void aws_event_loop_free_io_event_resources(struct aws_event_loop *event_loop, struct aws_io_handle *handle); +AWS_IO_API +struct aws_event_loop_group *aws_event_loop_group_new_internal( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options, + aws_new_event_loop_fn *new_loop_fn, + void *new_loop_user_data); + AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL diff --git a/source/event_loop.c b/source/event_loop.c index 1e7aef676..a480b320b 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -72,30 +73,32 @@ static void s_aws_event_loop_group_shutdown_async(struct aws_event_loop_group *e aws_thread_launch(&cleanup_thread, s_event_loop_destroy_async_thread_fn, el_group, &thread_options); } -static struct aws_event_loop_group *s_event_loop_group_new( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - uint16_t cpu_group, - bool pin_threads, +struct aws_event_loop_group *aws_event_loop_group_new_internal( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options, aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options) { - AWS_ASSERT(new_loop_fn); + void *new_loop_user_data) { + AWS_FATAL_ASSERT(new_loop_fn); + + aws_io_clock_fn *clock = options->clock_override; + if (!clock) { + clock = aws_high_res_clock_get_ticks; + } size_t group_cpu_count = 0; struct aws_cpu_info *usable_cpus = NULL; + bool pin_threads = options->pin_options != NULL; if (pin_threads) { + uint16_t cpu_group = options->pin_options->cpu_group; group_cpu_count = aws_get_cpu_count_for_group(cpu_group); - if (!group_cpu_count) { + // LOG THIS aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); return NULL; } - usable_cpus = aws_mem_calloc(alloc, group_cpu_count, sizeof(struct aws_cpu_info)); - + usable_cpus = aws_mem_calloc(allocator, group_cpu_count, sizeof(struct aws_cpu_info)); if (usable_cpus == NULL) { return NULL; } @@ -103,16 +106,17 @@ static struct aws_event_loop_group *s_event_loop_group_new( aws_get_cpu_ids_for_group(cpu_group, usable_cpus, group_cpu_count); } - struct aws_event_loop_group *el_group = aws_mem_calloc(alloc, 1, sizeof(struct aws_event_loop_group)); + struct aws_event_loop_group *el_group = aws_mem_calloc(allocator, 1, sizeof(struct aws_event_loop_group)); if (el_group == NULL) { return NULL; } - el_group->allocator = alloc; + el_group->allocator = allocator; aws_ref_count_init( &el_group->ref_count, el_group, (aws_simple_completion_callback *)s_aws_event_loop_group_shutdown_async); - if (aws_array_list_init_dynamic(&el_group->event_loops, alloc, el_count, sizeof(struct aws_event_loop *))) { + uint16_t el_count = options->loop_count; + if (aws_array_list_init_dynamic(&el_group->event_loops, allocator, el_count, sizeof(struct aws_event_loop *))) { goto on_error; } @@ -121,7 +125,7 @@ static struct aws_event_loop_group *s_event_loop_group_new( if (!pin_threads || (i < group_cpu_count && !usable_cpus[i].suspected_hyper_thread)) { struct aws_thread_options thread_options = *aws_default_thread_options(); - struct aws_event_loop_options options = { + struct aws_event_loop_options el_options = { .clock = clock, .thread_options = &thread_options, }; @@ -138,8 +142,7 @@ static struct aws_event_loop_group *s_event_loop_group_new( } thread_options.name = aws_byte_cursor_from_c_str(thread_name); - struct aws_event_loop *loop = new_loop_fn(alloc, &options, new_loop_user_data); - + struct aws_event_loop *loop = new_loop_fn(allocator, &el_options, new_loop_user_data); if (!loop) { goto on_error; } @@ -155,12 +158,12 @@ static struct aws_event_loop_group *s_event_loop_group_new( } } - if (shutdown_options != NULL) { - el_group->shutdown_options = *shutdown_options; + if (options->shutdown_options != NULL) { + el_group->shutdown_options = *options->shutdown_options; } if (pin_threads) { - aws_mem_release(alloc, usable_cpus); + aws_mem_release(allocator, usable_cpus); } return el_group; @@ -169,7 +172,7 @@ on_error:; /* cache the error code to prevent any potential side effects */ int cached_error_code = aws_last_error(); - aws_mem_release(alloc, usable_cpus); + aws_mem_release(allocator, usable_cpus); s_aws_event_loop_group_shutdown_sync(el_group); s_event_loop_group_thread_exit(el_group); @@ -178,74 +181,6 @@ on_error:; return NULL; } -struct aws_event_loop_group *aws_event_loop_group_new( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options) { - - AWS_ASSERT(new_loop_fn); - AWS_ASSERT(el_count); - - return s_event_loop_group_new(alloc, clock, el_count, 0, false, new_loop_fn, new_loop_user_data, shutdown_options); -} - -static struct aws_event_loop *s_default_new_event_loop( - struct aws_allocator *allocator, - const struct aws_event_loop_options *options, - void *user_data) { - - (void)user_data; - return aws_event_loop_new_default_with_options(allocator, options); -} - -struct aws_event_loop_group *aws_event_loop_group_new_default( - struct aws_allocator *alloc, - uint16_t max_threads, - const struct aws_shutdown_callback_options *shutdown_options) { - if (!max_threads) { - uint16_t processor_count = (uint16_t)aws_system_info_processor_count(); - /* cut them in half to avoid using hyper threads for the IO work. */ - max_threads = processor_count > 1 ? processor_count / 2 : processor_count; - } - - return aws_event_loop_group_new( - alloc, aws_high_res_clock_get_ticks, max_threads, s_default_new_event_loop, NULL, shutdown_options); -} - -struct aws_event_loop_group *aws_event_loop_group_new_pinned_to_cpu_group( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - uint16_t cpu_group, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options) { - AWS_ASSERT(new_loop_fn); - AWS_ASSERT(el_count); - - return s_event_loop_group_new( - alloc, clock, el_count, cpu_group, true, new_loop_fn, new_loop_user_data, shutdown_options); -} - -struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( - struct aws_allocator *alloc, - uint16_t max_threads, - uint16_t cpu_group, - const struct aws_shutdown_callback_options *shutdown_options) { - - if (!max_threads) { - uint16_t processor_count = (uint16_t)aws_system_info_processor_count(); - /* cut them in half to avoid using hyper threads for the IO work. */ - max_threads = processor_count > 1 ? processor_count / 2 : processor_count; - } - - return aws_event_loop_group_new_pinned_to_cpu_group( - alloc, aws_high_res_clock_get_ticks, max_threads, cpu_group, s_default_new_event_loop, NULL, shutdown_options); -} - struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group) { if (el_group != NULL) { aws_ref_count_acquire(&el_group->ref_count); From 974a9b2c7f41487cd01ea9d205d80d2005dd1301 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 5 Nov 2024 13:16:17 -0800 Subject: [PATCH 07/72] Checkpoint --- include/aws/io/event_loop.h | 26 +-------- include/aws/io/private/event_loop_impl.h | 1 + include/aws/testing/io_testing_channel.h | 1 + source/bsd/kqueue_event_loop.c | 4 +- source/channel.c | 1 + source/event_loop.c | 21 +++++++- source/exponential_backoff_retry_strategy.c | 5 +- source/linux/epoll_event_loop.c | 7 ++- source/posix/pipe.c | 1 + source/posix/socket.c | 1 + source/s2n/s2n_tls_channel_handler.c | 11 ++-- tests/alpn_handler_test.c | 1 + tests/channel_test.c | 6 ++- tests/default_host_resolver_test.c | 60 ++++++++++++++++----- tests/exponential_backoff_retry_test.c | 25 +++++++-- tests/future_test.c | 1 + tests/pipe_test.c | 1 + tests/pkcs11_test.c | 6 ++- tests/socket_handler_test.c | 14 +++-- tests/socket_test.c | 16 ++++-- tests/standard_retry_test.c | 8 ++- tests/tls_handler_test.c | 12 +++-- 22 files changed, 159 insertions(+), 70 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index acc66deae..12ee1d04e 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -12,27 +12,9 @@ AWS_PUSH_SANE_WARNING_LEVEL struct aws_event_loop; struct aws_event_loop_group; +struct aws_shutdown_callback_options; struct aws_task; -typedef void(aws_elg_shutdown_completion_callback)(void *); - -/** - * Configuration for a callback to invoke when an event loop group has been completely - * cleaned up, which includes destroying any managed threads. - */ -struct aws_event_loop_group_shutdown_options { - - /** - * Function to invoke when the event loop group is fully destroyed. - */ - aws_elg_shutdown_completion_callback *shutdown_callback_fn; - - /** - * User data to invoke the shutdown callback with. - */ - void *shutdown_callback_user_data; -}; - /** * Configuration to pin an event loop group to a particular CPU group */ @@ -55,12 +37,6 @@ struct aws_event_loop_group_options { */ uint16_t loop_count; - /** - * Clock function that all event loops should use. If left null, the system's high resolution - * clock will be used. Useful for injection mock time implementations when testing. - */ - aws_io_clock_fn *clock_override; - /** * Optional callback to invoke when the event loop group finishes destruction. */ diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index e852aba82..4935f8679 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -331,6 +331,7 @@ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new_internal( struct aws_allocator *allocator, const struct aws_event_loop_group_options *options, + aws_io_clock_fn *clock_override, aws_new_event_loop_fn *new_loop_fn, void *new_loop_user_data); diff --git a/include/aws/testing/io_testing_channel.h b/include/aws/testing/io_testing_channel.h index d2f1c13a5..501c3f6bf 100644 --- a/include/aws/testing/io_testing_channel.h +++ b/include/aws/testing/io_testing_channel.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/source/bsd/kqueue_event_loop.c b/source/bsd/kqueue_event_loop.c index 33a517e7b..e0f8ed63b 100644 --- a/source/bsd/kqueue_event_loop.c +++ b/source/bsd/kqueue_event_loop.c @@ -5,14 +5,14 @@ #include -#include - #include #include #include #include #include #include +#include +#include #if defined(__FreeBSD__) || defined(__NetBSD__) # define __BSD_VISIBLE 1 diff --git a/source/channel.c b/source/channel.c index 36a3975b2..6943540f6 100644 --- a/source/channel.c +++ b/source/channel.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #ifdef _MSC_VER diff --git a/source/event_loop.c b/source/event_loop.c index a480b320b..3b310ca85 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -4,7 +4,9 @@ */ #include + #include +#include #include #include @@ -76,11 +78,12 @@ static void s_aws_event_loop_group_shutdown_async(struct aws_event_loop_group *e struct aws_event_loop_group *aws_event_loop_group_new_internal( struct aws_allocator *allocator, const struct aws_event_loop_group_options *options, + aws_io_clock_fn *clock_override, aws_new_event_loop_fn *new_loop_fn, void *new_loop_user_data) { AWS_FATAL_ASSERT(new_loop_fn); - aws_io_clock_fn *clock = options->clock_override; + aws_io_clock_fn *clock = clock_override; if (!clock) { clock = aws_high_res_clock_get_ticks; } @@ -181,6 +184,22 @@ on_error:; return NULL; } +static struct aws_event_loop *s_default_new_event_loop( + struct aws_allocator *allocator, + const struct aws_event_loop_options *options, + void *user_data) { + + (void)user_data; + return aws_event_loop_new_default_with_options(allocator, options); +} + +struct aws_event_loop_group *aws_event_loop_group_new( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options) { + + return aws_event_loop_group_new_internal(allocator, options, aws_high_res_clock_get_ticks, s_default_new_event_loop, NULL); +} + struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group) { if (el_group != NULL) { aws_ref_count_acquire(&el_group->ref_count); diff --git a/source/exponential_backoff_retry_strategy.c b/source/exponential_backoff_retry_strategy.c index cf2472269..2110cbd46 100644 --- a/source/exponential_backoff_retry_strategy.c +++ b/source/exponential_backoff_retry_strategy.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,7 @@ static void s_exponential_retry_destroy(struct aws_retry_strategy *retry_strateg if (completion_callback != NULL) { completion_callback(completion_user_data); } - aws_ref_count_release(&el_group->ref_count); + aws_event_loop_group_release(el_group); } } @@ -361,7 +362,7 @@ struct aws_retry_strategy *aws_retry_strategy_new_exponential_backoff( aws_atomic_init_int(&exponential_backoff_strategy->base.ref_count, 1); exponential_backoff_strategy->config = *config; exponential_backoff_strategy->config.el_group = - aws_ref_count_acquire(&exponential_backoff_strategy->config.el_group->ref_count); + aws_event_loop_group_acquire(exponential_backoff_strategy->config.el_group); if (!exponential_backoff_strategy->config.generate_random && !exponential_backoff_strategy->config.generate_random_impl) { diff --git a/source/linux/epoll_event_loop.c b/source/linux/epoll_event_loop.c index 094a7836a..a99d5a8cf 100644 --- a/source/linux/epoll_event_loop.c +++ b/source/linux/epoll_event_loop.c @@ -3,17 +3,16 @@ * SPDX-License-Identifier: Apache-2.0. */ -#include - #include #include #include #include #include #include -#include - +#include #include +#include +#include #include diff --git a/source/posix/pipe.c b/source/posix/pipe.c index f727b021c..449ab1318 100644 --- a/source/posix/pipe.c +++ b/source/posix/pipe.c @@ -6,6 +6,7 @@ #include #include +#include #ifdef __GLIBC__ # define __USE_GNU diff --git a/source/posix/socket.c b/source/posix/socket.c index 16972756e..2751a0f75 100644 --- a/source/posix/socket.c +++ b/source/posix/socket.c @@ -13,6 +13,7 @@ #include #include +#include #include #include diff --git a/source/s2n/s2n_tls_channel_handler.c b/source/s2n/s2n_tls_channel_handler.c index 14839d19f..3ceee114f 100644 --- a/source/s2n/s2n_tls_channel_handler.c +++ b/source/s2n/s2n_tls_channel_handler.c @@ -5,21 +5,20 @@ #include #include +#include #include - +#include +#include +#include #include #include #include #include +#include #include #include #include -#include -#include -#include -#include - #include #include #include diff --git a/tests/alpn_handler_test.c b/tests/alpn_handler_test.c index 5d83bad4e..fa6d88e27 100644 --- a/tests/alpn_handler_test.c +++ b/tests/alpn_handler_test.c @@ -5,6 +5,7 @@ #include #include +#include #include #include diff --git a/tests/channel_test.c b/tests/channel_test.c index 9a730a351..318e9a7b2 100644 --- a/tests/channel_test.c +++ b/tests/channel_test.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -684,7 +685,10 @@ static int s_test_channel_connect_some_hosts_timeout(struct aws_allocator *alloc .shutdown = false, }; - struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); /* resolve our s3 test bucket and an EC2 host with an ACL that blackholes the connection */ const struct aws_string *addr1_ipv4 = NULL; diff --git a/tests/default_host_resolver_test.c b/tests/default_host_resolver_test.c index 2d0178a73..2a618108f 100644 --- a/tests/default_host_resolver_test.c +++ b/tests/default_host_resolver_test.c @@ -96,7 +96,10 @@ static int s_test_default_with_ipv6_lookup_fn(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -189,7 +192,10 @@ static int s_test_default_host_resolver_ipv6_address_variations_fn(struct aws_al }; - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -263,7 +269,10 @@ static int s_test_default_with_ipv4_only_lookup_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -333,7 +342,10 @@ static int s_test_default_with_multiple_lookups_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -460,7 +472,10 @@ static int s_test_resolver_ttls_fn(struct aws_allocator *allocator, void *ctx) { s_set_time(0); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, .max_entries = 10, .system_clock_override_fn = s_clock_fn}; @@ -672,7 +687,10 @@ static int s_test_resolver_connect_failure_recording_fn(struct aws_allocator *al aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -864,7 +882,10 @@ static int s_test_resolver_ttl_refreshes_on_resolve_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1044,7 +1065,10 @@ static int s_test_resolver_ipv4_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1105,7 +1129,10 @@ static int s_test_resolver_purge_host_cache(struct aws_allocator *allocator, voi (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1220,7 +1247,10 @@ static int s_test_resolver_purge_cache(struct aws_allocator *allocator, void *ct (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1369,7 +1399,10 @@ static int s_test_resolver_ipv6_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1431,7 +1464,10 @@ static int s_test_resolver_low_frequency_starvation_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, diff --git a/tests/exponential_backoff_retry_test.c b/tests/exponential_backoff_retry_test.c index a3bf7bde0..df71f8065 100644 --- a/tests/exponential_backoff_retry_test.c +++ b/tests/exponential_backoff_retry_test.c @@ -66,7 +66,10 @@ static int s_test_exponential_backoff_retry_too_many_retries_for_jitter_mode( aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, .jitter_mode = jitter_mode, @@ -157,7 +160,10 @@ static int s_test_exponential_backoff_retry_client_errors_do_not_count_fn(struct aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .el_group = el_group, .max_retries = 3, @@ -201,7 +207,10 @@ static int s_test_exponential_backoff_retry_no_jitter_time_taken_fn(struct aws_a aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, .jitter_mode = AWS_EXPONENTIAL_BACKOFF_JITTER_NONE, @@ -253,7 +262,10 @@ static int s_test_exponential_max_backoff_retry_no_jitter_fn(struct aws_allocato aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, .jitter_mode = AWS_EXPONENTIAL_BACKOFF_JITTER_NONE, @@ -310,7 +322,10 @@ static int s_test_exponential_backoff_retry_invalid_options_fn(struct aws_alloca aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 64, .el_group = el_group, diff --git a/tests/future_test.c b/tests/future_test.c index 1ac94b551..795d30bb5 100644 --- a/tests/future_test.c +++ b/tests/future_test.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "future_test.h" diff --git a/tests/pipe_test.c b/tests/pipe_test.c index 053c5aefd..f15f4da33 100644 --- a/tests/pipe_test.c +++ b/tests/pipe_test.c @@ -8,6 +8,7 @@ #include #include #include +#include #include enum pipe_loop_setup { diff --git a/tests/pkcs11_test.c b/tests/pkcs11_test.c index 792ed5fa4..5dcc2e8bb 100644 --- a/tests/pkcs11_test.c +++ b/tests/pkcs11_test.c @@ -1653,8 +1653,10 @@ static int s_test_pkcs11_tls_negotiation_succeeds_common( ASSERT_SUCCESS(aws_mutex_init(&s_tls_tester.synced.mutex)); ASSERT_SUCCESS(aws_condition_variable_init(&s_tls_tester.synced.cvar)); - struct aws_event_loop_group *event_loop_group = - aws_event_loop_group_new_default(allocator, 1, NULL /*shutdown_opts*/); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); ASSERT_NOT_NULL(event_loop_group); struct aws_host_resolver_default_options resolver_opts = { diff --git a/tests/socket_handler_test.c b/tests/socket_handler_test.c index 513ca570e..35dcfefc9 100644 --- a/tests/socket_handler_test.c +++ b/tests/socket_handler_test.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include #include @@ -59,7 +60,10 @@ static int s_socket_common_tester_init(struct aws_allocator *allocator, struct s AWS_ZERO_STRUCT(*tester); aws_io_library_init(allocator); - tester->el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, @@ -1006,8 +1010,12 @@ static int s_socket_common_tester_statistics_init( aws_io_library_init(allocator); AWS_ZERO_STRUCT(*tester); - tester->el_group = - aws_event_loop_group_new(allocator, s_statistic_test_clock_fn, 1, s_default_new_event_loop, NULL, NULL); + + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_statistic_test_clock_fn, s_default_new_event_loop, NULL); + struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; tester->mutex = mutex; diff --git a/tests/socket_test.c b/tests/socket_test.c index 07740fc21..52de3cee2 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -12,6 +12,7 @@ #include #include +#include #include #ifdef _MSC_VER @@ -546,7 +547,10 @@ static int s_test_connect_timeout(struct aws_allocator *allocator, void *ctx) { aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -626,7 +630,10 @@ static int s_test_connect_timeout_cancelation(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -1058,7 +1065,10 @@ static int s_cleanup_before_connect_or_timeout_doesnt_explode(struct aws_allocat aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); diff --git a/tests/standard_retry_test.c b/tests/standard_retry_test.c index bb62de691..11991a3e0 100644 --- a/tests/standard_retry_test.c +++ b/tests/standard_retry_test.c @@ -8,6 +8,7 @@ #include #include +#include #include @@ -49,7 +50,12 @@ static int s_fixture_setup(struct aws_allocator *allocator, void *ctx) { .shutdown_callback_user_data = ctx, }; - test_data->el_group = aws_event_loop_group_new_default(allocator, 1, &shutdown_options); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + .shutdown_options = &shutdown_options, + }; + test_data->el_group = aws_event_loop_group_new(allocator, &elg_options); + ASSERT_NOT_NULL(test_data->el_group); struct aws_standard_retry_options retry_options = { .initial_bucket_capacity = 15, diff --git a/tests/tls_handler_test.c b/tests/tls_handler_test.c index 1a7f94ddf..602246e52 100644 --- a/tests/tls_handler_test.c +++ b/tests/tls_handler_test.c @@ -10,6 +10,7 @@ # include # include # include +# include # include # include @@ -160,7 +161,10 @@ static int s_tls_common_tester_init(struct aws_allocator *allocator, struct tls_ aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - tester->el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 0 + }; + tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, @@ -1662,8 +1666,10 @@ static int s_tls_common_tester_statistics_init(struct aws_allocator *allocator, aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - tester->el_group = - aws_event_loop_group_new(allocator, s_statistic_test_clock_fn, 1, s_default_new_event_loop, NULL, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1 + }; + tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_statistic_test_clock_fn, s_default_new_event_loop, NULL); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, From 75e4f45c1d1819a213293d0721d7c2b78dbe5732 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 5 Nov 2024 13:36:29 -0800 Subject: [PATCH 08/72] Formatting --- source/event_loop.c | 5 +-- tests/channel_test.c | 4 +-- tests/default_host_resolver_test.c | 48 +++++++------------------- tests/event_loop_test.c | 10 ++---- tests/exponential_backoff_retry_test.c | 20 +++-------- tests/pkcs11_test.c | 4 +-- tests/socket_handler_test.c | 11 +++--- tests/socket_test.c | 12 ++----- tests/tls_handler_test.c | 15 +++----- 9 files changed, 37 insertions(+), 92 deletions(-) diff --git a/source/event_loop.c b/source/event_loop.c index 3b310ca85..4bc48a6b5 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -5,8 +5,8 @@ #include -#include #include +#include #include #include @@ -197,7 +197,8 @@ struct aws_event_loop_group *aws_event_loop_group_new( struct aws_allocator *allocator, const struct aws_event_loop_group_options *options) { - return aws_event_loop_group_new_internal(allocator, options, aws_high_res_clock_get_ticks, s_default_new_event_loop, NULL); + return aws_event_loop_group_new_internal( + allocator, options, aws_high_res_clock_get_ticks, s_default_new_event_loop, NULL); } struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group) { diff --git a/tests/channel_test.c b/tests/channel_test.c index 318e9a7b2..995d83add 100644 --- a/tests/channel_test.c +++ b/tests/channel_test.c @@ -685,9 +685,7 @@ static int s_test_channel_connect_some_hosts_timeout(struct aws_allocator *alloc .shutdown = false, }; - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); /* resolve our s3 test bucket and an EC2 host with an ACL that blackholes the connection */ diff --git a/tests/default_host_resolver_test.c b/tests/default_host_resolver_test.c index 2a618108f..5f9ba3734 100644 --- a/tests/default_host_resolver_test.c +++ b/tests/default_host_resolver_test.c @@ -96,9 +96,7 @@ static int s_test_default_with_ipv6_lookup_fn(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -192,9 +190,7 @@ static int s_test_default_host_resolver_ipv6_address_variations_fn(struct aws_al }; - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -269,9 +265,7 @@ static int s_test_default_with_ipv4_only_lookup_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -342,9 +336,7 @@ static int s_test_default_with_multiple_lookups_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -472,9 +464,7 @@ static int s_test_resolver_ttls_fn(struct aws_allocator *allocator, void *ctx) { s_set_time(0); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -687,9 +677,7 @@ static int s_test_resolver_connect_failure_recording_fn(struct aws_allocator *al aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -882,9 +870,7 @@ static int s_test_resolver_ttl_refreshes_on_resolve_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1065,9 +1051,7 @@ static int s_test_resolver_ipv4_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1129,9 +1113,7 @@ static int s_test_resolver_purge_host_cache(struct aws_allocator *allocator, voi (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1247,9 +1229,7 @@ static int s_test_resolver_purge_cache(struct aws_allocator *allocator, void *ct (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1399,9 +1379,7 @@ static int s_test_resolver_ipv6_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1464,9 +1442,7 @@ static int s_test_resolver_low_frequency_starvation_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index c0783c40e..737f0a0f7 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -1041,9 +1041,7 @@ static int test_event_loop_group_setup_and_shutdown(struct aws_allocator *alloca (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 0 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 0}; struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); size_t cpu_count = aws_system_info_processor_count(); @@ -1087,8 +1085,7 @@ static int test_numa_aware_event_loop_group_setup_and_shutdown(struct aws_alloca .loop_count = UINT16_MAX, .pin_options = &pin_options, }; - struct aws_event_loop_group *event_loop_group = - aws_event_loop_group_new(allocator, &elg_options); + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); el_count = aws_event_loop_group_get_loop_count(event_loop_group); @@ -1170,8 +1167,7 @@ static int test_event_loop_group_setup_and_shutdown_async(struct aws_allocator * .shutdown_options = &async_shutdown_options, }; - struct aws_event_loop_group *event_loop_group = - aws_event_loop_group_new(allocator, &elg_options); + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(event_loop_group); diff --git a/tests/exponential_backoff_retry_test.c b/tests/exponential_backoff_retry_test.c index df71f8065..f36c5c5e0 100644 --- a/tests/exponential_backoff_retry_test.c +++ b/tests/exponential_backoff_retry_test.c @@ -66,9 +66,7 @@ static int s_test_exponential_backoff_retry_too_many_retries_for_jitter_mode( aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, @@ -160,9 +158,7 @@ static int s_test_exponential_backoff_retry_client_errors_do_not_count_fn(struct aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .el_group = el_group, @@ -207,9 +203,7 @@ static int s_test_exponential_backoff_retry_no_jitter_time_taken_fn(struct aws_a aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, @@ -262,9 +256,7 @@ static int s_test_exponential_max_backoff_retry_no_jitter_fn(struct aws_allocato aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, @@ -322,9 +314,7 @@ static int s_test_exponential_backoff_retry_invalid_options_fn(struct aws_alloca aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 64, diff --git a/tests/pkcs11_test.c b/tests/pkcs11_test.c index 5dcc2e8bb..c15e0cd9c 100644 --- a/tests/pkcs11_test.c +++ b/tests/pkcs11_test.c @@ -1653,9 +1653,7 @@ static int s_test_pkcs11_tls_negotiation_succeeds_common( ASSERT_SUCCESS(aws_mutex_init(&s_tls_tester.synced.mutex)); ASSERT_SUCCESS(aws_condition_variable_init(&s_tls_tester.synced.cvar)); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); ASSERT_NOT_NULL(event_loop_group); diff --git a/tests/socket_handler_test.c b/tests/socket_handler_test.c index 181d0e099..af9b28473 100644 --- a/tests/socket_handler_test.c +++ b/tests/socket_handler_test.c @@ -60,9 +60,7 @@ static int s_socket_common_tester_init(struct aws_allocator *allocator, struct s AWS_ZERO_STRUCT(*tester); aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1011,10 +1009,9 @@ static int s_socket_common_tester_statistics_init( AWS_ZERO_STRUCT(*tester); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; - tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_statistic_test_clock_fn, s_default_new_event_loop, NULL); + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + tester->el_group = aws_event_loop_group_new_internal( + allocator, &elg_options, s_statistic_test_clock_fn, s_default_new_event_loop, NULL); struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; diff --git a/tests/socket_test.c b/tests/socket_test.c index b8d030d53..d930600c6 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -625,9 +625,7 @@ static int s_test_connect_timeout(struct aws_allocator *allocator, void *ctx) { aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -708,9 +706,7 @@ static int s_test_connect_timeout_cancelation(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -1154,9 +1150,7 @@ static int s_cleanup_before_connect_or_timeout_doesnt_explode(struct aws_allocat aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); diff --git a/tests/tls_handler_test.c b/tests/tls_handler_test.c index 3b899d363..10778a245 100644 --- a/tests/tls_handler_test.c +++ b/tests/tls_handler_test.c @@ -178,9 +178,7 @@ static int s_tls_common_tester_init(struct aws_allocator *allocator, struct tls_ aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - struct aws_event_loop_group_options elg_options = { - .loop_count = 0 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 0}; tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -537,9 +535,7 @@ static int s_tls_channel_server_client_tester_init(struct aws_allocator *allocat ASSERT_SUCCESS(aws_mutex_init(&s_server_client_tester.server_mutex)); ASSERT_SUCCESS(aws_condition_variable_init(&s_server_client_tester.server_condition_variable)); - struct aws_event_loop_group_options elg_options = { - .loop_count = 0 - }; + struct aws_event_loop_group_options elg_options = {.loop_count = 0}; s_server_client_tester.client_el_group = aws_event_loop_group_new(allocator, &elg_options); ASSERT_SUCCESS(s_tls_rw_args_init( @@ -1912,10 +1908,9 @@ static int s_tls_common_tester_statistics_init(struct aws_allocator *allocator, aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - struct aws_event_loop_group_options elg_options = { - .loop_count = 1 - }; - tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_statistic_test_clock_fn, s_default_new_event_loop, NULL); + struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + tester->el_group = aws_event_loop_group_new_internal( + allocator, &elg_options, s_statistic_test_clock_fn, s_default_new_event_loop, NULL); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, From 4a784ccb7e147cb7df03d24f989f99d7a5a5c9d2 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 5 Nov 2024 13:48:32 -0800 Subject: [PATCH 09/72] Oops --- source/event_loop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/event_loop.c b/source/event_loop.c index 4bc48a6b5..82b1c9b56 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -119,6 +119,12 @@ struct aws_event_loop_group *aws_event_loop_group_new_internal( &el_group->ref_count, el_group, (aws_simple_completion_callback *)s_aws_event_loop_group_shutdown_async); uint16_t el_count = options->loop_count; + if (el_count == 0) { + uint16_t processor_count = (uint16_t)aws_system_info_processor_count(); + /* cut them in half to avoid using hyper threads for the IO work. */ + el_count = processor_count > 1 ? processor_count / 2 : processor_count; + } + if (aws_array_list_init_dynamic(&el_group->event_loops, allocator, el_count, sizeof(struct aws_event_loop *))) { goto on_error; } From 381f3ddd9a4b96f30d95fb2cbd32ec6e08acd6d2 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 5 Nov 2024 13:55:27 -0800 Subject: [PATCH 10/72] Windows updates --- source/windows/iocp/iocp_event_loop.c | 1 + source/windows/iocp/pipe.c | 1 + source/windows/iocp/socket.c | 1 + 3 files changed, 3 insertions(+) diff --git a/source/windows/iocp/iocp_event_loop.c b/source/windows/iocp/iocp_event_loop.c index 313344ab9..1d0801e4b 100644 --- a/source/windows/iocp/iocp_event_loop.c +++ b/source/windows/iocp/iocp_event_loop.c @@ -11,6 +11,7 @@ #include #include +#include #include diff --git a/source/windows/iocp/pipe.c b/source/windows/iocp/pipe.c index 04145c679..a9e2185e5 100644 --- a/source/windows/iocp/pipe.c +++ b/source/windows/iocp/pipe.c @@ -7,6 +7,7 @@ #include #include +#include #include #include diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index 755950f0c..7286bd6ba 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -26,6 +26,7 @@ below, clang-format doesn't work (at least on my version) with the c-style comme #include #include #include +#include #include #include From e63c0a8b7bf4057007aa5fe278fe3d5e2d2582a3 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 5 Nov 2024 14:04:41 -0800 Subject: [PATCH 11/72] test update --- tests/byo_crypto_test.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/byo_crypto_test.c b/tests/byo_crypto_test.c index 878889646..1414f8652 100644 --- a/tests/byo_crypto_test.c +++ b/tests/byo_crypto_test.c @@ -54,7 +54,11 @@ static struct byo_crypto_common_tester c_tester; static int s_byo_crypto_common_tester_init(struct aws_allocator *allocator, struct byo_crypto_common_tester *tester) { AWS_ZERO_STRUCT(*tester); aws_io_library_init(allocator); - tester->el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; tester->mutex = mutex; From 09cff00d5a17023f832d8d0126b2ff80a2fa9614 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Wed, 6 Nov 2024 16:50:56 -0800 Subject: [PATCH 12/72] [WIP] API update for runtime switch event loop --- include/aws/io/event_loop.h | 25 +++++ include/aws/io/private/event_loop_impl.h | 33 +++++++ source/bsd/kqueue_event_loop.c | 2 +- source/event_loop.c | 115 ++++++++++++++++++++++- source/linux/epoll_event_loop.c | 2 +- source/windows/iocp/iocp_event_loop.c | 2 +- 6 files changed, 175 insertions(+), 4 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 12ee1d04e..923770977 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -15,6 +15,25 @@ struct aws_event_loop_group; struct aws_shutdown_callback_options; struct aws_task; +/** + * Event Loop Type. If set to `AWS_ELT_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default + * event loop type. + * + * Default Event Loop Type + * Linux | AWS_ELT_EPOLL + * Windows | AWS_ELT_IOCP + * BSD Variants| AWS_ELT_KQUEUE + * MacOS | AWS_ELT_KQUEUE + * iOS | AWS_ELT_DISPATCH_QUEUE + */ +enum aws_event_loop_type { + AWS_ELT_PLATFORM_DEFAULT = 0, + AWS_ELT_EPOLL, + AWS_ELT_IOCP, + AWS_ELT_KQUEUE, + AWS_ELT_DISPATCH_QUEUE, +}; + /** * Configuration to pin an event loop group to a particular CPU group */ @@ -37,6 +56,12 @@ struct aws_event_loop_group_options { */ uint16_t loop_count; + /** + * Event loop type. If the event loop type is set to AWS_ELT_PLATFORM_DEFAULT, the + * creation function will automatically use the platform’s default event loop type. + */ + enum aws_event_loop_type type; + /** * Optional callback to invoke when the event loop group finishes destruction. */ diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 4935f8679..d2d3c359b 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -115,8 +115,31 @@ struct aws_event_loop_local_object { struct aws_event_loop_options { aws_io_clock_fn *clock; struct aws_thread_options *thread_options; + + /** + * Event loop type. If the event loop type is set to AWS_ELT_PLATFORM_DEFAULT, the + * creation function will automatically use the platform’s default event loop type. + */ + enum aws_event_loop_type type; }; +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_iocp_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_kqueue_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_epoll_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); + typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, const struct aws_event_loop_options *options, void *new_loop_user_data); @@ -197,12 +220,22 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a /** * Creates an instance of the default event loop implementation for the current architecture and operating system using * extendable options. + * + * Please note the event loop type defined in the options will be ignored. */ AWS_IO_API struct aws_event_loop *aws_event_loop_new_default_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); +/** + * Creates an instance of the event loop implementation from the options. + */ +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); + /** * Invokes the destroy() fn for the event loop implementation. * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. diff --git a/source/bsd/kqueue_event_loop.c b/source/bsd/kqueue_event_loop.c index e0f8ed63b..a03f8daf4 100644 --- a/source/bsd/kqueue_event_loop.c +++ b/source/bsd/kqueue_event_loop.c @@ -131,7 +131,7 @@ struct aws_event_loop_vtable s_kqueue_vtable = { .is_on_callers_thread = s_is_event_thread, }; -struct aws_event_loop *aws_event_loop_new_default_with_options( +struct aws_event_loop *aws_event_loop_new_kqueue_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { AWS_ASSERT(alloc); diff --git a/source/event_loop.c b/source/event_loop.c index 82b1c9b56..ded252698 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -5,11 +5,12 @@ #include -#include +#include #include #include #include +#include #include #include @@ -17,11 +18,70 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a struct aws_event_loop_options options = { .thread_options = NULL, .clock = clock, + .type = AWS_ELT_PLATFORM_DEFAULT, }; return aws_event_loop_new_default_with_options(alloc, &options); } +struct aws_event_loop *aws_event_loop_new_default_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + struct aws_event_loop_options local_options = { + .thread_options = options->thread_options, + .clock = options->clock, + .type = AWS_ELT_PLATFORM_DEFAULT, + }; + + return aws_event_loop_new_with_options(alloc, &local_options); +} + +static enum aws_event_loop_type aws_event_loop_get_default_type(void); +static int aws_event_loop_validate_platform(enum aws_event_loop_type type); +struct aws_event_loop *aws_event_loop_new_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + + enum aws_event_loop_type type = options->type; + if (type == AWS_ELT_PLATFORM_DEFAULT) { + type = aws_event_loop_get_default_type(); + } + + if (aws_event_loop_validate_platform(type)) { + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type on the platform."); + return NULL; + } + + switch (type) { + case AWS_ELT_EPOLL: + return aws_event_loop_new_epoll_with_options(alloc, options); + break; + case AWS_ELT_IOCP: + return aws_event_loop_new_iocp_with_options(alloc, options); + break; + case AWS_ELT_KQUEUE: + return aws_event_loop_new_kqueue_with_options(alloc, options); + break; + case AWS_ELT_DISPATCH_QUEUE: + return aws_event_loop_new_dispatch_queue_with_options(alloc, options); + break; + default: + break; + } + + return NULL; +} + +// TODO: DISPATCH QUEUE will be implemented later. +struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + (void) alloc; + (void) options; + AWS_ASSERT("DISPATCH QUEUE IS NOT SUPPORTED YET" == NULL); + return NULL; +} + static void s_event_loop_group_thread_exit(void *user_data) { struct aws_event_loop_group *el_group = user_data; @@ -489,3 +549,56 @@ int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_ AWS_ASSERT(event_loop->clock); return event_loop->clock(time_nanos); } + +static enum aws_event_loop_type aws_event_loop_get_default_type(void) { +/** + * Ideally we should use the platform definition (e.x.: AWS_OS_APPLE) here, however the platform + * definition was declared in aws-c-common. We probably do not want to introduce extra dependency here. + */ +#ifdef AWS_OS_WINDOWS + return AWS_ELT_IOCP; +#endif +#ifdef AWS_USE_KQUEUE + return AWS_ELT_KQUEUE; +#endif +#ifdef AWS_USE_DISPATCH_QUEUE + return AWS_ELT_DISPATCH_QUEUE; +#endif +#ifdef AWS_USE_EPOLL + return AWS_ELT_DISPATCH_QUEUE; +#endif +} + +static int aws_event_loop_validate_platform(enum aws_event_loop_type type) { + switch (type) { + case AWS_ELT_EPOLL: +#ifndef AWS_USE_EPOLL + AWS_ASSERT("Event loop type EPOLL is not supported on the platform." == NULL); + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); +#endif // AWS_USE_EPOLL + break; + case AWS_ELT_IOCP: +#ifndef AWS_USE_IO_COMPLETION_PORTS + AWS_ASSERT("Event loop type IOCP is not supported on the platform." == NULL); + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); +#endif // AWS_USE_IO_COMPLETION_PORTS + break; + case AWS_ELT_KQUEUE: +#ifndef AWS_USE_KQUEUE + AWS_ASSERT("Event loop type KQUEUE is not supported on the platform." == NULL); + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); +#endif // AWS_USE_KQUEUE + break; + case AWS_ELT_DISPATCH_QUEUE: +#ifndef AWS_USE_DISPATCH_QUEUE + AWS_ASSERT("Event loop type Dispatch Queue is not supported on the platform." == NULL); + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); +#endif // AWS_USE_DISPATCH_QUEUE + break; + default: + AWS_ASSERT("Invalid event loop type." == NULL); + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); + break; + } + return AWS_OP_SUCCESS; +} diff --git a/source/linux/epoll_event_loop.c b/source/linux/epoll_event_loop.c index a99d5a8cf..b0f6d7334 100644 --- a/source/linux/epoll_event_loop.c +++ b/source/linux/epoll_event_loop.c @@ -112,7 +112,7 @@ enum { int aws_open_nonblocking_posix_pipe(int pipe_fds[2]); /* Setup edge triggered epoll with a scheduler. */ -struct aws_event_loop *aws_event_loop_new_default_with_options( +struct aws_event_loop *aws_event_loop_new_epoll_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { AWS_PRECONDITION(options); diff --git a/source/windows/iocp/iocp_event_loop.c b/source/windows/iocp/iocp_event_loop.c index 1d0801e4b..473629de9 100644 --- a/source/windows/iocp/iocp_event_loop.c +++ b/source/windows/iocp/iocp_event_loop.c @@ -144,7 +144,7 @@ struct aws_event_loop_vtable s_iocp_vtable = { .free_io_event_resources = s_free_io_event_resources, }; -struct aws_event_loop *aws_event_loop_new_default_with_options( +struct aws_event_loop *aws_event_loop_new_iocp_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { AWS_ASSERT(alloc); From ca3a1342585e59ea9b688ff023cb671db60cff9c Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 7 Nov 2024 09:09:15 -0800 Subject: [PATCH 13/72] update event loop group creation --- source/event_loop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/event_loop.c b/source/event_loop.c index ded252698..4259b0bd2 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -66,6 +66,8 @@ struct aws_event_loop *aws_event_loop_new_with_options( return aws_event_loop_new_dispatch_queue_with_options(alloc, options); break; default: + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type on the platform."); + aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); break; } @@ -197,6 +199,7 @@ struct aws_event_loop_group *aws_event_loop_group_new_internal( struct aws_event_loop_options el_options = { .clock = clock, .thread_options = &thread_options, + .type = options->type }; if (pin_threads) { From 66196955ae6a252a820c74c35d44481b898870df Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 7 Nov 2024 09:23:17 -0800 Subject: [PATCH 14/72] clang format --- include/aws/io/private/event_loop_impl.h | 4 ++-- source/event_loop.c | 11 ++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index d2d3c359b..6a7c49149 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -117,7 +117,7 @@ struct aws_event_loop_options { struct aws_thread_options *thread_options; /** - * Event loop type. If the event loop type is set to AWS_ELT_PLATFORM_DEFAULT, the + * Event loop type. If the event loop type is set to AWS_ELT_PLATFORM_DEFAULT, the * creation function will automatically use the platform’s default event loop type. */ enum aws_event_loop_type type; @@ -220,7 +220,7 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a /** * Creates an instance of the default event loop implementation for the current architecture and operating system using * extendable options. - * + * * Please note the event loop type defined in the options will be ignored. */ AWS_IO_API diff --git a/source/event_loop.c b/source/event_loop.c index 4259b0bd2..bcb288fa4 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -74,12 +74,12 @@ struct aws_event_loop *aws_event_loop_new_with_options( return NULL; } -// TODO: DISPATCH QUEUE will be implemented later. +// TODO: DISPATCH QUEUE will be implemented later. struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { - (void) alloc; - (void) options; + (void)alloc; + (void)options; AWS_ASSERT("DISPATCH QUEUE IS NOT SUPPORTED YET" == NULL); return NULL; } @@ -197,10 +197,7 @@ struct aws_event_loop_group *aws_event_loop_group_new_internal( struct aws_thread_options thread_options = *aws_default_thread_options(); struct aws_event_loop_options el_options = { - .clock = clock, - .thread_options = &thread_options, - .type = options->type - }; + .clock = clock, .thread_options = &thread_options, .type = options->type}; if (pin_threads) { thread_options.cpu_id = usable_cpus[i].cpu_id; From 7a89d9e5029cd9bd3e71c06d3c3fc1b9920e0dc4 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 7 Nov 2024 09:24:13 -0800 Subject: [PATCH 15/72] revert shutdown_types? --- source/exponential_backoff_retry_strategy.c | 2 +- tests/standard_retry_test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/exponential_backoff_retry_strategy.c b/source/exponential_backoff_retry_strategy.c index 2110cbd46..f256c0126 100644 --- a/source/exponential_backoff_retry_strategy.c +++ b/source/exponential_backoff_retry_strategy.c @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include diff --git a/tests/standard_retry_test.c b/tests/standard_retry_test.c index 11991a3e0..3811e7937 100644 --- a/tests/standard_retry_test.c +++ b/tests/standard_retry_test.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include From 56fa4d11b90c78fa8d928eb8f859f85374f43e0c Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 7 Nov 2024 09:46:23 -0800 Subject: [PATCH 16/72] rename cmake flags --- CMakeLists.txt | 2 +- include/aws/io/private/event_loop_impl.h | 7 +- source/event_loop.c | 94 ++++++++++++++++-------- tests/event_loop_test.c | 6 +- 4 files changed, 70 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0f030b98..9adb1c145 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,7 +187,7 @@ aws_add_sanitizers(${PROJECT_NAME}) # We are not ABI stable yet set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0) -target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_USE_${EVENT_LOOP_DEFINE}") +target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_ENABLE_${EVENT_LOOP_DEFINE}") if (BYO_CRYPTO) target_compile_definitions(${PROJECT_NAME} PUBLIC "-DBYO_CRYPTO") diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 6a7c49149..9f86ac2e6 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -153,7 +153,7 @@ struct aws_event_loop_group { AWS_EXTERN_C_BEGIN -#ifdef AWS_USE_IO_COMPLETION_PORTS +#ifdef AWS_ENABLE_IO_COMPLETION_PORTS /** * Prepares aws_overlapped for use, and sets a function to call when the overlapped operation completes. @@ -176,6 +176,7 @@ void aws_overlapped_reset(struct aws_overlapped *overlapped); */ AWS_IO_API struct _OVERLAPPED *aws_overlapped_to_windows_overlapped(struct aws_overlapped *overlapped); +#endif /* AWS_ENABLE_IO_COMPLETION_PORTS */ /** * Associates an aws_io_handle with the event loop's I/O Completion Port. @@ -192,8 +193,6 @@ int aws_event_loop_connect_handle_to_io_completion_port( struct aws_event_loop *event_loop, struct aws_io_handle *handle); -#else - /** * Subscribes on_event to events on the event-loop for handle. events is a bitwise concatenation of the events that were * received. The definition for these values can be found in aws_io_event_type. Currently, only @@ -209,8 +208,6 @@ int aws_event_loop_subscribe_to_io_events( aws_event_loop_on_event_fn *on_event, void *user_data); -#endif /* AWS_USE_IO_COMPLETION_PORTS */ - /** * Creates an instance of the default event loop implementation for the current architecture and operating system. */ diff --git a/source/event_loop.c b/source/event_loop.c index bcb288fa4..380a7dcf2 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -74,16 +74,6 @@ struct aws_event_loop *aws_event_loop_new_with_options( return NULL; } -// TODO: DISPATCH QUEUE will be implemented later. -struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options) { - (void)alloc; - (void)options; - AWS_ASSERT("DISPATCH QUEUE IS NOT SUPPORTED YET" == NULL); - return NULL; -} - static void s_event_loop_group_thread_exit(void *user_data) { struct aws_event_loop_group *el_group = user_data; @@ -505,17 +495,16 @@ void aws_event_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_ta event_loop->vtable->cancel_task(event_loop, task); } -#if AWS_USE_IO_COMPLETION_PORTS - int aws_event_loop_connect_handle_to_io_completion_port( struct aws_event_loop *event_loop, struct aws_io_handle *handle) { - AWS_ASSERT(event_loop->vtable && event_loop->vtable->connect_to_io_completion_port); - return event_loop->vtable->connect_to_io_completion_port(event_loop, handle); -} + if (event_loop->vtable && event_loop->vtable->connect_to_io_completion_port) { + return event_loop->vtable->connect_to_io_completion_port(event_loop, handle); + } -#else /* !AWS_USE_IO_COMPLETION_PORTS */ + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); +} int aws_event_loop_subscribe_to_io_events( struct aws_event_loop *event_loop, @@ -524,10 +513,11 @@ int aws_event_loop_subscribe_to_io_events( aws_event_loop_on_event_fn *on_event, void *user_data) { - AWS_ASSERT(event_loop->vtable && event_loop->vtable->subscribe_to_io_events); - return event_loop->vtable->subscribe_to_io_events(event_loop, handle, events, on_event, user_data); + if (event_loop->vtable && event_loop->vtable->subscribe_to_io_events) { + return event_loop->vtable->subscribe_to_io_events(event_loop, handle, events, on_event, user_data); + } + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); } -#endif /* AWS_USE_IO_COMPLETION_PORTS */ int aws_event_loop_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struct aws_io_handle *handle) { AWS_ASSERT(aws_event_loop_thread_is_callers_thread(event_loop)); @@ -558,13 +548,13 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { #ifdef AWS_OS_WINDOWS return AWS_ELT_IOCP; #endif -#ifdef AWS_USE_KQUEUE +#ifdef AWS_ENABLE_KQUEUE return AWS_ELT_KQUEUE; #endif -#ifdef AWS_USE_DISPATCH_QUEUE +#ifdef AWS_ENABLE_DISPATCH_QUEUE return AWS_ELT_DISPATCH_QUEUE; #endif -#ifdef AWS_USE_EPOLL +#ifdef AWS_ENABLE_EPOLL return AWS_ELT_DISPATCH_QUEUE; #endif } @@ -572,28 +562,28 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { static int aws_event_loop_validate_platform(enum aws_event_loop_type type) { switch (type) { case AWS_ELT_EPOLL: -#ifndef AWS_USE_EPOLL +#ifndef AWS_ENABLE_EPOLL AWS_ASSERT("Event loop type EPOLL is not supported on the platform." == NULL); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); -#endif // AWS_USE_EPOLL +#endif // AWS_ENABLE_EPOLL break; case AWS_ELT_IOCP: -#ifndef AWS_USE_IO_COMPLETION_PORTS +#ifndef AWS_ENABLE_IO_COMPLETION_PORTS AWS_ASSERT("Event loop type IOCP is not supported on the platform." == NULL); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); -#endif // AWS_USE_IO_COMPLETION_PORTS +#endif // AWS_ENABLE_IO_COMPLETION_PORTS break; case AWS_ELT_KQUEUE: -#ifndef AWS_USE_KQUEUE +#ifndef AWS_ENABLE_KQUEUE AWS_ASSERT("Event loop type KQUEUE is not supported on the platform." == NULL); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); -#endif // AWS_USE_KQUEUE +#endif // AWS_ENABLE_KQUEUE break; case AWS_ELT_DISPATCH_QUEUE: -#ifndef AWS_USE_DISPATCH_QUEUE +#ifndef AWS_ENABLE_DISPATCH_QUEUE AWS_ASSERT("Event loop type Dispatch Queue is not supported on the platform." == NULL); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); -#endif // AWS_USE_DISPATCH_QUEUE +#endif // AWS_ENABLE_DISPATCH_QUEUE break; default: AWS_ASSERT("Invalid event loop type." == NULL); @@ -602,3 +592,47 @@ static int aws_event_loop_validate_platform(enum aws_event_loop_type type) { } return AWS_OP_SUCCESS; } + +#ifndef AWS_ENABLE_DISPATCH_QUEUE +struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + (void)alloc; + (void)options; + AWS_ASSERT("Dispatch Queue is not supported on the platform" == NULL); + return NULL; +} +#endif // AWS_ENABLE_DISPATCH_QUEUE + +#ifndef AWS_ENABLE_IO_COMPLETION_PORTS +struct aws_event_loop *aws_event_loop_new_iocp_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + (void)alloc; + (void)options; + AWS_ASSERT("IOCP is not supported on the platform" == NULL); + return NULL; +} +#endif // AWS_ENABLE_IO_COMPLETION_PORTS + +#ifndef AWS_ENABLE_KQUEUE +struct aws_event_loop *aws_event_loop_new_kqueue_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + (void)alloc; + (void)options; + AWS_ASSERT("Kqueue is not supported on the platform" == NULL); + return NULL; +} +#endif // AWS_ENABLE_EPOLL + +#ifndef AWS_ENABLE_EPOLL +struct aws_event_loop *aws_event_loop_new_epoll_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + (void)alloc; + (void)options; + AWS_ASSERT("Epoll is not supported on the platform" == NULL); + return NULL; +} +#endif // AWS_ENABLE_KQUEUE diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index 737f0a0f7..e28103288 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -172,7 +172,7 @@ static int s_test_event_loop_canceled_tasks_run_in_el_thread(struct aws_allocato AWS_TEST_CASE(event_loop_canceled_tasks_run_in_el_thread, s_test_event_loop_canceled_tasks_run_in_el_thread) -#if AWS_USE_IO_COMPLETION_PORTS +#if AWS_ENABLE_IO_COMPLETION_PORTS int aws_pipe_get_unique_name(char *dst, size_t dst_size); @@ -311,7 +311,7 @@ static int s_test_event_loop_completion_events(struct aws_allocator *allocator, AWS_TEST_CASE(event_loop_completion_events, s_test_event_loop_completion_events) -#else /* !AWS_USE_IO_COMPLETION_PORTS */ +#else /* !AWS_ENABLE_IO_COMPLETION_PORTS */ # include @@ -971,7 +971,7 @@ static int s_test_event_loop_readable_event_on_2nd_time_readable(struct aws_allo } AWS_TEST_CASE(event_loop_readable_event_on_2nd_time_readable, s_test_event_loop_readable_event_on_2nd_time_readable); -#endif /* AWS_USE_IO_COMPLETION_PORTS */ +#endif /* AWS_ENABLE_IO_COMPLETION_PORTS */ static int s_event_loop_test_stop_then_restart(struct aws_allocator *allocator, void *ctx) { (void)ctx; From c1a4971e9dbc52c4ac44c79e7734f57203745c40 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 7 Nov 2024 10:06:28 -0800 Subject: [PATCH 17/72] fix default event loop --- source/event_loop.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/event_loop.c b/source/event_loop.c index 380a7dcf2..3a4dd8a3c 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -21,7 +21,7 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a .type = AWS_ELT_PLATFORM_DEFAULT, }; - return aws_event_loop_new_default_with_options(alloc, &options); + return aws_event_loop_new_with_options(alloc, &options); } struct aws_event_loop *aws_event_loop_new_default_with_options( @@ -555,7 +555,7 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { return AWS_ELT_DISPATCH_QUEUE; #endif #ifdef AWS_ENABLE_EPOLL - return AWS_ELT_DISPATCH_QUEUE; + return AWS_ELT_EPOLL; #endif } @@ -563,30 +563,30 @@ static int aws_event_loop_validate_platform(enum aws_event_loop_type type) { switch (type) { case AWS_ELT_EPOLL: #ifndef AWS_ENABLE_EPOLL - AWS_ASSERT("Event loop type EPOLL is not supported on the platform." == NULL); + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type EPOLL is not supported on the platform."); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); #endif // AWS_ENABLE_EPOLL break; case AWS_ELT_IOCP: #ifndef AWS_ENABLE_IO_COMPLETION_PORTS - AWS_ASSERT("Event loop type IOCP is not supported on the platform." == NULL); + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type IOCP is not supported on the platform."); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); #endif // AWS_ENABLE_IO_COMPLETION_PORTS break; case AWS_ELT_KQUEUE: #ifndef AWS_ENABLE_KQUEUE - AWS_ASSERT("Event loop type KQUEUE is not supported on the platform." == NULL); + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type KQUEUE is not supported on the platform."); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); #endif // AWS_ENABLE_KQUEUE break; case AWS_ELT_DISPATCH_QUEUE: #ifndef AWS_ENABLE_DISPATCH_QUEUE - AWS_ASSERT("Event loop type Dispatch Queue is not supported on the platform." == NULL); + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type Dispatch Queue is not supported on the platform."); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); #endif // AWS_ENABLE_DISPATCH_QUEUE break; default: - AWS_ASSERT("Invalid event loop type." == NULL); + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type."); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); break; } From 470164be56994355d0d06c63df71f6b084d7813f Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 7 Nov 2024 10:19:19 -0800 Subject: [PATCH 18/72] improve error message --- source/event_loop.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/source/event_loop.c b/source/event_loop.c index 3a4dd8a3c..18b01ec7a 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -599,7 +599,9 @@ struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( const struct aws_event_loop_options *options) { (void)alloc; (void)options; - AWS_ASSERT("Dispatch Queue is not supported on the platform" == NULL); + AWS_ASSERT(0); + + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Dispatch Queue is not supported on the platform"); return NULL; } #endif // AWS_ENABLE_DISPATCH_QUEUE @@ -610,7 +612,9 @@ struct aws_event_loop *aws_event_loop_new_iocp_with_options( const struct aws_event_loop_options *options) { (void)alloc; (void)options; - AWS_ASSERT("IOCP is not supported on the platform" == NULL); + AWS_ASSERT(0); + + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "IOCP is not supported on the platform"); return NULL; } #endif // AWS_ENABLE_IO_COMPLETION_PORTS @@ -621,7 +625,9 @@ struct aws_event_loop *aws_event_loop_new_kqueue_with_options( const struct aws_event_loop_options *options) { (void)alloc; (void)options; - AWS_ASSERT("Kqueue is not supported on the platform" == NULL); + AWS_ASSERT(0); + + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Kqueue is not supported on the platform"); return NULL; } #endif // AWS_ENABLE_EPOLL @@ -632,7 +638,9 @@ struct aws_event_loop *aws_event_loop_new_epoll_with_options( const struct aws_event_loop_options *options) { (void)alloc; (void)options; - AWS_ASSERT("Epoll is not supported on the platform" == NULL); + AWS_ASSERT(0); + + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Epoll is not supported on the platform"); return NULL; } #endif // AWS_ENABLE_KQUEUE From 9e6d574908f0b70aa63bf7f0571740a9df16106b Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Thu, 7 Nov 2024 11:07:12 -0800 Subject: [PATCH 19/72] Update based on PR feedback: --- include/aws/io/event_loop.h | 54 ++++++++++++++++++------ include/aws/io/private/event_loop_impl.h | 1 - source/event_loop.c | 38 ++++++++++++++--- tests/channel_test.c | 4 +- tests/default_host_resolver_test.c | 48 +++++++++++++++------ tests/event_loop_test.c | 11 +++-- tests/exponential_backoff_retry_test.c | 20 ++++++--- tests/pkcs11_test.c | 4 +- tests/socket_handler_test.c | 8 ++-- tests/socket_test.c | 12 ++++-- tests/tls_handler_test.c | 16 ++++--- 11 files changed, 160 insertions(+), 56 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 12ee1d04e..f953ae04d 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -15,17 +15,6 @@ struct aws_event_loop_group; struct aws_shutdown_callback_options; struct aws_task; -/** - * Configuration to pin an event loop group to a particular CPU group - */ -struct aws_event_loop_group_pin_options { - - /** - * CPU group id that threads in this event loop group should be bound to - */ - uint16_t cpu_group; -}; - /** * Event loop group configuration options */ @@ -40,12 +29,20 @@ struct aws_event_loop_group_options { /** * Optional callback to invoke when the event loop group finishes destruction. */ - struct aws_shutdown_callback_options *shutdown_options; + const struct aws_shutdown_callback_options *shutdown_options; /** * Optional configuration to control how the event loop group's threads bind to CPU groups */ - struct aws_event_loop_group_pin_options *pin_options; + uint16_t *cpu_group; + + /** + * Override for the clock function that event loops should use. Defaults to the system's high resolution + * timer. + * + * Do not bind this value to managed code; it is only used in timing-sensitive tests. + */ + aws_io_clock_fn *clock_override; }; AWS_EXTERN_C_BEGIN @@ -138,6 +135,37 @@ size_t aws_event_loop_group_get_loop_count(struct aws_event_loop_group *el_group AWS_IO_API struct aws_event_loop *aws_event_loop_group_get_next_loop(struct aws_event_loop_group *el_group); +/** + * Initializes an event loop group with platform defaults. If max_threads == 0, then the + * loop count will be the number of available processors on the machine / 2 (to exclude hyper-threads). + * Otherwise, max_threads will be the number of event loops in the group. + * + * @deprecated - use aws_event_loop_group_new() instead + */ +AWS_IO_API +struct aws_event_loop_group *aws_event_loop_group_new_default( + struct aws_allocator *alloc, + uint16_t max_threads, + const struct aws_shutdown_callback_options *shutdown_options); + +/** Creates an event loop group, with clock, number of loops to manage, the function to call for creating a new + * event loop, and also pins all loops to hw threads on the same cpu_group (e.g. NUMA nodes). Note: + * If el_count exceeds the number of hw threads in the cpu_group it will be clamped to the number of hw threads + * on the assumption that if you care about NUMA, you don't want hyper-threads doing your IO and you especially + * don't want IO on a different node. + * + * If max_threads == 0, then the + * loop count will be the number of available processors in the cpu_group / 2 (to exclude hyper-threads) + * + * @deprecated - use aws_event_loop_group_new() instead + */ +AWS_IO_API +struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( + struct aws_allocator *alloc, + uint16_t max_threads, + uint16_t cpu_group, + const struct aws_shutdown_callback_options *shutdown_options); + AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 4935f8679..e852aba82 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -331,7 +331,6 @@ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new_internal( struct aws_allocator *allocator, const struct aws_event_loop_group_options *options, - aws_io_clock_fn *clock_override, aws_new_event_loop_fn *new_loop_fn, void *new_loop_user_data); diff --git a/source/event_loop.c b/source/event_loop.c index 82b1c9b56..e11af4844 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -78,12 +78,11 @@ static void s_aws_event_loop_group_shutdown_async(struct aws_event_loop_group *e struct aws_event_loop_group *aws_event_loop_group_new_internal( struct aws_allocator *allocator, const struct aws_event_loop_group_options *options, - aws_io_clock_fn *clock_override, aws_new_event_loop_fn *new_loop_fn, void *new_loop_user_data) { AWS_FATAL_ASSERT(new_loop_fn); - aws_io_clock_fn *clock = clock_override; + aws_io_clock_fn *clock = options->clock_override; if (!clock) { clock = aws_high_res_clock_get_ticks; } @@ -91,9 +90,9 @@ struct aws_event_loop_group *aws_event_loop_group_new_internal( size_t group_cpu_count = 0; struct aws_cpu_info *usable_cpus = NULL; - bool pin_threads = options->pin_options != NULL; + bool pin_threads = options->cpu_group != NULL; if (pin_threads) { - uint16_t cpu_group = options->pin_options->cpu_group; + uint16_t cpu_group = *options->cpu_group; group_cpu_count = aws_get_cpu_count_for_group(cpu_group); if (!group_cpu_count) { // LOG THIS @@ -203,8 +202,7 @@ struct aws_event_loop_group *aws_event_loop_group_new( struct aws_allocator *allocator, const struct aws_event_loop_group_options *options) { - return aws_event_loop_group_new_internal( - allocator, options, aws_high_res_clock_get_ticks, s_default_new_event_loop, NULL); + return aws_event_loop_group_new_internal(allocator, options, s_default_new_event_loop, NULL); } struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group) { @@ -489,3 +487,31 @@ int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_ AWS_ASSERT(event_loop->clock); return event_loop->clock(time_nanos); } + +struct aws_event_loop_group *aws_event_loop_group_new_default( + struct aws_allocator *alloc, + uint16_t max_threads, + const struct aws_shutdown_callback_options *shutdown_options) { + + struct aws_event_loop_group_options elg_options = { + .loop_count = max_threads, + .shutdown_options = shutdown_options, + }; + + return aws_event_loop_group_new(alloc, &elg_options); +} + +struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( + struct aws_allocator *alloc, + uint16_t max_threads, + uint16_t cpu_group, + const struct aws_shutdown_callback_options *shutdown_options) { + + struct aws_event_loop_group_options elg_options = { + .loop_count = max_threads, + .shutdown_options = shutdown_options, + .cpu_group = &cpu_group, + }; + + return aws_event_loop_group_new(alloc, &elg_options); +} diff --git a/tests/channel_test.c b/tests/channel_test.c index 995d83add..8fc530f99 100644 --- a/tests/channel_test.c +++ b/tests/channel_test.c @@ -685,7 +685,9 @@ static int s_test_channel_connect_some_hosts_timeout(struct aws_allocator *alloc .shutdown = false, }; - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); /* resolve our s3 test bucket and an EC2 host with an ACL that blackholes the connection */ diff --git a/tests/default_host_resolver_test.c b/tests/default_host_resolver_test.c index 5f9ba3734..f47b346bf 100644 --- a/tests/default_host_resolver_test.c +++ b/tests/default_host_resolver_test.c @@ -96,7 +96,9 @@ static int s_test_default_with_ipv6_lookup_fn(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -190,7 +192,9 @@ static int s_test_default_host_resolver_ipv6_address_variations_fn(struct aws_al }; - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -265,7 +269,9 @@ static int s_test_default_with_ipv4_only_lookup_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -336,7 +342,9 @@ static int s_test_default_with_multiple_lookups_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -464,7 +472,9 @@ static int s_test_resolver_ttls_fn(struct aws_allocator *allocator, void *ctx) { s_set_time(0); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -677,7 +687,9 @@ static int s_test_resolver_connect_failure_recording_fn(struct aws_allocator *al aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -870,7 +882,9 @@ static int s_test_resolver_ttl_refreshes_on_resolve_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1051,7 +1065,9 @@ static int s_test_resolver_ipv4_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1113,7 +1129,9 @@ static int s_test_resolver_purge_host_cache(struct aws_allocator *allocator, voi (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1229,7 +1247,9 @@ static int s_test_resolver_purge_cache(struct aws_allocator *allocator, void *ct (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1379,7 +1399,9 @@ static int s_test_resolver_ipv6_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -1442,7 +1464,9 @@ static int s_test_resolver_low_frequency_starvation_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index 737f0a0f7..caa276f0e 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -1041,7 +1041,9 @@ static int test_event_loop_group_setup_and_shutdown(struct aws_allocator *alloca (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 0}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); size_t cpu_count = aws_system_info_processor_count(); @@ -1077,13 +1079,10 @@ static int test_numa_aware_event_loop_group_setup_and_shutdown(struct aws_alloca /* pass UINT16_MAX here to check the boundary conditions on numa cpu detection. It should never create more threads * than hw cpus available */ - struct aws_event_loop_group_pin_options pin_options = { - .cpu_group = 0, - }; - + uint16_t cpu_group = 0; struct aws_event_loop_group_options elg_options = { .loop_count = UINT16_MAX, - .pin_options = &pin_options, + .cpu_group = &cpu_group, }; struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); diff --git a/tests/exponential_backoff_retry_test.c b/tests/exponential_backoff_retry_test.c index f36c5c5e0..779a4f50f 100644 --- a/tests/exponential_backoff_retry_test.c +++ b/tests/exponential_backoff_retry_test.c @@ -66,7 +66,9 @@ static int s_test_exponential_backoff_retry_too_many_retries_for_jitter_mode( aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, @@ -158,7 +160,9 @@ static int s_test_exponential_backoff_retry_client_errors_do_not_count_fn(struct aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .el_group = el_group, @@ -203,7 +207,9 @@ static int s_test_exponential_backoff_retry_no_jitter_time_taken_fn(struct aws_a aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, @@ -256,7 +262,9 @@ static int s_test_exponential_max_backoff_retry_no_jitter_fn(struct aws_allocato aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, @@ -314,7 +322,9 @@ static int s_test_exponential_backoff_retry_invalid_options_fn(struct aws_alloca aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 64, diff --git a/tests/pkcs11_test.c b/tests/pkcs11_test.c index c15e0cd9c..4af9d0fb0 100644 --- a/tests/pkcs11_test.c +++ b/tests/pkcs11_test.c @@ -1653,7 +1653,9 @@ static int s_test_pkcs11_tls_negotiation_succeeds_common( ASSERT_SUCCESS(aws_mutex_init(&s_tls_tester.synced.mutex)); ASSERT_SUCCESS(aws_condition_variable_init(&s_tls_tester.synced.cvar)); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); ASSERT_NOT_NULL(event_loop_group); diff --git a/tests/socket_handler_test.c b/tests/socket_handler_test.c index af9b28473..6067b80b6 100644 --- a/tests/socket_handler_test.c +++ b/tests/socket_handler_test.c @@ -1009,9 +1009,11 @@ static int s_socket_common_tester_statistics_init( AWS_ZERO_STRUCT(*tester); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; - tester->el_group = aws_event_loop_group_new_internal( - allocator, &elg_options, s_statistic_test_clock_fn, s_default_new_event_loop, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + .clock_override = s_statistic_test_clock_fn, + }; + tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_default_new_event_loop, NULL); struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; diff --git a/tests/socket_test.c b/tests/socket_test.c index d930600c6..e01834a75 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -625,7 +625,9 @@ static int s_test_connect_timeout(struct aws_allocator *allocator, void *ctx) { aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -706,7 +708,9 @@ static int s_test_connect_timeout_cancelation(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -1150,7 +1154,9 @@ static int s_cleanup_before_connect_or_timeout_doesnt_explode(struct aws_allocat aws_io_library_init(allocator); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); diff --git a/tests/tls_handler_test.c b/tests/tls_handler_test.c index 10778a245..7b1a68c32 100644 --- a/tests/tls_handler_test.c +++ b/tests/tls_handler_test.c @@ -178,7 +178,9 @@ static int s_tls_common_tester_init(struct aws_allocator *allocator, struct tls_ aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - struct aws_event_loop_group_options elg_options = {.loop_count = 0}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { @@ -535,7 +537,9 @@ static int s_tls_channel_server_client_tester_init(struct aws_allocator *allocat ASSERT_SUCCESS(aws_mutex_init(&s_server_client_tester.server_mutex)); ASSERT_SUCCESS(aws_condition_variable_init(&s_server_client_tester.server_condition_variable)); - struct aws_event_loop_group_options elg_options = {.loop_count = 0}; + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; s_server_client_tester.client_el_group = aws_event_loop_group_new(allocator, &elg_options); ASSERT_SUCCESS(s_tls_rw_args_init( @@ -1908,9 +1912,11 @@ static int s_tls_common_tester_statistics_init(struct aws_allocator *allocator, aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - struct aws_event_loop_group_options elg_options = {.loop_count = 1}; - tester->el_group = aws_event_loop_group_new_internal( - allocator, &elg_options, s_statistic_test_clock_fn, s_default_new_event_loop, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + .clock_override = s_statistic_test_clock_fn, + }; + tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_default_new_event_loop, NULL); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, From eab14fa53f96af03c2b9830df40a366a33d08a0c Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 7 Nov 2024 12:53:02 -0800 Subject: [PATCH 20/72] fix header update --- .github/workflows/ci.yml | 4 ++-- CMakeLists.txt | 21 ++++++++--------- include/aws/io/io.h | 4 ---- source/darwin/dispatch_queue_event_loop.c | 28 +++++++++++------------ source/event_loop.c | 4 +++- source/windows/iocp/iocp_event_loop.c | 2 +- tests/CMakeLists.txt | 4 ++-- tests/event_loop_test.c | 6 ++--- 8 files changed, 34 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 986685b5c..6daefec60 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -160,7 +160,7 @@ jobs: runs-on: macos-14 # latest strategy: matrix: - eventloop: ["-DAWS_USE_DISPATCH_QUEUE=ON", "-DAWS_USE_DISPATCH_QUEUE=OFF"] + eventloop: ["-DAWS_ENABLE_DISPATCH_QUEUE=ON", "-DAWS_ENABLE_DISPATCH_QUEUE=OFF"] steps: - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | @@ -181,7 +181,7 @@ jobs: runs-on: macos-14 # latest strategy: matrix: - eventloop: ["-DAWS_USE_DISPATCH_QUEUE=ON", "-DAWS_USE_DISPATCH_QUEUE=OFF"] + eventloop: ["-DAWS_ENABLE_DISPATCH_QUEUE=ON", "-DAWS_ENABLE_DISPATCH_QUEUE=OFF"] steps: - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index c7763aeda..cb1e7d4e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,10 +110,7 @@ elseif (APPLE) ) file(GLOB AWS_IO_OS_SRC - "source/bsd/*.c" - "source/posix/*.c" - "source/darwin/darwin_pki_utils.c" - "source/darwin/secure_transport_tls_channel_handler.c" + "source/darwin/*.c" ) find_library(SECURITY_LIB Security) @@ -129,14 +126,16 @@ elseif (APPLE) #No choice on TLS for apple, darwinssl will always be used. list(APPEND PLATFORM_LIBS "-framework Security -framework Network") - if(AWS_USE_DISPATCH_QUEUE OR IOS) - set(EVENT_LOOP_DEFINES "DISPATCH_QUEUE" ) - message("use dispatch queue") - file(GLOB AWS_IO_DISPATCH_QUEUE_SRC - "source/darwin/dispatch_queue_event_loop.c" + set(EVENT_LOOP_DEFINES "DISPATCH_QUEUE" ) + message("Enable dispatch queue") + + # Enable KQUEUE on OSX + if(OSX) + file(GLOB AWS_IO_KUEUE_SRC + "source/bsd/*.c" + "source/posix/*.c" ) - list(APPEND AWS_IO_OS_SRC ${AWS_IO_DISPATCH_QUEUE_SRC}) - else () + list(APPEND AWS_IO_OS_SRC ${AWS_IO_KUEUE_SRC}) set(EVENT_LOOP_DEFINE "KQUEUE") endif() diff --git a/include/aws/io/io.h b/include/aws/io/io.h index 832a46b21..a9cc2618b 100644 --- a/include/aws/io/io.h +++ b/include/aws/io/io.h @@ -16,10 +16,8 @@ AWS_PUSH_SANE_WARNING_LEVEL struct aws_io_handle; -#ifdef AWS_USE_DISPATCH_QUEUE typedef void aws_io_set_queue_on_handle_fn(struct aws_io_handle *handle, void *queue); typedef void aws_io_clear_queue_on_handle_fn(struct aws_io_handle *handle); -#endif /* AWS_USE_DISPATCH_QUEUE */ struct aws_io_handle { union { @@ -28,10 +26,8 @@ struct aws_io_handle { void *handle; } data; void *additional_data; -#ifdef AWS_USE_DISPATCH_QUEUE aws_io_set_queue_on_handle_fn *set_queue; aws_io_clear_queue_on_handle_fn *clear_queue; -#endif /* AWS_USE_DISPATCH_QUEUE */ }; enum aws_io_message_type { diff --git a/source/darwin/dispatch_queue_event_loop.c b/source/darwin/dispatch_queue_event_loop.c index 7e2679127..8bb7b50c9 100644 --- a/source/darwin/dispatch_queue_event_loop.c +++ b/source/darwin/dispatch_queue_event_loop.c @@ -2,23 +2,23 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ -#ifdef AWS_USE_DISPATCH_QUEUE -# include +#include +#include -# include -# include -# include -# include +#include +#include +#include +#include -# include +#include -# include +#include -# include -# include -# include -# include +#include +#include +#include +#include static void s_destroy(struct aws_event_loop *event_loop); static int s_run(struct aws_event_loop *event_loop); @@ -42,7 +42,7 @@ static struct aws_event_loop_vtable s_vtable = { .schedule_task_now = s_schedule_task_now, .schedule_task_future = s_schedule_task_future, .cancel_task = s_cancel_task, - .connect_to_completion_port = s_connect_to_dispatch_queue, + .connect_to_io_completion_port = s_connect_to_dispatch_queue, .unsubscribe_from_io_events = s_unsubscribe_from_io_events, .free_io_event_resources = s_free_io_event_resources, .is_on_callers_thread = s_is_on_callers_thread, @@ -498,5 +498,3 @@ static bool s_is_on_callers_thread(struct aws_event_loop *event_loop) { aws_mutex_unlock(&dispatch_queue->synced_data.lock); return result; } - -#endif /* AWS_USE_DISPATCH_QUEUE */ diff --git a/source/event_loop.c b/source/event_loop.c index 18b01ec7a..5de06c456 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -548,6 +548,7 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { #ifdef AWS_OS_WINDOWS return AWS_ELT_IOCP; #endif +// If both kqueue and dispatch queue is enabled, default to kqueue #ifdef AWS_ENABLE_KQUEUE return AWS_ELT_KQUEUE; #endif @@ -557,6 +558,7 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { #ifdef AWS_ENABLE_EPOLL return AWS_ELT_EPOLL; #endif + return AWS_ELT_PLATFORM_DEFAULT; } static int aws_event_loop_validate_platform(enum aws_event_loop_type type) { @@ -600,7 +602,7 @@ struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( (void)alloc; (void)options; AWS_ASSERT(0); - + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Dispatch Queue is not supported on the platform"); return NULL; } diff --git a/source/windows/iocp/iocp_event_loop.c b/source/windows/iocp/iocp_event_loop.c index 6cd46b23a..473629de9 100644 --- a/source/windows/iocp/iocp_event_loop.c +++ b/source/windows/iocp/iocp_event_loop.c @@ -138,7 +138,7 @@ struct aws_event_loop_vtable s_iocp_vtable = { .schedule_task_now = s_schedule_task_now, .schedule_task_future = s_schedule_task_future, .cancel_task = s_cancel_task, - .connect_to_completion_port = s_connect_to_io_completion_port, + .connect_to_io_completion_port = s_connect_to_io_completion_port, .is_on_callers_thread = s_is_event_thread, .unsubscribe_from_io_events = s_unsubscribe_from_io_events, .free_io_event_resources = s_free_io_event_resources, diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a15cd94d6..edceafb23 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,7 +18,7 @@ add_test_case(io_library_init) add_test_case(io_library_init_cleanup_init_cleanup) # DEBUG: temporarily disable the pipe related tests -if(NOT AWS_USE_DISPATCH_QUEUE) +if(NOT AWS_TEST_DISPATCH_QUEUE) add_pipe_test_case(pipe_open_close) add_pipe_test_case(pipe_read_write) add_pipe_test_case(pipe_read_write_large_buffer) @@ -39,7 +39,7 @@ add_test_case(event_loop_canceled_tasks_run_in_el_thread) if(USE_IO_COMPLETION_PORTS) add_test_case(event_loop_completion_events) -elseif(NOT AWS_USE_DISPATCH_QUEUE) # TODO: setup a test for dispatch queue once pipe is there. +elseif(NOT AWS_TEST_DISPATCH_QUEUE) # TODO: setup a test for dispatch queue once pipe is there. add_test_case(event_loop_subscribe_unsubscribe) add_test_case(event_loop_writable_event_on_subscribe) add_test_case(event_loop_no_readable_event_before_write) diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index a9e5da9da..3bc1d4a32 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -80,7 +80,7 @@ static int s_test_event_loop_xthread_scheduled_tasks_execute(struct aws_allocato // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, // therefore we do not validate the thread id for dispatch queue. -#ifndef AWS_USE_DISPATCH_QUEUE +#ifndef AWS_TEST_DISPATCH_QUEUE ASSERT_FALSE(aws_thread_thread_id_equal(task_args.thread_id, aws_thread_current_thread_id())); #endif @@ -156,7 +156,7 @@ static int s_test_event_loop_canceled_tasks_run_in_el_thread(struct aws_allocato ASSERT_TRUE(task1_args.was_in_thread); // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, // therefore we do not validate the thread id for dispatch queue. -#ifndef AWS_USE_DISPATCH_QUEUE +#ifndef AWS_TEST_DISPATCH_QUEUE ASSERT_FALSE(aws_thread_thread_id_equal(task1_args.thread_id, aws_thread_current_thread_id())); #endif ASSERT_INT_EQUALS(AWS_TASK_STATUS_RUN_READY, task1_args.status); @@ -174,7 +174,7 @@ static int s_test_event_loop_canceled_tasks_run_in_el_thread(struct aws_allocato ASSERT_TRUE(task2_args.was_in_thread); // The dispatch queue will schedule tasks on thread pools, it is unpredictable which thread we run the task on, // therefore we do not validate the thread id for dispatch queue. -#ifndef AWS_USE_DISPATCH_QUEUE +#ifndef AWS_TEST_DISPATCH_QUEUE ASSERT_TRUE(aws_thread_thread_id_equal(task2_args.thread_id, aws_thread_current_thread_id())); #endif ASSERT_INT_EQUALS(AWS_TASK_STATUS_CANCELED, task2_args.status); From 9323cc38734f61cebf4695d7977116b696bd8823 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Thu, 7 Nov 2024 14:16:19 -0800 Subject: [PATCH 21/72] Make io testing channel usable across library boundaries --- include/aws/io/event_loop.h | 53 ++++++++++++++++++++++++ include/aws/io/private/event_loop_impl.h | 44 +------------------- include/aws/testing/io_testing_channel.h | 27 ++++++------ source/event_loop.c | 17 ++++++++ 4 files changed, 83 insertions(+), 58 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index f953ae04d..093e632f5 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -15,6 +15,32 @@ struct aws_event_loop_group; struct aws_shutdown_callback_options; struct aws_task; +typedef void(aws_event_loop_on_event_fn)( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + void *user_data); + +struct aws_event_loop_vtable { + void (*destroy)(struct aws_event_loop *event_loop); + int (*run)(struct aws_event_loop *event_loop); + int (*stop)(struct aws_event_loop *event_loop); + int (*wait_for_stop_completion)(struct aws_event_loop *event_loop); + void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); + void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); + void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); + int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + int (*subscribe_to_io_events)( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + aws_event_loop_on_event_fn *on_event, + void *user_data); + int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + void (*free_io_event_resources)(void *user_data); + bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); +}; + /** * Event loop group configuration options */ @@ -166,6 +192,33 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou uint16_t cpu_group, const struct aws_shutdown_callback_options *shutdown_options); +AWS_IO_API +void *aws_event_loop_get_impl(struct aws_event_loop *event_loop); + +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_base( + struct aws_allocator *allocator, + aws_io_clock_fn *clock, + struct aws_event_loop_vtable *vtable, + void *impl); + +/** + * Common cleanup code for all implementations. + * This is only called from the *destroy() function of event loop implementations. + */ +AWS_IO_API +void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); + +/** + * Invokes the destroy() fn for the event loop implementation. + * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. + * If you do not want this function to block, call aws_event_loop_stop() manually first. + * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads + * must ensure their API calls to the event loop happen-before the call to destroy. + */ +AWS_IO_API +void aws_event_loop_destroy(struct aws_event_loop *event_loop); + AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index e852aba82..4eb2f6230 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -11,6 +11,7 @@ #include #include #include +#include AWS_PUSH_SANE_WARNING_LEVEL @@ -57,12 +58,6 @@ struct aws_overlapped { void *user_data; }; -typedef void(aws_event_loop_on_event_fn)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - void *user_data); - enum aws_io_event_type { AWS_IO_EVENT_TYPE_READABLE = 1, AWS_IO_EVENT_TYPE_WRITABLE = 2, @@ -71,26 +66,6 @@ enum aws_io_event_type { AWS_IO_EVENT_TYPE_ERROR = 16, }; -struct aws_event_loop_vtable { - void (*destroy)(struct aws_event_loop *event_loop); - int (*run)(struct aws_event_loop *event_loop); - int (*stop)(struct aws_event_loop *event_loop); - int (*wait_for_stop_completion)(struct aws_event_loop *event_loop); - void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); - void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); - void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); - int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); - int (*subscribe_to_io_events)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - aws_event_loop_on_event_fn *on_event, - void *user_data); - int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); - void (*free_io_event_resources)(void *user_data); - bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); -}; - struct aws_event_loop { struct aws_event_loop_vtable *vtable; struct aws_allocator *alloc; @@ -203,16 +178,6 @@ struct aws_event_loop *aws_event_loop_new_default_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -/** - * Invokes the destroy() fn for the event loop implementation. - * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. - * If you do not want this function to block, call aws_event_loop_stop() manually first. - * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads - * must ensure their API calls to the event loop happen-before the call to destroy. - */ -AWS_IO_API -void aws_event_loop_destroy(struct aws_event_loop *event_loop); - /** * Initializes common event-loop data structures. * This is only called from the *new() function of event loop implementations. @@ -220,13 +185,6 @@ void aws_event_loop_destroy(struct aws_event_loop *event_loop); AWS_IO_API int aws_event_loop_init_base(struct aws_event_loop *event_loop, struct aws_allocator *alloc, aws_io_clock_fn *clock); -/** - * Common cleanup code for all implementations. - * This is only called from the *destroy() function of event loop implementations. - */ -AWS_IO_API -void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); - /** * Fetches an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to * by key. This function is not thread safe and should be called inside the event-loop's thread. diff --git a/include/aws/testing/io_testing_channel.h b/include/aws/testing/io_testing_channel.h index 501c3f6bf..3e2835dba 100644 --- a/include/aws/testing/io_testing_channel.h +++ b/include/aws/testing/io_testing_channel.h @@ -9,11 +9,12 @@ #include #include #include -#include +// #include #include #include struct testing_loop { + struct aws_allocator *allocator; struct aws_task_scheduler scheduler; bool mock_on_callers_thread; }; @@ -34,7 +35,7 @@ static int s_testing_loop_wait_for_stop_completion(struct aws_event_loop *event_ } static void s_testing_loop_schedule_task_now(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); aws_task_scheduler_schedule_now(&testing_loop->scheduler, task); } @@ -43,26 +44,27 @@ static void s_testing_loop_schedule_task_future( struct aws_task *task, uint64_t run_at_nanos) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); aws_task_scheduler_schedule_future(&testing_loop->scheduler, task, run_at_nanos); } static void s_testing_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); aws_task_scheduler_cancel_task(&testing_loop->scheduler, task); } static bool s_testing_loop_is_on_callers_thread(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); return testing_loop->mock_on_callers_thread; } static void s_testing_loop_destroy(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); + struct aws_allocator *allocator = testing_loop->allocator; aws_task_scheduler_clean_up(&testing_loop->scheduler); - aws_mem_release(event_loop->alloc, testing_loop); + aws_mem_release(allocator, testing_loop); aws_event_loop_clean_up_base(event_loop); - aws_mem_release(event_loop->alloc, event_loop); + aws_mem_release(allocator, event_loop); } static struct aws_event_loop_vtable s_testing_loop_vtable = { @@ -77,16 +79,11 @@ static struct aws_event_loop_vtable s_testing_loop_vtable = { }; static struct aws_event_loop *s_testing_loop_new(struct aws_allocator *allocator, aws_io_clock_fn clock) { - struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); - aws_event_loop_init_base(event_loop, allocator, clock); - struct testing_loop *testing_loop = aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); aws_task_scheduler_init(&testing_loop->scheduler, allocator); testing_loop->mock_on_callers_thread = true; - event_loop->impl_data = testing_loop; - event_loop->vtable = &s_testing_loop_vtable; - return event_loop; + return aws_event_loop_new_base(allocator, clock, &s_testing_loop_vtable, testing_loop); } typedef void(testing_channel_handler_on_shutdown_fn)( @@ -394,7 +391,7 @@ static inline int testing_channel_init( AWS_ZERO_STRUCT(*testing); testing->loop = s_testing_loop_new(allocator, options->clock_fn); - testing->loop_impl = testing->loop->impl_data; + testing->loop_impl = aws_event_loop_get_impl(testing->loop); struct aws_channel_options args = { .on_setup_completed = s_testing_channel_on_setup_completed, diff --git a/source/event_loop.c b/source/event_loop.c index e11af4844..5f4d250bb 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -515,3 +515,20 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou return aws_event_loop_group_new(alloc, &elg_options); } + +void *aws_event_loop_get_impl(struct aws_event_loop *event_loop) { + return event_loop->impl_data; +} + +struct aws_event_loop *aws_event_loop_new_base( + struct aws_allocator *allocator, + aws_io_clock_fn *clock, + struct aws_event_loop_vtable *vtable, + void *impl) { + struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); + aws_event_loop_init_base(event_loop, allocator, clock); + event_loop->impl_data = impl; + event_loop->vtable = vtable; + + return event_loop; +} From b771d8c96d0308e8ace166f5ad8205492b0e2a11 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Thu, 7 Nov 2024 14:30:03 -0800 Subject: [PATCH 22/72] Revert "Make io testing channel usable across library boundaries" This reverts commit 9323cc38734f61cebf4695d7977116b696bd8823. --- include/aws/io/event_loop.h | 53 ------------------------ include/aws/io/private/event_loop_impl.h | 44 +++++++++++++++++++- include/aws/testing/io_testing_channel.h | 27 ++++++------ source/event_loop.c | 17 -------- 4 files changed, 58 insertions(+), 83 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 093e632f5..f953ae04d 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -15,32 +15,6 @@ struct aws_event_loop_group; struct aws_shutdown_callback_options; struct aws_task; -typedef void(aws_event_loop_on_event_fn)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - void *user_data); - -struct aws_event_loop_vtable { - void (*destroy)(struct aws_event_loop *event_loop); - int (*run)(struct aws_event_loop *event_loop); - int (*stop)(struct aws_event_loop *event_loop); - int (*wait_for_stop_completion)(struct aws_event_loop *event_loop); - void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); - void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); - void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); - int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); - int (*subscribe_to_io_events)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - aws_event_loop_on_event_fn *on_event, - void *user_data); - int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); - void (*free_io_event_resources)(void *user_data); - bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); -}; - /** * Event loop group configuration options */ @@ -192,33 +166,6 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou uint16_t cpu_group, const struct aws_shutdown_callback_options *shutdown_options); -AWS_IO_API -void *aws_event_loop_get_impl(struct aws_event_loop *event_loop); - -AWS_IO_API -struct aws_event_loop *aws_event_loop_new_base( - struct aws_allocator *allocator, - aws_io_clock_fn *clock, - struct aws_event_loop_vtable *vtable, - void *impl); - -/** - * Common cleanup code for all implementations. - * This is only called from the *destroy() function of event loop implementations. - */ -AWS_IO_API -void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); - -/** - * Invokes the destroy() fn for the event loop implementation. - * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. - * If you do not want this function to block, call aws_event_loop_stop() manually first. - * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads - * must ensure their API calls to the event loop happen-before the call to destroy. - */ -AWS_IO_API -void aws_event_loop_destroy(struct aws_event_loop *event_loop); - AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 4eb2f6230..e852aba82 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -11,7 +11,6 @@ #include #include #include -#include AWS_PUSH_SANE_WARNING_LEVEL @@ -58,6 +57,12 @@ struct aws_overlapped { void *user_data; }; +typedef void(aws_event_loop_on_event_fn)( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + void *user_data); + enum aws_io_event_type { AWS_IO_EVENT_TYPE_READABLE = 1, AWS_IO_EVENT_TYPE_WRITABLE = 2, @@ -66,6 +71,26 @@ enum aws_io_event_type { AWS_IO_EVENT_TYPE_ERROR = 16, }; +struct aws_event_loop_vtable { + void (*destroy)(struct aws_event_loop *event_loop); + int (*run)(struct aws_event_loop *event_loop); + int (*stop)(struct aws_event_loop *event_loop); + int (*wait_for_stop_completion)(struct aws_event_loop *event_loop); + void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); + void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); + void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); + int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + int (*subscribe_to_io_events)( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + aws_event_loop_on_event_fn *on_event, + void *user_data); + int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + void (*free_io_event_resources)(void *user_data); + bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); +}; + struct aws_event_loop { struct aws_event_loop_vtable *vtable; struct aws_allocator *alloc; @@ -178,6 +203,16 @@ struct aws_event_loop *aws_event_loop_new_default_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); +/** + * Invokes the destroy() fn for the event loop implementation. + * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. + * If you do not want this function to block, call aws_event_loop_stop() manually first. + * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads + * must ensure their API calls to the event loop happen-before the call to destroy. + */ +AWS_IO_API +void aws_event_loop_destroy(struct aws_event_loop *event_loop); + /** * Initializes common event-loop data structures. * This is only called from the *new() function of event loop implementations. @@ -185,6 +220,13 @@ struct aws_event_loop *aws_event_loop_new_default_with_options( AWS_IO_API int aws_event_loop_init_base(struct aws_event_loop *event_loop, struct aws_allocator *alloc, aws_io_clock_fn *clock); +/** + * Common cleanup code for all implementations. + * This is only called from the *destroy() function of event loop implementations. + */ +AWS_IO_API +void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); + /** * Fetches an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to * by key. This function is not thread safe and should be called inside the event-loop's thread. diff --git a/include/aws/testing/io_testing_channel.h b/include/aws/testing/io_testing_channel.h index 3e2835dba..501c3f6bf 100644 --- a/include/aws/testing/io_testing_channel.h +++ b/include/aws/testing/io_testing_channel.h @@ -9,12 +9,11 @@ #include #include #include -// #include +#include #include #include struct testing_loop { - struct aws_allocator *allocator; struct aws_task_scheduler scheduler; bool mock_on_callers_thread; }; @@ -35,7 +34,7 @@ static int s_testing_loop_wait_for_stop_completion(struct aws_event_loop *event_ } static void s_testing_loop_schedule_task_now(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); + struct testing_loop *testing_loop = event_loop->impl_data; aws_task_scheduler_schedule_now(&testing_loop->scheduler, task); } @@ -44,27 +43,26 @@ static void s_testing_loop_schedule_task_future( struct aws_task *task, uint64_t run_at_nanos) { - struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); + struct testing_loop *testing_loop = event_loop->impl_data; aws_task_scheduler_schedule_future(&testing_loop->scheduler, task, run_at_nanos); } static void s_testing_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); + struct testing_loop *testing_loop = event_loop->impl_data; aws_task_scheduler_cancel_task(&testing_loop->scheduler, task); } static bool s_testing_loop_is_on_callers_thread(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); + struct testing_loop *testing_loop = event_loop->impl_data; return testing_loop->mock_on_callers_thread; } static void s_testing_loop_destroy(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); - struct aws_allocator *allocator = testing_loop->allocator; + struct testing_loop *testing_loop = event_loop->impl_data; aws_task_scheduler_clean_up(&testing_loop->scheduler); - aws_mem_release(allocator, testing_loop); + aws_mem_release(event_loop->alloc, testing_loop); aws_event_loop_clean_up_base(event_loop); - aws_mem_release(allocator, event_loop); + aws_mem_release(event_loop->alloc, event_loop); } static struct aws_event_loop_vtable s_testing_loop_vtable = { @@ -79,11 +77,16 @@ static struct aws_event_loop_vtable s_testing_loop_vtable = { }; static struct aws_event_loop *s_testing_loop_new(struct aws_allocator *allocator, aws_io_clock_fn clock) { + struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); + aws_event_loop_init_base(event_loop, allocator, clock); + struct testing_loop *testing_loop = aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); aws_task_scheduler_init(&testing_loop->scheduler, allocator); testing_loop->mock_on_callers_thread = true; + event_loop->impl_data = testing_loop; + event_loop->vtable = &s_testing_loop_vtable; - return aws_event_loop_new_base(allocator, clock, &s_testing_loop_vtable, testing_loop); + return event_loop; } typedef void(testing_channel_handler_on_shutdown_fn)( @@ -391,7 +394,7 @@ static inline int testing_channel_init( AWS_ZERO_STRUCT(*testing); testing->loop = s_testing_loop_new(allocator, options->clock_fn); - testing->loop_impl = aws_event_loop_get_impl(testing->loop); + testing->loop_impl = testing->loop->impl_data; struct aws_channel_options args = { .on_setup_completed = s_testing_channel_on_setup_completed, diff --git a/source/event_loop.c b/source/event_loop.c index 5f4d250bb..e11af4844 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -515,20 +515,3 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou return aws_event_loop_group_new(alloc, &elg_options); } - -void *aws_event_loop_get_impl(struct aws_event_loop *event_loop) { - return event_loop->impl_data; -} - -struct aws_event_loop *aws_event_loop_new_base( - struct aws_allocator *allocator, - aws_io_clock_fn *clock, - struct aws_event_loop_vtable *vtable, - void *impl) { - struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); - aws_event_loop_init_base(event_loop, allocator, clock); - event_loop->impl_data = impl; - event_loop->vtable = vtable; - - return event_loop; -} From 4f3048efd8e8b63f696719fc2b8e28259709fecf Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 7 Nov 2024 14:50:14 -0800 Subject: [PATCH 23/72] add function to override the default event loop type --- include/aws/io/private/event_loop_impl.h | 21 ++++++++++++++--- source/event_loop.c | 29 ++++++++++++++++++------ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index ec8c70eda..94ab94e3e 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -140,9 +140,24 @@ struct aws_event_loop *aws_event_loop_new_epoll_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, - const struct aws_event_loop_options *options, - void *new_loop_user_data); +/** + * Override default event loop type. Only used internally in tests. + * + * If the defined type is not supported on the current platform, the event loop type would reset to + * AWS_ELT_PLATFORM_DEFAULT. + */ +static int aws_event_loop_override_default_type(enum aws_event_loop_type default_type); + +/** + * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to + * retrieve the default type value. + * If `aws_event_loop_override_default_type` has been called, return the override default type. + */ +static enum aws_event_loop_type aws_event_loop_get_default_type(void) + + typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, + const struct aws_event_loop_options *options, + void *new_loop_user_data); struct aws_event_loop_group { struct aws_allocator *allocator; diff --git a/source/event_loop.c b/source/event_loop.c index 0e045835f..5b01793c2 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -14,6 +14,8 @@ #include #include +static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; + struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock) { struct aws_event_loop_options options = { .thread_options = NULL, @@ -37,7 +39,7 @@ struct aws_event_loop *aws_event_loop_new_default_with_options( } static enum aws_event_loop_type aws_event_loop_get_default_type(void); -static int aws_event_loop_validate_platform(enum aws_event_loop_type type); +static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type); struct aws_event_loop *aws_event_loop_new_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { @@ -47,7 +49,7 @@ struct aws_event_loop *aws_event_loop_new_with_options( type = aws_event_loop_get_default_type(); } - if (aws_event_loop_validate_platform(type)) { + if (aws_event_loop_type_validate_platform(type)) { AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type on the platform."); return NULL; } @@ -538,14 +540,22 @@ int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_ return event_loop->clock(time_nanos); } +static int aws_event_loop_override_default_type(enum aws_event_loop_type default_type_override) { + if (aws_event_loop_type_validate_platform(default_type_override)) { + s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; + return; + } + s_default_event_loop_type_override = default_type_override; +} + static enum aws_event_loop_type aws_event_loop_get_default_type(void) { + if (s_default_event_loop_type_override != AWS_ELT_PLATFORM_DEFAULT) { + return s_default_event_loop_type_override; + } /** * Ideally we should use the platform definition (e.x.: AWS_OS_APPLE) here, however the platform * definition was declared in aws-c-common. We probably do not want to introduce extra dependency here. */ -#ifdef AWS_OS_WINDOWS - return AWS_ELT_IOCP; -#endif #ifdef AWS_ENABLE_KQUEUE return AWS_ELT_KQUEUE; #endif @@ -555,9 +565,14 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { #ifdef AWS_ENABLE_EPOLL return AWS_ELT_EPOLL; #endif +#ifdef AWS_OS_WINDOWS + return AWS_ELT_IOCP; +#endif + AWS_FATAL_ASSERT(false && "Could not find default event loop type"); + return AWS_ELT_PLATFORM_DEFAULT; } -static int aws_event_loop_validate_platform(enum aws_event_loop_type type) { +static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) { switch (type) { case AWS_ELT_EPOLL: #ifndef AWS_ENABLE_EPOLL @@ -598,7 +613,7 @@ struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( (void)alloc; (void)options; AWS_ASSERT(0); - + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Dispatch Queue is not supported on the platform"); return NULL; } From fcb3d9a87cfe72600272d7e708e07519a882c180 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 8 Nov 2024 08:34:44 -0800 Subject: [PATCH 24/72] Revert "Revert "Make io testing channel usable across library boundaries"" This reverts commit b771d8c96d0308e8ace166f5ad8205492b0e2a11. --- include/aws/io/event_loop.h | 53 ++++++++++++++++++++++++ include/aws/io/private/event_loop_impl.h | 44 +------------------- include/aws/testing/io_testing_channel.h | 27 ++++++------ source/event_loop.c | 17 ++++++++ 4 files changed, 83 insertions(+), 58 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index f953ae04d..093e632f5 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -15,6 +15,32 @@ struct aws_event_loop_group; struct aws_shutdown_callback_options; struct aws_task; +typedef void(aws_event_loop_on_event_fn)( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + void *user_data); + +struct aws_event_loop_vtable { + void (*destroy)(struct aws_event_loop *event_loop); + int (*run)(struct aws_event_loop *event_loop); + int (*stop)(struct aws_event_loop *event_loop); + int (*wait_for_stop_completion)(struct aws_event_loop *event_loop); + void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); + void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); + void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); + int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + int (*subscribe_to_io_events)( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + aws_event_loop_on_event_fn *on_event, + void *user_data); + int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + void (*free_io_event_resources)(void *user_data); + bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); +}; + /** * Event loop group configuration options */ @@ -166,6 +192,33 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou uint16_t cpu_group, const struct aws_shutdown_callback_options *shutdown_options); +AWS_IO_API +void *aws_event_loop_get_impl(struct aws_event_loop *event_loop); + +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_base( + struct aws_allocator *allocator, + aws_io_clock_fn *clock, + struct aws_event_loop_vtable *vtable, + void *impl); + +/** + * Common cleanup code for all implementations. + * This is only called from the *destroy() function of event loop implementations. + */ +AWS_IO_API +void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); + +/** + * Invokes the destroy() fn for the event loop implementation. + * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. + * If you do not want this function to block, call aws_event_loop_stop() manually first. + * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads + * must ensure their API calls to the event loop happen-before the call to destroy. + */ +AWS_IO_API +void aws_event_loop_destroy(struct aws_event_loop *event_loop); + AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index e852aba82..4eb2f6230 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -11,6 +11,7 @@ #include #include #include +#include AWS_PUSH_SANE_WARNING_LEVEL @@ -57,12 +58,6 @@ struct aws_overlapped { void *user_data; }; -typedef void(aws_event_loop_on_event_fn)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - void *user_data); - enum aws_io_event_type { AWS_IO_EVENT_TYPE_READABLE = 1, AWS_IO_EVENT_TYPE_WRITABLE = 2, @@ -71,26 +66,6 @@ enum aws_io_event_type { AWS_IO_EVENT_TYPE_ERROR = 16, }; -struct aws_event_loop_vtable { - void (*destroy)(struct aws_event_loop *event_loop); - int (*run)(struct aws_event_loop *event_loop); - int (*stop)(struct aws_event_loop *event_loop); - int (*wait_for_stop_completion)(struct aws_event_loop *event_loop); - void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); - void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); - void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); - int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); - int (*subscribe_to_io_events)( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - aws_event_loop_on_event_fn *on_event, - void *user_data); - int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); - void (*free_io_event_resources)(void *user_data); - bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); -}; - struct aws_event_loop { struct aws_event_loop_vtable *vtable; struct aws_allocator *alloc; @@ -203,16 +178,6 @@ struct aws_event_loop *aws_event_loop_new_default_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -/** - * Invokes the destroy() fn for the event loop implementation. - * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. - * If you do not want this function to block, call aws_event_loop_stop() manually first. - * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads - * must ensure their API calls to the event loop happen-before the call to destroy. - */ -AWS_IO_API -void aws_event_loop_destroy(struct aws_event_loop *event_loop); - /** * Initializes common event-loop data structures. * This is only called from the *new() function of event loop implementations. @@ -220,13 +185,6 @@ void aws_event_loop_destroy(struct aws_event_loop *event_loop); AWS_IO_API int aws_event_loop_init_base(struct aws_event_loop *event_loop, struct aws_allocator *alloc, aws_io_clock_fn *clock); -/** - * Common cleanup code for all implementations. - * This is only called from the *destroy() function of event loop implementations. - */ -AWS_IO_API -void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); - /** * Fetches an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to * by key. This function is not thread safe and should be called inside the event-loop's thread. diff --git a/include/aws/testing/io_testing_channel.h b/include/aws/testing/io_testing_channel.h index 501c3f6bf..3e2835dba 100644 --- a/include/aws/testing/io_testing_channel.h +++ b/include/aws/testing/io_testing_channel.h @@ -9,11 +9,12 @@ #include #include #include -#include +// #include #include #include struct testing_loop { + struct aws_allocator *allocator; struct aws_task_scheduler scheduler; bool mock_on_callers_thread; }; @@ -34,7 +35,7 @@ static int s_testing_loop_wait_for_stop_completion(struct aws_event_loop *event_ } static void s_testing_loop_schedule_task_now(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); aws_task_scheduler_schedule_now(&testing_loop->scheduler, task); } @@ -43,26 +44,27 @@ static void s_testing_loop_schedule_task_future( struct aws_task *task, uint64_t run_at_nanos) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); aws_task_scheduler_schedule_future(&testing_loop->scheduler, task, run_at_nanos); } static void s_testing_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); aws_task_scheduler_cancel_task(&testing_loop->scheduler, task); } static bool s_testing_loop_is_on_callers_thread(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); return testing_loop->mock_on_callers_thread; } static void s_testing_loop_destroy(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = aws_event_loop_get_impl(event_loop); + struct aws_allocator *allocator = testing_loop->allocator; aws_task_scheduler_clean_up(&testing_loop->scheduler); - aws_mem_release(event_loop->alloc, testing_loop); + aws_mem_release(allocator, testing_loop); aws_event_loop_clean_up_base(event_loop); - aws_mem_release(event_loop->alloc, event_loop); + aws_mem_release(allocator, event_loop); } static struct aws_event_loop_vtable s_testing_loop_vtable = { @@ -77,16 +79,11 @@ static struct aws_event_loop_vtable s_testing_loop_vtable = { }; static struct aws_event_loop *s_testing_loop_new(struct aws_allocator *allocator, aws_io_clock_fn clock) { - struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); - aws_event_loop_init_base(event_loop, allocator, clock); - struct testing_loop *testing_loop = aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); aws_task_scheduler_init(&testing_loop->scheduler, allocator); testing_loop->mock_on_callers_thread = true; - event_loop->impl_data = testing_loop; - event_loop->vtable = &s_testing_loop_vtable; - return event_loop; + return aws_event_loop_new_base(allocator, clock, &s_testing_loop_vtable, testing_loop); } typedef void(testing_channel_handler_on_shutdown_fn)( @@ -394,7 +391,7 @@ static inline int testing_channel_init( AWS_ZERO_STRUCT(*testing); testing->loop = s_testing_loop_new(allocator, options->clock_fn); - testing->loop_impl = testing->loop->impl_data; + testing->loop_impl = aws_event_loop_get_impl(testing->loop); struct aws_channel_options args = { .on_setup_completed = s_testing_channel_on_setup_completed, diff --git a/source/event_loop.c b/source/event_loop.c index e11af4844..5f4d250bb 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -515,3 +515,20 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou return aws_event_loop_group_new(alloc, &elg_options); } + +void *aws_event_loop_get_impl(struct aws_event_loop *event_loop) { + return event_loop->impl_data; +} + +struct aws_event_loop *aws_event_loop_new_base( + struct aws_allocator *allocator, + aws_io_clock_fn *clock, + struct aws_event_loop_vtable *vtable, + void *impl) { + struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); + aws_event_loop_init_base(event_loop, allocator, clock); + event_loop->impl_data = impl; + event_loop->vtable = vtable; + + return event_loop; +} From 9b16a3bb4d4de1bff216d41d992dd79d28a9d3dd Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 8 Nov 2024 08:52:58 -0800 Subject: [PATCH 25/72] Set allocator --- include/aws/testing/io_testing_channel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/aws/testing/io_testing_channel.h b/include/aws/testing/io_testing_channel.h index 3e2835dba..75e9de9c6 100644 --- a/include/aws/testing/io_testing_channel.h +++ b/include/aws/testing/io_testing_channel.h @@ -82,6 +82,7 @@ static struct aws_event_loop *s_testing_loop_new(struct aws_allocator *allocator struct testing_loop *testing_loop = aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); aws_task_scheduler_init(&testing_loop->scheduler, allocator); testing_loop->mock_on_callers_thread = true; + testing_loop->allocator = allocator; return aws_event_loop_new_base(allocator, clock, &s_testing_loop_vtable, testing_loop); } From a30cd394b978c56c378d70d475a64d1575606009 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 09:33:49 -0800 Subject: [PATCH 26/72] default event loop type override --- include/aws/io/private/event_loop_impl.h | 12 +++++++----- source/event_loop.c | 6 ++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 94ab94e3e..f8cdc8546 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -146,18 +146,20 @@ struct aws_event_loop *aws_event_loop_new_epoll_with_options( * If the defined type is not supported on the current platform, the event loop type would reset to * AWS_ELT_PLATFORM_DEFAULT. */ -static int aws_event_loop_override_default_type(enum aws_event_loop_type default_type); +AWS_IO_API +static void aws_event_loop_override_default_type(enum aws_event_loop_type default_type); /** * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to * retrieve the default type value. * If `aws_event_loop_override_default_type` has been called, return the override default type. */ -static enum aws_event_loop_type aws_event_loop_get_default_type(void) +AWS_IO_API +static enum aws_event_loop_type aws_event_loop_get_default_type(void); - typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, - const struct aws_event_loop_options *options, - void *new_loop_user_data); +typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, + const struct aws_event_loop_options *options, + void *new_loop_user_data); struct aws_event_loop_group { struct aws_allocator *allocator; diff --git a/source/event_loop.c b/source/event_loop.c index 5b01793c2..8f1187447 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -540,15 +540,17 @@ int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_ return event_loop->clock(time_nanos); } -static int aws_event_loop_override_default_type(enum aws_event_loop_type default_type_override) { +static void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_override) { if (aws_event_loop_type_validate_platform(default_type_override)) { s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; - return; } s_default_event_loop_type_override = default_type_override; } static enum aws_event_loop_type aws_event_loop_get_default_type(void) { +#ifdef AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE + aws_event_loop_override_default_type(AWS_ELT_DISPATCH_QUEUE); +#endif // AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE if (s_default_event_loop_type_override != AWS_ELT_PLATFORM_DEFAULT) { return s_default_event_loop_type_override; } From 74733ad3084c2201f097eb0bca616cb4828a53e6 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 10:22:24 -0800 Subject: [PATCH 27/72] hide the test help function as internal private --- include/aws/io/private/event_loop_impl.h | 17 ----------------- source/event_loop.c | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index f8cdc8546..ec8c70eda 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -140,23 +140,6 @@ struct aws_event_loop *aws_event_loop_new_epoll_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -/** - * Override default event loop type. Only used internally in tests. - * - * If the defined type is not supported on the current platform, the event loop type would reset to - * AWS_ELT_PLATFORM_DEFAULT. - */ -AWS_IO_API -static void aws_event_loop_override_default_type(enum aws_event_loop_type default_type); - -/** - * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to - * retrieve the default type value. - * If `aws_event_loop_override_default_type` has been called, return the override default type. - */ -AWS_IO_API -static enum aws_event_loop_type aws_event_loop_get_default_type(void); - typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, const struct aws_event_loop_options *options, void *new_loop_user_data); diff --git a/source/event_loop.c b/source/event_loop.c index 8f1187447..992745ef1 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -540,13 +540,26 @@ int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_ return event_loop->clock(time_nanos); } -static void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_override) { + +/** + * Override default event loop type. Only used internally in tests. + * + * If the defined type is not supported on the current platform, the event loop type would reset to + * AWS_ELT_PLATFORM_DEFAULT. + */ +void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_override) { if (aws_event_loop_type_validate_platform(default_type_override)) { s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; } s_default_event_loop_type_override = default_type_override; } + +/** + * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to + * retrieve the default type value. + * If `aws_event_loop_override_default_type` has been called, return the override default type. + */ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { #ifdef AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE aws_event_loop_override_default_type(AWS_ELT_DISPATCH_QUEUE); From 558d179865d2e460cdd81ee6f66972b04a35afb6 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 10:24:41 -0800 Subject: [PATCH 28/72] clang format --- source/event_loop.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/event_loop.c b/source/event_loop.c index 992745ef1..25565d81a 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -540,7 +540,6 @@ int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_ return event_loop->clock(time_nanos); } - /** * Override default event loop type. Only used internally in tests. * @@ -554,7 +553,6 @@ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_ s_default_event_loop_type_override = default_type_override; } - /** * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to * retrieve the default type value. From 16d4e259404ee57e0264695f7f30745f1f43e753 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 10:27:59 -0800 Subject: [PATCH 29/72] remove unreachable.. --- source/event_loop.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/event_loop.c b/source/event_loop.c index 25565d81a..96b9cf172 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -581,8 +581,6 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { #ifdef AWS_OS_WINDOWS return AWS_ELT_IOCP; #endif - AWS_FATAL_ASSERT(false && "Could not find default event loop type"); - return AWS_ELT_PLATFORM_DEFAULT; } static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) { From 74019cfe6399a847458be8f55162678020e40d39 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 10:35:51 -0800 Subject: [PATCH 30/72] update ci flags --- .github/workflows/ci.yml | 2 +- tests/CMakeLists.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6daefec60..11fd5f4c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -160,7 +160,7 @@ jobs: runs-on: macos-14 # latest strategy: matrix: - eventloop: ["-DAWS_ENABLE_DISPATCH_QUEUE=ON", "-DAWS_ENABLE_DISPATCH_QUEUE=OFF"] + eventloop: ["-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=ON", "-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=OFF"] steps: - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index edceafb23..b7bd0332e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,7 +18,7 @@ add_test_case(io_library_init) add_test_case(io_library_init_cleanup_init_cleanup) # DEBUG: temporarily disable the pipe related tests -if(NOT AWS_TEST_DISPATCH_QUEUE) +if(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) add_pipe_test_case(pipe_open_close) add_pipe_test_case(pipe_read_write) add_pipe_test_case(pipe_read_write_large_buffer) @@ -39,7 +39,7 @@ add_test_case(event_loop_canceled_tasks_run_in_el_thread) if(USE_IO_COMPLETION_PORTS) add_test_case(event_loop_completion_events) -elseif(NOT AWS_TEST_DISPATCH_QUEUE) # TODO: setup a test for dispatch queue once pipe is there. +elseif(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) # TODO: setup a test for dispatch queue once pipe is there. add_test_case(event_loop_subscribe_unsubscribe) add_test_case(event_loop_writable_event_on_subscribe) add_test_case(event_loop_no_readable_event_before_write) From 5d22a69f41d238b07c6ca656a3bbc59b355cf9de Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 11:17:41 -0800 Subject: [PATCH 31/72] update setup switch default event loop --- .github/workflows/ci.yml | 2 +- include/aws/io/private/event_loop_impl.h | 8 ++++++ source/event_loop.c | 10 +++----- tests/event_loop_test.c | 32 ++++++++++++------------ 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 11fd5f4c5..20af43195 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -181,7 +181,7 @@ jobs: runs-on: macos-14 # latest strategy: matrix: - eventloop: ["-DAWS_ENABLE_DISPATCH_QUEUE=ON", "-DAWS_ENABLE_DISPATCH_QUEUE=OFF"] + eventloop: ["-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=ON", "-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=OFF"] steps: - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index ec8c70eda..cc08fb8db 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -140,6 +140,14 @@ struct aws_event_loop *aws_event_loop_new_epoll_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); +/** + * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to + * retrieve the default type value. + * If `aws_event_loop_override_default_type` has been called, return the override default type. + */ +AWS_IO_API +enum aws_event_loop_type aws_event_loop_get_default_type(void); + typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, const struct aws_event_loop_options *options, void *new_loop_user_data); diff --git a/source/event_loop.c b/source/event_loop.c index 96b9cf172..ff131a32e 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -38,7 +38,6 @@ struct aws_event_loop *aws_event_loop_new_default_with_options( return aws_event_loop_new_with_options(alloc, &local_options); } -static enum aws_event_loop_type aws_event_loop_get_default_type(void); static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type); struct aws_event_loop *aws_event_loop_new_with_options( struct aws_allocator *alloc, @@ -553,12 +552,7 @@ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_ s_default_event_loop_type_override = default_type_override; } -/** - * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to - * retrieve the default type value. - * If `aws_event_loop_override_default_type` has been called, return the override default type. - */ -static enum aws_event_loop_type aws_event_loop_get_default_type(void) { +enum aws_event_loop_type aws_event_loop_get_default_type(void) { #ifdef AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE aws_event_loop_override_default_type(AWS_ELT_DISPATCH_QUEUE); #endif // AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE @@ -580,6 +574,8 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { #endif #ifdef AWS_OS_WINDOWS return AWS_ELT_IOCP; +#else + return AWS_ELT_PLATFORM_DEFAULT; #endif } diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index 39a0fc422..97b3bafd5 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -78,11 +78,11 @@ static int s_test_event_loop_xthread_scheduled_tasks_execute(struct aws_allocato ASSERT_TRUE(task_args.invoked); aws_mutex_unlock(&task_args.mutex); -// The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, -// therefore we do not validate the thread id for dispatch queue. -#ifndef AWS_TEST_DISPATCH_QUEUE - ASSERT_FALSE(aws_thread_thread_id_equal(task_args.thread_id, aws_thread_current_thread_id())); -#endif + // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, + // therefore we do not validate the thread id for dispatch queue. + if (aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE) { + ASSERT_FALSE(aws_thread_thread_id_equal(task_args.thread_id, aws_thread_current_thread_id())); + } /* Test "now" tasks */ task_args.invoked = false; @@ -154,11 +154,11 @@ static int s_test_event_loop_canceled_tasks_run_in_el_thread(struct aws_allocato &task1_args.condition_variable, &task1_args.mutex, s_task_ran_predicate, &task1_args)); ASSERT_TRUE(task1_args.invoked); ASSERT_TRUE(task1_args.was_in_thread); -// The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, -// therefore we do not validate the thread id for dispatch queue. -#ifndef AWS_TEST_DISPATCH_QUEUE - ASSERT_FALSE(aws_thread_thread_id_equal(task1_args.thread_id, aws_thread_current_thread_id())); -#endif + // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, + // therefore we do not validate the thread id for dispatch queue. + if (aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE) { + ASSERT_FALSE(aws_thread_thread_id_equal(task1_args.thread_id, aws_thread_current_thread_id())); + } ASSERT_INT_EQUALS(AWS_TASK_STATUS_RUN_READY, task1_args.status); aws_mutex_unlock(&task1_args.mutex); @@ -172,11 +172,11 @@ static int s_test_event_loop_canceled_tasks_run_in_el_thread(struct aws_allocato aws_mutex_unlock(&task2_args.mutex); ASSERT_TRUE(task2_args.was_in_thread); -// The dispatch queue will schedule tasks on thread pools, it is unpredictable which thread we run the task on, -// therefore we do not validate the thread id for dispatch queue. -#ifndef AWS_TEST_DISPATCH_QUEUE - ASSERT_TRUE(aws_thread_thread_id_equal(task2_args.thread_id, aws_thread_current_thread_id())); -#endif + // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, + // therefore we do not validate the thread id for dispatch queue. + if (aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE) { + ASSERT_TRUE(aws_thread_thread_id_equal(task2_args.thread_id, aws_thread_current_thread_id())); + } ASSERT_INT_EQUALS(AWS_TASK_STATUS_CANCELED, task2_args.status); return AWS_OP_SUCCESS; @@ -282,7 +282,7 @@ static int s_test_event_loop_completion_events(struct aws_allocator *allocator, ASSERT_SUCCESS(s_async_pipe_init(&read_handle, &write_handle)); /* Connect to event-loop */ - ASSERT_SUCCESS(aws_event_loop_connect_handle_to_completion_port(event_loop, &write_handle)); + ASSERT_SUCCESS(aws_event_loop_connect_handle_to_io_completion_port(event_loop, &write_handle)); /* Set up an async (overlapped) write that will result in s_on_overlapped_operation_complete() getting run * and filling out `completion_data` */ From 600421e99a2a2d67ecc807be767419987f7c13bc Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 11:24:21 -0800 Subject: [PATCH 32/72] revert function rename --- source/windows/iocp/pipe.c | 4 ++-- source/windows/iocp/socket.c | 2 +- tests/CMakeLists.txt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/windows/iocp/pipe.c b/source/windows/iocp/pipe.c index 6a8abda94..a9e2185e5 100644 --- a/source/windows/iocp/pipe.c +++ b/source/windows/iocp/pipe.c @@ -252,7 +252,7 @@ int aws_pipe_init( } } - int err = aws_event_loop_connect_handle_to_completion_port(write_end_event_loop, &write_impl->handle); + int err = aws_event_loop_connect_handle_to_io_completion_port(write_end_event_loop, &write_impl->handle); if (err) { goto clean_up; } @@ -283,7 +283,7 @@ int aws_pipe_init( goto clean_up; } - err = aws_event_loop_connect_handle_to_completion_port(read_end_event_loop, &read_impl->handle); + err = aws_event_loop_connect_handle_to_io_completion_port(read_end_event_loop, &read_impl->handle); if (err) { goto clean_up; } diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index 1eb342d3a..7286bd6ba 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -2556,7 +2556,7 @@ int aws_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_ } socket->event_loop = event_loop; - return aws_event_loop_connect_handle_to_completion_port(event_loop, &socket->io_handle); + return aws_event_loop_connect_handle_to_io_completion_port(event_loop, &socket->io_handle); } struct aws_event_loop *aws_socket_get_event_loop(struct aws_socket *socket) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b7bd0332e..afcc1979c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,7 +17,7 @@ endmacro() add_test_case(io_library_init) add_test_case(io_library_init_cleanup_init_cleanup) -# DEBUG: temporarily disable the pipe related tests +# Dispatch Queue does not support pipe if(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) add_pipe_test_case(pipe_open_close) add_pipe_test_case(pipe_read_write) @@ -39,7 +39,7 @@ add_test_case(event_loop_canceled_tasks_run_in_el_thread) if(USE_IO_COMPLETION_PORTS) add_test_case(event_loop_completion_events) -elseif(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) # TODO: setup a test for dispatch queue once pipe is there. +elseif(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) # Dispatch Queue does not support pipe add_test_case(event_loop_subscribe_unsubscribe) add_test_case(event_loop_writable_event_on_subscribe) add_test_case(event_loop_no_readable_event_before_write) From 7cb09361985fd8a9fd03cdcabbf8aa8b7608856f Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 11:42:50 -0800 Subject: [PATCH 33/72] update cmake for dispatch queue --- .github/workflows/ci.yml | 12 +++++++++--- CMakeLists.txt | 21 +++++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f9774c160..d101fea08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,12 +158,15 @@ jobs: macos: runs-on: macos-14 # latest + strategy: + matrix: + eventloop: ["-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=ON", "-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=OFF"] steps: - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')" chmod a+x builder - ./builder build -p ${{ env.PACKAGE_NAME }} + ./builder build -p ${{ env.PACKAGE_NAME }} --cmake-extra=${{ matrix.eventloop }} macos-x64: runs-on: macos-14-large # latest @@ -176,12 +179,15 @@ jobs: macos-debug: runs-on: macos-14 # latest + strategy: + matrix: + eventloop: ["-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=ON", "-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=OFF"] steps: - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')" chmod a+x builder - ./builder build -p ${{ env.PACKAGE_NAME }} --config Debug + ./builder build -p ${{ env.PACKAGE_NAME }} --cmake-extra=${{ matrix.eventloop }} --config Debug freebsd: runs-on: ubuntu-22.04 # latest @@ -219,4 +225,4 @@ jobs: sudo pkg_add py3-urllib3 python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')" chmod a+x builder - ./builder build -p ${{ env.PACKAGE_NAME }} + ./builder build -p ${{ env.PACKAGE_NAME }} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9adb1c145..a0e9f52ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,8 +111,6 @@ elseif (APPLE) ) file(GLOB AWS_IO_OS_SRC - "source/bsd/*.c" - "source/posix/*.c" "source/darwin/*.c" ) @@ -121,9 +119,24 @@ elseif (APPLE) message(FATAL_ERROR "Security framework not found") endif () + find_library(NETWORK_LIB Network) + if (NOT NETWORK_LIB) + message(FATAL_ERROR "Network framework not found") + endif () + #No choice on TLS for apple, darwinssl will always be used. - list(APPEND PLATFORM_LIBS "-framework Security") - set(EVENT_LOOP_DEFINE "KQUEUE") + list(APPEND PLATFORM_LIBS "-framework Security -framework Network") + set(EVENT_LOOP_DEFINES "DISPATCH_QUEUE" ) + + # Enable KQUEUE on MacOS + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + file(GLOB AWS_IO_KUEUE_SRC + "source/bsd/*.c" + "source/posix/*.c" + ) + list(APPEND AWS_IO_OS_SRC ${AWS_IO_KUEUE_SRC}) + set(EVENT_LOOP_DEFINE "KQUEUE") + endif() elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") file(GLOB AWS_IO_OS_HEADERS From 69c22b4a6c1b7e1c4dbb064d2d5324ac65afe410 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 12:03:11 -0800 Subject: [PATCH 34/72] clean up merge changes --- include/aws/io/socket.h | 1 - source/darwin/nw_socket.c | 10 ++++------ source/posix/socket.c | 1 - source/socket.c | 2 -- source/windows/iocp/socket.c | 1 - 5 files changed, 4 insertions(+), 11 deletions(-) diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index 9a6d8110f..01c83084c 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -164,7 +164,6 @@ struct aws_socket { struct aws_event_loop *event_loop; struct aws_channel_handler *handler; int state; - enum aws_event_loop_style event_loop_style; aws_socket_on_readable_fn *readable_fn; void *readable_user_data; aws_socket_on_connection_result_fn *connection_result_fn; diff --git a/source/darwin/nw_socket.c b/source/darwin/nw_socket.c index 6a4ce4ba4..a54367aa5 100644 --- a/source/darwin/nw_socket.c +++ b/source/darwin/nw_socket.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -17,7 +18,6 @@ #include #include -#ifdef AWS_USE_DISPATCH_QUEUE static int s_determine_socket_error(int error) { switch (error) { case ECONNREFUSED: @@ -355,7 +355,6 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons socket->options = *options; socket->impl = nw_socket; socket->vtable = &s_vtable; - socket->event_loop_style = AWS_EVENT_LOOP_STYLE_COMPLETION_PORT_BASED; aws_mutex_init(&nw_socket->synced_data.lock); aws_mutex_lock(&nw_socket->synced_data.lock); @@ -833,7 +832,7 @@ static int s_socket_connect_fn( socket->io_handle.set_queue = s_client_set_dispatch_queue; socket->io_handle.clear_queue = s_client_clear_dispatch_queue; - aws_event_loop_connect_handle_to_completion_port(event_loop, &socket->io_handle); + aws_event_loop_connect_handle_to_io_completion_port(event_loop, &socket->io_handle); socket->event_loop = event_loop; nw_socket->on_connection_result_fn = on_connection_result; @@ -1144,7 +1143,7 @@ static int s_socket_start_accept_fn( return aws_raise_error(AWS_IO_SOCKET_ILLEGAL_OPERATION_FOR_STATE); } - aws_event_loop_connect_handle_to_completion_port(accept_loop, &socket->io_handle); + aws_event_loop_connect_handle_to_io_completion_port(accept_loop, &socket->io_handle); socket->event_loop = accept_loop; socket->accept_result_fn = on_accept_result; socket->connect_accept_user_data = user_data; @@ -1314,7 +1313,7 @@ static int s_socket_assign_to_event_loop_fn(struct aws_socket *socket, struct aw // aws_mutex_lock(&nw_socket->synced_data.lock); nw_socket->synced_data.event_loop = event_loop; - if (!aws_event_loop_connect_handle_to_completion_port(event_loop, &socket->io_handle)) { + if (!aws_event_loop_connect_handle_to_io_completion_port(event_loop, &socket->io_handle)) { nw_connection_start(socket->io_handle.data.handle); aws_mutex_unlock(&nw_socket->synced_data.lock); return AWS_OP_SUCCESS; @@ -1609,4 +1608,3 @@ int aws_socket_get_bound_address(const struct aws_socket *socket, struct aws_soc *out_address = socket->local_endpoint; return AWS_OP_SUCCESS; } -#endif // AWS_USE_DISPATCH_QUEUE diff --git a/source/posix/socket.c b/source/posix/socket.c index 68ca8d7cf..d8a1d7d63 100644 --- a/source/posix/socket.c +++ b/source/posix/socket.c @@ -264,7 +264,6 @@ static int s_socket_init( socket->options = *options; socket->impl = posix_socket; socket->vtable = &s_vtable; - socket->event_loop_style = AWS_EVENT_LOOP_STYLE_POLL_BASED; if (existing_socket_fd < 0) { int err = s_create_socket(socket, options); diff --git a/source/socket.c b/source/socket.c index 4f0730bee..95c247509 100644 --- a/source/socket.c +++ b/source/socket.c @@ -16,7 +16,6 @@ int aws_socket_connect( aws_socket_on_connection_result_fn *on_connection_result, void *user_data) { AWS_PRECONDITION(socket->vtable && socket->vtable->socket_connect_fn); - AWS_PRECONDITION(socket->event_loop_style & event_loop->vtable->event_loop_style); return socket->vtable->socket_connect_fn(socket, remote_endpoint, event_loop, on_connection_result, user_data); } @@ -61,7 +60,6 @@ int aws_socket_set_options(struct aws_socket *socket, const struct aws_socket_op int aws_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_loop *event_loop) { AWS_PRECONDITION(socket->vtable && socket->vtable->socket_assign_to_event_loop_fn); - AWS_PRECONDITION(socket->event_loop_style & event_loop->vtable->event_loop_style); return socket->vtable->socket_assign_to_event_loop_fn(socket, event_loop); } diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index b2b155e6b..925f65f82 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -433,7 +433,6 @@ static int s_socket_init( socket->state = INIT; socket->impl = impl; socket->options = *options; - socket->event_loop_style = AWS_EVENT_LOOP_STYLE_COMPLETION_PORT_BASED; if (options->domain != AWS_SOCKET_LOCAL && create_underlying_socket) { if (s_create_socket(socket, options)) { From 1b79cbd69f381aa1f18390f791c24ddf8c150db2 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 12:10:28 -0800 Subject: [PATCH 35/72] fix dispatch queue test flag --- README.md | 3 +-- include/aws/io/socket.h | 7 +++---- source/darwin/dispatch_queue_event_loop.c | 4 ---- tests/CMakeLists.txt | 2 +- tests/socket_test.c | 21 +++++++-------------- 5 files changed, 12 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 36fbad8ed..b4a0f0636 100644 --- a/README.md +++ b/README.md @@ -646,8 +646,7 @@ All exported functions, simply shim into the v-table and return. We include a cross-platform API for sockets. We support TCP and UDP using IPv4 and IPv6, and Unix Domain sockets. On Windows, we use Named Pipes to support the functionality of Unix Domain sockets. On Windows, this is implemented with winsock2, and on -all unix platforms we use the posix API. We can also enable Apple Network Framework along with the Apple Dispatch Queue by setting -the preprocessing flag `AWS_USE_DISPATCH_QUEUE`. Then we will use Apple Network Framework on Apple platforms. +all unix platforms we use the posix API. Then we will use Apple Network Framework on Apple platforms. Upon a connection being established, the new socket (either as the result of a `connect()` or `start_accept()` call) will not be attached to any event loops. It is your responsibility to register it with an event loop to begin receiving diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index 01c83084c..621fc17e4 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -213,10 +213,9 @@ AWS_IO_API void aws_socket_clean_up(struct aws_socket *socket); * In TCP, LOCAL and VSOCK this function will not block. If the return value is successful, then you must wait on the * `on_connection_result()` callback to be invoked before using the socket. * - * The function will failed with error if the endpoint is invalid. Except for Apple Network Framework (with - * AWS_USE_DISPATCH_QUEUE enabled). In Apple network framework, as connect is an async api, we would not know if the - * local endpoint is valid until we have the connection state returned in callback. The error will returned in - * `on_connection_result` callback + * The function will failed with error if the endpoint is invalid, except for Apple Network Framework. In Apple network + * framework, as connect is an async api, we would not know if the local endpoint is valid until we have the connection + * state returned in callback. The error will returned in `on_connection_result` callback * * If an event_loop is provided for UDP sockets, a notification will be sent on * on_connection_result in the event-loop's thread. Upon completion, the socket will already be assigned diff --git a/source/darwin/dispatch_queue_event_loop.c b/source/darwin/dispatch_queue_event_loop.c index 842357c67..18e8af76b 100644 --- a/source/darwin/dispatch_queue_event_loop.c +++ b/source/darwin/dispatch_queue_event_loop.c @@ -465,7 +465,6 @@ static void s_cancel_task(struct aws_event_loop *event_loop, struct aws_task *ta static int s_connect_to_dispatch_queue(struct aws_event_loop *event_loop, struct aws_io_handle *handle) { (void)event_loop; (void)handle; -#ifdef AWS_USE_DISPATCH_QUEUE AWS_PRECONDITION(handle->set_queue && handle->clear_queue); AWS_LOGF_TRACE( @@ -475,7 +474,6 @@ static int s_connect_to_dispatch_queue(struct aws_event_loop *event_loop, struct (void *)handle->data.handle); struct dispatch_loop *dispatch_loop = event_loop->impl_data; handle->set_queue(handle, dispatch_loop->dispatch_queue); -#endif // #ifdef AWS_USE_DISPATCH_QUEUE return AWS_OP_SUCCESS; } @@ -485,9 +483,7 @@ static int s_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struc "id=%p: un-subscribing from events on handle %p", (void *)event_loop, (void *)handle->data.handle); -#ifdef AWS_USE_DISPATCH_QUEUE handle->clear_queue(handle); -#endif return AWS_OP_SUCCESS; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 78433a950..56bebddd0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -83,7 +83,7 @@ add_test_case(cleanup_in_write_cb_doesnt_explode) add_test_case(sock_write_cb_is_async) add_test_case(socket_validate_port) -if(NOT AWS_USE_DISPATCH_QUEUE) +if(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) # Apple Network Framework does not support bind+connect add_test_case(udp_bind_connect_communication) # The read/write will always run a different thread for Apple Network Framework diff --git a/tests/socket_test.c b/tests/socket_test.c index 91b0e80ee..f99a765b2 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -23,13 +23,6 @@ # include #endif -// DEBUG WIP -#ifdef AWS_USE_DISPATCH_QUEUE -static bool s_use_dispatch_queue = true; -#else -static bool s_use_dispatch_queue = false; -#endif - struct local_listener_args { struct aws_socket *incoming; struct aws_mutex *mutex; @@ -254,7 +247,7 @@ static int s_test_socket_ex( // The Apple Network Framework always require a "start listener/start connection" // for setup a server socket - if (options->type == AWS_SOCKET_STREAM || s_use_dispatch_queue) { + if (options->type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { ASSERT_SUCCESS(aws_socket_listen(&listener, 1024)); ASSERT_SUCCESS(aws_socket_start_accept(&listener, event_loop, s_local_listener_incoming, &listener_args)); } @@ -269,7 +262,7 @@ static int s_test_socket_ex( } ASSERT_SUCCESS(aws_socket_connect(&outgoing, endpoint, event_loop, s_local_outgoing_connection, &outgoing_args)); - if (listener.options.type == AWS_SOCKET_STREAM || s_use_dispatch_queue) { + if (listener.options.type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { ASSERT_SUCCESS(aws_mutex_lock(&mutex)); ASSERT_SUCCESS( aws_condition_variable_wait_pred(&condition_variable, &mutex, s_incoming_predicate, &listener_args)); @@ -282,7 +275,7 @@ static int s_test_socket_ex( struct aws_socket *server_sock = &listener; - if (options->type == AWS_SOCKET_STREAM || s_use_dispatch_queue) { + if (options->type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { ASSERT_TRUE(listener_args.incoming_invoked); ASSERT_FALSE(listener_args.error_invoked); server_sock = listener_args.incoming; @@ -493,7 +486,7 @@ static int s_test_socket_udp_dispatch_queue( ASSERT_SUCCESS(aws_mutex_unlock(&mutex)); ASSERT_INT_EQUALS(AWS_OP_SUCCESS, io_args.error_code); - if (listener.options.type == AWS_SOCKET_STREAM || s_use_dispatch_queue) { + if (listener.options.type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { ASSERT_SUCCESS(aws_mutex_lock(&mutex)); ASSERT_SUCCESS( aws_condition_variable_wait_pred(&condition_variable, &mutex, s_incoming_predicate, &listener_args)); @@ -593,7 +586,7 @@ static int s_test_socket( struct aws_socket_options *options, struct aws_socket_endpoint *endpoint) { - if (s_use_dispatch_queue && options->type == AWS_SOCKET_DGRAM) + if (aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE && options->type == AWS_SOCKET_DGRAM) return s_test_socket_udp_dispatch_queue(allocator, options, endpoint); else return s_test_socket_ex(allocator, options, NULL, endpoint); @@ -1056,7 +1049,7 @@ static int s_test_outgoing_local_sock_errors(struct aws_allocator *allocator, vo int socket_connect_result = aws_socket_connect(&outgoing, &endpoint, event_loop, s_null_sock_connection, &args); // As Apple network framework has a async API design, we would not get the error back on connect - if (!s_use_dispatch_queue) { + if(aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE){ ASSERT_FAILS(socket_connect_result); ASSERT_TRUE( aws_last_error() == AWS_IO_SOCKET_CONNECTION_REFUSED || aws_last_error() == AWS_ERROR_FILE_INVALID_PATH); @@ -1270,7 +1263,7 @@ static int s_test_bind_on_zero_port( ASSERT_SUCCESS(aws_socket_get_bound_address(&incoming, &local_address1)); - if (s_use_dispatch_queue) { + if (aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; From e84a1a6a8776ce17589e5256cef123f429872def Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 15:35:03 -0800 Subject: [PATCH 36/72] introduce socket vtable --- .github/workflows/ci.yml | 4 +- include/aws/io/event_loop.h | 3 +- include/aws/io/socket.h | 79 +++++++++++- source/event_loop.c | 4 +- source/posix/socket.c | 123 +++++++++++------- source/socket.c | 242 +++++++++++++++++++++++++++++++++++ source/windows/iocp/socket.c | 189 +++++++++++++++------------ 7 files changed, 511 insertions(+), 133 deletions(-) create mode 100644 source/socket.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d101fea08..79ff62a5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -160,7 +160,7 @@ jobs: runs-on: macos-14 # latest strategy: matrix: - eventloop: ["-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=ON", "-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=OFF"] + eventloop: ["-DAWS_USE_APPLE_NETWORK_FRAMEWORK=ON", "-DAWS_USE_APPLE_NETWORK_FRAMEWORK=OFF"] steps: - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | @@ -181,7 +181,7 @@ jobs: runs-on: macos-14 # latest strategy: matrix: - eventloop: ["-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=ON", "-DAWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE=OFF"] + eventloop: ["-DAWS_USE_APPLE_NETWORK_FRAMEWORK=ON", "-DAWS_USE_APPLE_NETWORK_FRAMEWORK=OFF"] steps: - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 671c5c546..0e01d2d04 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -16,8 +16,7 @@ struct aws_shutdown_callback_options; struct aws_task; /** - * Event Loop Type. If set to `AWS_ELT_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default - * event loop type. + * Event Loop Type. If set to `AWS_ELT_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default. * * Default Event Loop Type * Linux | AWS_ELT_EPOLL diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index b0758e222..5d187379d 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -6,6 +6,7 @@ */ #include +#include #include AWS_PUSH_SANE_WARNING_LEVEL @@ -30,11 +31,30 @@ enum aws_socket_type { AWS_SOCKET_DGRAM, }; +/** + * Socket Implementation type. Decides which socket implementation is used. If set to `AWS_SIT_PLATFORM_DEFAULT`, it + * will automatically use the platform’s default. + * + * PLATFORM DEFAULT SOCKET IMPLEMENTATION TYPE + * Linux | AWS_SIT_POSIX + * Windows | AWS_SIT_WINSOCK + * BSD Variants| AWS_SIT_POSIX + * MacOS | AWS_SIT_POSIX + * iOS | AWS_SIT_APPLE_NETWORK_FRAMEWORK + */ +enum aws_socket_impl_type { + AWS_SIT_PLATFORM_DEFAULT, + AWS_SIT_POSIX, + AWS_SIT_WINSOCK, + AWS_SIT_APPLE_NETWORK_FRAMEWORK, +}; + #define AWS_NETWORK_INTERFACE_NAME_MAX 16 struct aws_socket_options { enum aws_socket_type type; enum aws_socket_domain domain; + enum aws_socket_impl_type impl_type; uint32_t connect_timeout_ms; /* Keepalive properties are TCP only. * Set keepalive true to periodically transmit messages for detecting a disconnected peer. @@ -52,8 +72,9 @@ struct aws_socket_options { * This property is used to bind the socket to a particular network interface by name, such as eth0 and ens32. * If this is empty, the socket will not be bound to any interface and will use OS defaults. If the provided name * is invalid, `aws_socket_init()` will error out with AWS_IO_SOCKET_INVALID_OPTIONS. This option is only - * supported on Linux, macOS, and platforms that have either SO_BINDTODEVICE or IP_BOUND_IF. It is not supported on - * Windows. `AWS_ERROR_PLATFORM_NOT_SUPPORTED` will be raised on unsupported platforms. + * supported on Linux, macOS(bsd socket), and platforms that have either SO_BINDTODEVICE or IP_BOUND_IF. It is not + * supported on Windows and Apple Network Framework. `AWS_ERROR_PLATFORM_NOT_SUPPORTED` will be raised on + * unsupported platforms. */ char network_interface_name[AWS_NETWORK_INTERFACE_NAME_MAX]; }; @@ -78,7 +99,7 @@ typedef void(aws_socket_on_connection_result_fn)(struct aws_socket *socket, int * A user may want to call aws_socket_set_options() on the new socket if different options are desired. * * new_socket is not yet assigned to an event-loop. The user should call aws_socket_assign_to_event_loop() before - * performing IO operations. + * performing IO operations. The user is responsible to releasing the socket memory after use. * * When error_code is AWS_ERROR_SUCCESS, new_socket is the recently accepted connection. * If error_code is non-zero, an error occurred and you should aws_socket_close() the socket. @@ -94,6 +115,8 @@ typedef void(aws_socket_on_accept_result_fn)( /** * Callback for when the data passed to a call to aws_socket_write() has either completed or failed. * On success, error_code will be AWS_ERROR_SUCCESS. + * + * socket is possible to be a NULL pointer in the callback. */ typedef void( aws_socket_on_write_completed_fn)(struct aws_socket *socket, int error_code, size_t bytes_written, void *user_data); @@ -114,7 +137,49 @@ struct aws_socket_endpoint { uint32_t port; }; +struct aws_socket; + +struct aws_socket_vtable { + int (*socket_init_fn)( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options); + void (*socket_cleanup_fn)(struct aws_socket *socket); + int (*socket_connect_fn)( + struct aws_socket *socket, + const struct aws_socket_endpoint *remote_endpoint, + struct aws_event_loop *event_loop, + aws_socket_on_connection_result_fn *on_connection_result, + void *user_data); + int (*socket_bind_fn)(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint); + int (*socket_listen_fn)(struct aws_socket *socket, int backlog_size); + int (*socket_start_accept_fn)( + struct aws_socket *socket, + struct aws_event_loop *accept_loop, + aws_socket_on_accept_result_fn *on_accept_result, + void *user_data); + int (*socket_stop_accept_fn)(struct aws_socket *socket); + int (*socket_close_fn)(struct aws_socket *socket); + int (*socket_shutdown_dir_fn)(struct aws_socket *socket, enum aws_channel_direction dir); + int (*socket_set_options_fn)(struct aws_socket *socket, const struct aws_socket_options *options); + int (*socket_assign_to_event_loop_fn)(struct aws_socket *socket, struct aws_event_loop *event_loop); + int (*socket_subscribe_to_readable_events_fn)( + struct aws_socket *socket, + aws_socket_on_readable_fn *on_readable, + void *user_data); + int (*socket_read_fn)(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read); + int (*socket_write_fn)( + struct aws_socket *socket, + const struct aws_byte_cursor *cursor, + aws_socket_on_write_completed_fn *written_fn, + void *user_data); + int (*socket_get_error_fn)(struct aws_socket *socket); + bool (*socket_is_open_fn)(struct aws_socket *socket); + int (*socket_get_bound_address_fn)(const struct aws_socket *socket, struct aws_socket_endpoint *out_address); +}; + struct aws_socket { + struct aws_socket_vtable *vtable; struct aws_allocator *allocator; struct aws_socket_endpoint local_endpoint; struct aws_socket_endpoint remote_endpoint; @@ -172,10 +237,15 @@ AWS_IO_API void aws_socket_clean_up(struct aws_socket *socket); * In TCP, LOCAL and VSOCK this function will not block. If the return value is successful, then you must wait on the * `on_connection_result()` callback to be invoked before using the socket. * + * The function will failed with error if the endpoint is invalid, except for Apple Network Framework. In Apple network + * framework, as connect is an async api, we would not know if the local endpoint is valid until we have the connection + * state returned in callback. The error will returned in `on_connection_result` callback + * * If an event_loop is provided for UDP sockets, a notification will be sent on * on_connection_result in the event-loop's thread. Upon completion, the socket will already be assigned * an event loop. If NULL is passed for UDP, it will immediately return upon success, but you must call * aws_socket_assign_to_event_loop before use. + * */ AWS_IO_API int aws_socket_connect( struct aws_socket *socket, @@ -207,6 +277,7 @@ AWS_IO_API int aws_socket_listen(struct aws_socket *socket, int backlog_size); * connections or errors will arrive via the `on_accept_result` callback. * * aws_socket_bind() and aws_socket_listen() must be called before calling this function. + * */ AWS_IO_API int aws_socket_start_accept( struct aws_socket *socket, @@ -260,7 +331,7 @@ AWS_IO_API int aws_socket_assign_to_event_loop(struct aws_socket *socket, struct AWS_IO_API struct aws_event_loop *aws_socket_get_event_loop(struct aws_socket *socket); /** - * Subscribes on_readable to notifications when the socket goes readable (edge-triggered). Errors will also be recieved + * Subscribes on_readable to notifications when the socket goes readable (edge-triggered). Errors will also be received * in the callback. * * Note! This function is technically not thread safe, but we do not enforce which thread you call from. diff --git a/source/event_loop.c b/source/event_loop.c index 96b9cf172..4017b09a3 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -559,9 +559,9 @@ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_ * If `aws_event_loop_override_default_type` has been called, return the override default type. */ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { -#ifdef AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE +#ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK aws_event_loop_override_default_type(AWS_ELT_DISPATCH_QUEUE); -#endif // AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE +#endif // AWS_USE_APPLE_NETWORK_FRAMEWORK if (s_default_event_loop_type_override != AWS_ELT_PLATFORM_DEFAULT) { return s_default_event_loop_type_override; } diff --git a/source/posix/socket.c b/source/posix/socket.c index 49e18f47e..fd2f39bd8 100644 --- a/source/posix/socket.c +++ b/source/posix/socket.c @@ -188,6 +188,61 @@ struct posix_socket { bool *close_happened; }; +static int s_aws_socket_init( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options); +static void s_socket_clean_up(struct aws_socket *socket); +static int s_socket_connect( + struct aws_socket *socket, + const struct aws_socket_endpoint *remote_endpoint, + struct aws_event_loop *event_loop, + aws_socket_on_connection_result_fn *on_connection_result, + void *user_data); +static int s_socket_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint); +static int s_socket_listen(struct aws_socket *socket, int backlog_size); +static int s_socket_start_accept( + struct aws_socket *socket, + struct aws_event_loop *accept_loop, + aws_socket_on_accept_result_fn *on_accept_result, + void *user_data); +static int s_socket_stop_accept(struct aws_socket *socket); +static int s_socket_set_options(struct aws_socket *socket, const struct aws_socket_options *options); +static int s_socket_close(struct aws_socket *socket); +static int s_socket_shutdown_dir(struct aws_socket *socket, enum aws_channel_direction dir); +static int s_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_loop *event_loop); +static int s_socket_subscribe_to_readable_events( + struct aws_socket *socket, + aws_socket_on_readable_fn *on_readable, + void *user_data); +static int s_socket_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read); +static int s_socket_write( + struct aws_socket *socket, + const struct aws_byte_cursor *cursor, + aws_socket_on_write_completed_fn *written_fn, + void *user_data); +static int s_socket_get_error(struct aws_socket *socket); +static bool s_socket_is_open(struct aws_socket *socket); + +static struct aws_socket_vtable g_posix_socket_vtable = { + .socket_init_fn = s_aws_socket_init, + .socket_cleanup_fn = s_socket_clean_up, + .socket_connect_fn = s_socket_connect, + .socket_bind_fn = s_socket_bind, + .socket_listen_fn = s_socket_listen, + .socket_start_accept_fn = s_socket_start_accept, + .socket_stop_accept_fn = s_socket_stop_accept, + .socket_set_options_fn = s_socket_set_options, + .socket_close_fn = s_socket_close, + .socket_shutdown_dir_fn = s_socket_shutdown_dir, + .socket_assign_to_event_loop_fn = s_socket_assign_to_event_loop, + .socket_subscribe_to_readable_events_fn = s_socket_subscribe_to_readable_events, + .socket_read_fn = s_socket_read, + .socket_write_fn = s_socket_write, + .socket_get_error_fn = s_socket_get_error, + .socket_is_open_fn = s_socket_is_open, +}; + static void s_socket_destroy_impl(void *user_data) { struct posix_socket *socket_impl = user_data; aws_mem_release(socket_impl->allocator, socket_impl); @@ -199,6 +254,7 @@ static int s_socket_init( const struct aws_socket_options *options, int existing_socket_fd) { AWS_ASSERT(options); + AWS_ZERO_STRUCT(*socket); struct posix_socket *posix_socket = aws_mem_calloc(alloc, 1, sizeof(struct posix_socket)); @@ -211,6 +267,8 @@ static int s_socket_init( socket->io_handle.data.fd = -1; socket->state = INIT; socket->options = *options; + socket->impl = posix_socket; + socket->vtable = &g_posix_socket_vtable; if (existing_socket_fd < 0) { int err = s_create_socket(socket, options); @@ -235,16 +293,19 @@ static int s_socket_init( posix_socket->allocator = alloc; posix_socket->connect_args = NULL; posix_socket->close_happened = NULL; - socket->impl = posix_socket; + return AWS_OP_SUCCESS; } -int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options) { +static int s_aws_socket_init( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options) { AWS_ASSERT(options); return s_socket_init(socket, alloc, options, -1); } -void aws_socket_clean_up(struct aws_socket *socket) { +static void s_socket_clean_up(struct aws_socket *socket) { if (!socket->impl) { /* protect from double clean */ return; @@ -601,7 +662,7 @@ static int parse_cid(const char *cid_str, unsigned int *value) { } #endif -int aws_socket_connect( +static int s_socket_connect( struct aws_socket *socket, const struct aws_socket_endpoint *remote_endpoint, struct aws_event_loop *event_loop, @@ -786,7 +847,7 @@ int aws_socket_connect( return AWS_OP_ERR; } -int aws_socket_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint) { +static int s_socket_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint) { if (socket->state != INIT) { AWS_LOGF_ERROR( AWS_LS_IO_SOCKET, @@ -894,20 +955,7 @@ int aws_socket_bind(struct aws_socket *socket, const struct aws_socket_endpoint return AWS_OP_ERR; } -int aws_socket_get_bound_address(const struct aws_socket *socket, struct aws_socket_endpoint *out_address) { - if (socket->local_endpoint.address[0] == 0) { - AWS_LOGF_ERROR( - AWS_LS_IO_SOCKET, - "id=%p fd=%d: Socket has no local address. Socket must be bound first.", - (void *)socket, - socket->io_handle.data.fd); - return aws_raise_error(AWS_IO_SOCKET_ILLEGAL_OPERATION_FOR_STATE); - } - *out_address = socket->local_endpoint; - return AWS_OP_SUCCESS; -} - -int aws_socket_listen(struct aws_socket *socket, int backlog_size) { +static int s_socket_listen(struct aws_socket *socket, int backlog_size) { if (socket->state != BOUND) { AWS_LOGF_ERROR( AWS_LS_IO_SOCKET, @@ -979,7 +1027,7 @@ static void s_socket_accept_event( AWS_LOGF_DEBUG( AWS_LS_IO_SOCKET, "id=%p fd=%d: incoming connection", (void *)socket, socket->io_handle.data.fd); - struct aws_socket *new_sock = aws_mem_acquire(socket->allocator, sizeof(struct aws_socket)); + struct aws_socket *new_sock = aws_mem_calloc(socket->allocator, 1, sizeof(struct aws_socket)); if (!new_sock) { close(in_fd); @@ -1073,7 +1121,7 @@ static void s_socket_accept_event( socket->io_handle.data.fd); } -int aws_socket_start_accept( +static int s_socket_start_accept( struct aws_socket *socket, struct aws_event_loop *accept_loop, aws_socket_on_accept_result_fn *on_accept_result, @@ -1154,7 +1202,7 @@ static void s_stop_accept_task(struct aws_task *task, void *arg, enum aws_task_s aws_mutex_unlock(&stop_accept_args->mutex); } -int aws_socket_stop_accept(struct aws_socket *socket) { +static int s_socket_stop_accept(struct aws_socket *socket) { if (socket->state != LISTENING) { AWS_LOGF_ERROR( AWS_LS_IO_SOCKET, @@ -1214,7 +1262,7 @@ int aws_socket_stop_accept(struct aws_socket *socket) { return ret_val; } -int aws_socket_set_options(struct aws_socket *socket, const struct aws_socket_options *options) { +static int s_socket_set_options(struct aws_socket *socket, const struct aws_socket_options *options) { if (socket->options.domain != options->domain || socket->options.type != options->type) { return aws_raise_error(AWS_IO_SOCKET_INVALID_OPTIONS); } @@ -1446,7 +1494,7 @@ static void s_close_task(struct aws_task *task, void *arg, enum aws_task_status aws_mutex_unlock(&close_args->mutex); } -int aws_socket_close(struct aws_socket *socket) { +static int s_socket_close(struct aws_socket *socket) { struct posix_socket *socket_impl = socket->impl; AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "id=%p fd=%d: closing", (void *)socket, socket->io_handle.data.fd); struct aws_event_loop *event_loop = socket->event_loop; @@ -1548,7 +1596,7 @@ int aws_socket_close(struct aws_socket *socket) { return AWS_OP_SUCCESS; } -int aws_socket_shutdown_dir(struct aws_socket *socket, enum aws_channel_direction dir) { +static int s_socket_shutdown_dir(struct aws_socket *socket, enum aws_channel_direction dir) { int how = dir == AWS_CHANNEL_DIR_READ ? 0 : 1; AWS_LOGF_DEBUG( AWS_LS_IO_SOCKET, "id=%p fd=%d: shutting down in direction %d", (void *)socket, socket->io_handle.data.fd, dir); @@ -1800,7 +1848,7 @@ static void s_on_socket_io_event( aws_ref_count_release(&socket_impl->internal_refcount); } -int aws_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_loop *event_loop) { +static int s_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_loop *event_loop) { if (!socket->event_loop) { AWS_LOGF_DEBUG( AWS_LS_IO_SOCKET, @@ -1835,11 +1883,7 @@ int aws_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_ return aws_raise_error(AWS_IO_EVENT_LOOP_ALREADY_ASSIGNED); } -struct aws_event_loop *aws_socket_get_event_loop(struct aws_socket *socket) { - return socket->event_loop; -} - -int aws_socket_subscribe_to_readable_events( +static int s_socket_subscribe_to_readable_events( struct aws_socket *socket, aws_socket_on_readable_fn *on_readable, void *user_data) { @@ -1871,7 +1915,7 @@ int aws_socket_subscribe_to_readable_events( return AWS_OP_SUCCESS; } -int aws_socket_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read) { +static int s_socket_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read) { AWS_ASSERT(amount_read); if (!aws_event_loop_thread_is_callers_thread(socket->event_loop)) { @@ -1946,7 +1990,7 @@ int aws_socket_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size return aws_raise_error(s_determine_socket_error(errno_value)); } -int aws_socket_write( +static int s_socket_write( struct aws_socket *socket, const struct aws_byte_cursor *cursor, aws_socket_on_write_completed_fn *written_fn, @@ -1982,7 +2026,7 @@ int aws_socket_write( return s_process_socket_write_requests(socket, write_request); } -int aws_socket_get_error(struct aws_socket *socket) { +static int s_socket_get_error(struct aws_socket *socket) { int connect_result; socklen_t result_length = sizeof(connect_result); @@ -1997,19 +2041,10 @@ int aws_socket_get_error(struct aws_socket *socket) { return AWS_OP_SUCCESS; } -bool aws_socket_is_open(struct aws_socket *socket) { +static bool s_socket_is_open(struct aws_socket *socket) { return socket->io_handle.data.fd >= 0; } -void aws_socket_endpoint_init_local_address_for_test(struct aws_socket_endpoint *endpoint) { - struct aws_uuid uuid; - AWS_FATAL_ASSERT(aws_uuid_init(&uuid) == AWS_OP_SUCCESS); - char uuid_str[AWS_UUID_STR_LEN] = {0}; - struct aws_byte_buf uuid_buf = aws_byte_buf_from_empty_array(uuid_str, sizeof(uuid_str)); - AWS_FATAL_ASSERT(aws_uuid_to_str(&uuid, &uuid_buf) == AWS_OP_SUCCESS); - snprintf(endpoint->address, sizeof(endpoint->address), "testsock" PRInSTR ".sock", AWS_BYTE_BUF_PRI(uuid_buf)); -} - bool aws_is_network_interface_name_valid(const char *interface_name) { if (if_nametoindex(interface_name) == 0) { AWS_LOGF_ERROR(AWS_LS_IO_SOCKET, "network_interface_name(%s) is invalid with errno: %d", interface_name, errno); diff --git a/source/socket.c b/source/socket.c new file mode 100644 index 000000000..924e17d0c --- /dev/null +++ b/source/socket.c @@ -0,0 +1,242 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include + +// socket vtables, defined in socket implementation files. +extern struct aws_socket_vtable g_posix_socket_vtable; +extern struct aws_socket_vtable g_winsock_vtable; +// TODO: support extern struct aws_socket_vtable g_apple_nw_vtable; + +void aws_socket_clean_up(struct aws_socket *socket) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_cleanup_fn); + socket->vtable->socket_cleanup_fn(socket); +} + +int aws_socket_connect( + struct aws_socket *socket, + const struct aws_socket_endpoint *remote_endpoint, + struct aws_event_loop *event_loop, + aws_socket_on_connection_result_fn *on_connection_result, + void *user_data) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_connect_fn); + return socket->vtable->socket_connect_fn(socket, remote_endpoint, event_loop, on_connection_result, user_data); +} + +int aws_socket_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_bind_fn); + return socket->vtable->socket_bind_fn(socket, local_endpoint); +} + +int aws_socket_listen(struct aws_socket *socket, int backlog_size) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_listen_fn); + return socket->vtable->socket_listen_fn(socket, backlog_size); +} + +int aws_socket_start_accept( + struct aws_socket *socket, + struct aws_event_loop *accept_loop, + aws_socket_on_accept_result_fn *on_accept_result, + void *user_data) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_listen_fn); + return socket->vtable->socket_start_accept_fn(socket, accept_loop, on_accept_result, user_data); +} + +int aws_socket_stop_accept(struct aws_socket *socket) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_stop_accept_fn); + return socket->vtable->socket_stop_accept_fn(socket); +} + +int aws_socket_close(struct aws_socket *socket) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_close_fn); + return socket->vtable->socket_close_fn(socket); +} + +int aws_socket_shutdown_dir(struct aws_socket *socket, enum aws_channel_direction dir) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_shutdown_dir_fn); + return socket->vtable->socket_shutdown_dir_fn(socket, dir); +} + +int aws_socket_set_options(struct aws_socket *socket, const struct aws_socket_options *options) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_set_options_fn); + return socket->vtable->socket_set_options_fn(socket, options); +} + +int aws_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_loop *event_loop) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_assign_to_event_loop_fn); + return socket->vtable->socket_assign_to_event_loop_fn(socket, event_loop); +} + +struct aws_event_loop *aws_socket_get_event_loop(struct aws_socket *socket) { + return socket->event_loop; +} + +int aws_socket_subscribe_to_readable_events( + struct aws_socket *socket, + aws_socket_on_readable_fn *on_readable, + void *user_data) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_subscribe_to_readable_events_fn); + return socket->vtable->socket_subscribe_to_readable_events_fn(socket, on_readable, user_data); +} + +int aws_socket_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_read_fn); + return socket->vtable->socket_read_fn(socket, buffer, amount_read); +} + +int aws_socket_write( + struct aws_socket *socket, + const struct aws_byte_cursor *cursor, + aws_socket_on_write_completed_fn *written_fn, + void *user_data) { + + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_write_fn); + return socket->vtable->socket_write_fn(socket, cursor, written_fn, user_data); +} + +int aws_socket_get_error(struct aws_socket *socket) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_get_error_fn); + return socket->vtable->socket_get_error_fn(socket); +} + +bool aws_socket_is_open(struct aws_socket *socket) { + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_is_open_fn); + return socket->vtable->socket_is_open_fn(socket); +} + +static enum aws_socket_impl_type aws_socket_get_default_impl_type(void); +static int aws_socket_impl_type_validate_platform(enum aws_socket_impl_type type); +int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options) { + + // 1. get socket type & validate type is avliable the platform + enum aws_socket_impl_type type = options->impl_type; + if (type == AWS_SIT_PLATFORM_DEFAULT) { + type = aws_socket_get_default_impl_type(); + } + + if (aws_socket_impl_type_validate_platform(type)) { + AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Invalid event loop type on the platform."); + return AWS_ERROR_PLATFORM_NOT_SUPPORTED; + } + + // 2. setup vtable based on socket type + switch (type) { + case AWS_SIT_POSIX: +#ifdef g_posix_socket_vtable + socket->vtable = &g_posix_socket_vtable; +#endif + break; + case AWS_SIT_WINSOCK: +#ifdef g_winsock_vtable + socket->vtable = &g_winsock_vtable; + break; +#endif + case AWS_SIT_APPLE_NETWORK_FRAMEWORK: + AWS_ASSERT(false && "Invalid socket implementation on platform."); + // TODO: + // Apple network framework is not supported yet. + // socket->vtable = g_apple_nw_vtable; + break; + default: + AWS_ASSERT(false && "Invalid socket implementation on platform."); + } + + // 3. init the socket + AWS_PRECONDITION(socket->vtable && socket->vtable->socket_init_fn); + return socket->vtable->socket_init_fn(socket, alloc, options); +} + +int aws_socket_get_bound_address(const struct aws_socket *socket, struct aws_socket_endpoint *out_address) { + if (socket->local_endpoint.address[0] == 0) { + AWS_LOGF_ERROR( + AWS_LS_IO_SOCKET, + "id=%p fd=%d: Socket has no local address. Socket must be bound first.", + (void *)socket, + socket->io_handle.data.fd); + return aws_raise_error(AWS_IO_SOCKET_ILLEGAL_OPERATION_FOR_STATE); + } + *out_address = socket->local_endpoint; + return AWS_OP_SUCCESS; +} + +void aws_socket_endpoint_init_local_address_for_test(struct aws_socket_endpoint *endpoint) { + (void)endpoint; + struct aws_uuid uuid; + AWS_FATAL_ASSERT(aws_uuid_init(&uuid) == AWS_OP_SUCCESS); + char uuid_str[AWS_UUID_STR_LEN] = {0}; + struct aws_byte_buf uuid_buf = aws_byte_buf_from_empty_array(uuid_str, sizeof(uuid_str)); + AWS_FATAL_ASSERT(aws_uuid_to_str(&uuid, &uuid_buf) == AWS_OP_SUCCESS); + +#if defined(AWS_USE_KQUEUE) || defined(AWS_USE_EPOLL) + snprintf(endpoint->address, sizeof(endpoint->address), "testsock" PRInSTR ".sock", AWS_BYTE_BUF_PRI(uuid_buf)); + return; +#endif + +#if defined(AWS_USE_IO_COMPLETION_PORTS) + snprintf(endpoint->address, sizeof(endpoint->address), "\\\\.\\pipe\\testsock" PRInSTR, AWS_BYTE_BUF_PRI(uuid_buf)); + return; +#endif +} + +/** + * Return the default socket implementation type. If the return value is `AWS_SIT_PLATFORM_DEFAULT`, the function failed + * to retrieve the default type value. + */ +static enum aws_socket_impl_type aws_socket_get_default_impl_type(void) { + enum aws_socket_impl_type type = AWS_SIT_PLATFORM_DEFAULT; +// override default socket +#ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK + type = AWS_SIT_APPLE_NETWORK_FRAMEWORK; +#endif // AWS_USE_APPLE_NETWORK_FRAMEWORK + if (type != AWS_SIT_PLATFORM_DEFAULT) { + return type; + } +/** + * Ideally we should use the platform definition (e.x.: AWS_OS_APPLE) here, however the platform + * definition was declared in aws-c-common. We probably do not want to introduce extra dependency here. + */ +#if defined(AWS_ENABLE_KQUEUE) || defined(AWS_ENABLE_EPOLL) + return AWS_SIT_POSIX; +#endif +#ifdef AWS_ENABLE_DISPATCH_QUEUE + return AWS_SIT_APPLE_NETWORK_FRAMEWORK; +#endif +#ifdef AWS_ENABLE_IO_COMPLETION_PORTS + return AWS_SIT_WINSOCK; +#else + return AWS_SIT_PLATFORM_DEFAULT; +#endif +} + +static int aws_socket_impl_type_validate_platform(enum aws_socket_impl_type type) { + switch (type) { + case AWS_SIT_POSIX: +#if !defined(AWS_ENABLE_EPOLL) || !defined(AWS_ENABLE_KQUEUE) + AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Posix socket is not supported on the platform."); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); +#endif // AWS_SIT_POSIX + break; + case AWS_SIT_WINSOCK: +#ifndef AWS_ENABLE_IO_COMPLETION_PORTS + AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "WINSOCK is not supported on the platform."); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); +#endif // AWS_ENABLE_IO_COMPLETION_PORTS + break; + case AWS_SIT_APPLE_NETWORK_FRAMEWORK: +#ifndef AWS_ENABLE_DISPATCH_QUEUE + AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Apple Network Framework is not supported on the platform."); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); +#endif // AWS_ENABLE_DISPATCH_QUEUE + break; + default: + AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Invalid socket implementation type."); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); + break; + } + return AWS_OP_SUCCESS; +} diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index 7286bd6ba..dc15d2ea6 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -21,7 +21,6 @@ below, clang-format doesn't work (at least on my version) with the c-style comme #include #include #include -#include #include #include @@ -57,7 +56,7 @@ below, clang-format doesn't work (at least on my version) with the c-style comme #define PIPE_BUFFER_SIZE 512 -struct socket_vtable { +struct winsock_vtable { int (*connection_success)(struct aws_socket *socket); void (*connection_error)(struct aws_socket *socket, int error_code); int (*close)(struct aws_socket *socket); @@ -137,7 +136,7 @@ static int s_local_listen(struct aws_socket *socket, int backlog_size); static int s_tcp_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read); static int s_local_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read); static int s_dgram_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read); -static int s_socket_close(struct aws_socket *socket); +static int s_protocol_socket_close(struct aws_socket *socket); static int s_local_close(struct aws_socket *socket); static int s_ipv4_stream_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint); static int s_ipv4_dgram_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint); @@ -145,6 +144,42 @@ static int s_ipv6_stream_bind(struct aws_socket *socket, const struct aws_socket static int s_ipv6_dgram_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint); static int s_local_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint); +static int s_aws_socket_init( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options); +static void s_socket_clean_up(struct aws_socket *socket); +static int s_socket_connect( + struct aws_socket *socket, + const struct aws_socket_endpoint *remote_endpoint, + struct aws_event_loop *event_loop, + aws_socket_on_connection_result_fn *on_connection_result, + void *user_data); +static int s_socket_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint); +static int s_socket_listen(struct aws_socket *socket, int backlog_size); +static int s_socket_start_accept( + struct aws_socket *socket, + struct aws_event_loop *accept_loop, + aws_socket_on_accept_result_fn *on_accept_result, + void *user_data); +static int s_socket_stop_accept(struct aws_socket *socket); +static int s_socket_set_options(struct aws_socket *socket, const struct aws_socket_options *options); +static int s_socket_close(struct aws_socket *socket); +static int s_socket_shutdown_dir(struct aws_socket *socket, enum aws_channel_direction dir); +static int s_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_loop *event_loop); +static int s_socket_subscribe_to_readable_events( + struct aws_socket *socket, + aws_socket_on_readable_fn *on_readable, + void *user_data); +static int s_socket_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read); +static int s_socket_write( + struct aws_socket *socket, + const struct aws_byte_cursor *cursor, + aws_socket_on_write_completed_fn *written_fn, + void *user_data); +static int s_socket_get_error(struct aws_socket *socket); +static bool s_socket_is_open(struct aws_socket *socket); + static int s_stream_subscribe_to_read( struct aws_socket *socket, aws_socket_on_readable_fn *on_readable, @@ -161,7 +196,7 @@ static int s_determine_socket_error(int error); as well thought out. There were so many branches to handle three entirely different APIs we decided it was less painful to just have a bunch of function pointers in a table than to want to gouge our eyes out while looking at a ridiculous number of branches. */ -static struct socket_vtable vtables[3][2] = { +static struct winsock_vtable s_winsock_vtables[3][2] = { [AWS_SOCKET_IPV4] = { [AWS_SOCKET_STREAM] = @@ -174,7 +209,7 @@ static struct socket_vtable vtables[3][2] = { .bind = s_ipv4_stream_bind, .listen = s_tcp_listen, .read = s_tcp_read, - .close = s_socket_close, + .close = s_protocol_socket_close, .subscribe_to_read = s_stream_subscribe_to_read, }, [AWS_SOCKET_DGRAM] = @@ -187,7 +222,7 @@ static struct socket_vtable vtables[3][2] = { .bind = s_ipv4_dgram_bind, .listen = s_udp_listen, .read = s_dgram_read, - .close = s_socket_close, + .close = s_protocol_socket_close, .subscribe_to_read = s_dgram_subscribe_to_read, }, }, @@ -203,7 +238,7 @@ static struct socket_vtable vtables[3][2] = { .bind = s_ipv6_stream_bind, .listen = s_tcp_listen, .read = s_tcp_read, - .close = s_socket_close, + .close = s_protocol_socket_close, .subscribe_to_read = s_stream_subscribe_to_read, }, [AWS_SOCKET_DGRAM] = @@ -216,7 +251,7 @@ static struct socket_vtable vtables[3][2] = { .bind = s_ipv6_dgram_bind, .listen = s_udp_listen, .read = s_dgram_read, - .close = s_socket_close, + .close = s_protocol_socket_close, .subscribe_to_read = s_dgram_subscribe_to_read, }, }, @@ -239,6 +274,25 @@ static struct socket_vtable vtables[3][2] = { }, }; +static struct aws_socket_vtable g_winsock_vtable = { + .socket_init_fn = s_aws_socket_init, + .socket_cleanup_fn = s_socket_clean_up, + .socket_connect_fn = s_socket_connect, + .socket_bind_fn = s_socket_bind, + .socket_listen_fn = s_socket_listen, + .socket_start_accept_fn = s_socket_start_accept, + .socket_stop_accept_fn = s_socket_stop_accept, + .socket_set_options_fn = s_socket_set_options, + .socket_close_fn = s_socket_close, + .socket_shutdown_dir_fn = s_socket_shutdown_dir, + .socket_assign_to_event_loop_fn = s_socket_assign_to_event_loop, + .socket_subscribe_to_readable_events_fn = s_socket_subscribe_to_readable_events, + .socket_read_fn = s_socket_read, + .socket_write_fn = s_socket_write, + .socket_get_error_fn = s_socket_get_error, + .socket_is_open_fn = s_socket_is_open, +}; + /* When socket is connected, any of the CONNECT_*** flags might be set. Otherwise, only one state flag is active at a time. */ enum socket_state { @@ -298,7 +352,7 @@ struct io_operation_data { }; struct iocp_socket { - struct socket_vtable *vtable; + struct winsock_vtable *winsock_vtable; struct io_operation_data *read_io_data; struct aws_socket *incoming_socket; uint8_t accept_buffer[SOCK_STORAGE_SIZE * 2]; @@ -357,8 +411,10 @@ static int s_socket_init( return AWS_OP_ERR; } - impl->vtable = &vtables[options->domain][options->type]; - if (!impl->vtable || !impl->vtable->read) { + socket->vtable = &g_winsock_vtable; + + impl->winsock_vtable = &s_winsock_vtables[options->domain][options->type]; + if (!impl->winsock_vtable || !impl->winsock_vtable->connection_success) { aws_mem_release(alloc, impl); socket->impl = NULL; return aws_raise_error(AWS_IO_SOCKET_INVALID_OPTIONS); @@ -393,7 +449,10 @@ static int s_socket_init( return AWS_OP_SUCCESS; } -int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options) { +static int s_aws_socket_init( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options) { AWS_ASSERT(options); aws_check_and_init_winsock(); @@ -403,7 +462,7 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons return err; } -void aws_socket_clean_up(struct aws_socket *socket) { +static void s_socket_clean_up(struct aws_socket *socket) { if (!socket->impl) { /* protect from double clean */ return; @@ -414,7 +473,7 @@ void aws_socket_clean_up(struct aws_socket *socket) { (void *)socket, (void *)socket->io_handle.data.handle); struct iocp_socket *socket_impl = socket->impl; - socket_impl->vtable->close(socket); + socket_impl->winsock_vtable->close(socket); if (socket_impl->incoming_socket) { aws_socket_clean_up(socket_impl->incoming_socket); @@ -430,7 +489,7 @@ void aws_socket_clean_up(struct aws_socket *socket) { socket->io_handle.data.handle = INVALID_HANDLE_VALUE; } -int aws_socket_connect( +static int s_socket_connect( struct aws_socket *socket, const struct aws_socket_endpoint *remote_endpoint, struct aws_event_loop *event_loop, @@ -455,10 +514,10 @@ int aws_socket_connect( return AWS_OP_ERR; } - return socket_impl->vtable->connect(socket, remote_endpoint, event_loop, on_connection_result, user_data); + return socket_impl->winsock_vtable->connect(socket, remote_endpoint, event_loop, on_connection_result, user_data); } -int aws_socket_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint) { +static int s_socket_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint) { if (socket->state != INIT) { socket->state = ERRORED; return aws_raise_error(AWS_IO_SOCKET_ILLEGAL_OPERATION_FOR_STATE); @@ -469,20 +528,7 @@ int aws_socket_bind(struct aws_socket *socket, const struct aws_socket_endpoint } struct iocp_socket *socket_impl = socket->impl; - return socket_impl->vtable->bind(socket, local_endpoint); -} - -int aws_socket_get_bound_address(const struct aws_socket *socket, struct aws_socket_endpoint *out_address) { - if (socket->local_endpoint.address[0] == 0) { - AWS_LOGF_ERROR( - AWS_LS_IO_SOCKET, - "id=%p fd=%d: Socket has no local address. Socket must be bound first.", - (void *)socket, - socket->io_handle.data.fd); - return aws_raise_error(AWS_IO_SOCKET_ILLEGAL_OPERATION_FOR_STATE); - } - *out_address = socket->local_endpoint; - return AWS_OP_SUCCESS; + return socket_impl->winsock_vtable->bind(socket, local_endpoint); } /* Update IPV4 or IPV6 socket->local_endpoint based on the results of getsockname() */ @@ -542,31 +588,31 @@ static int s_update_local_endpoint_ipv4_ipv6(struct aws_socket *socket) { return AWS_OP_SUCCESS; } -int aws_socket_listen(struct aws_socket *socket, int backlog_size) { +static int s_socket_listen(struct aws_socket *socket, int backlog_size) { struct iocp_socket *socket_impl = socket->impl; - return socket_impl->vtable->listen(socket, backlog_size); + return socket_impl->winsock_vtable->listen(socket, backlog_size); } -int aws_socket_start_accept( +static int s_socket_start_accept( struct aws_socket *socket, struct aws_event_loop *accept_loop, aws_socket_on_accept_result_fn *on_accept_result, void *user_data) { struct iocp_socket *socket_impl = socket->impl; - return socket_impl->vtable->start_accept(socket, accept_loop, on_accept_result, user_data); + return socket_impl->winsock_vtable->start_accept(socket, accept_loop, on_accept_result, user_data); } -int aws_socket_stop_accept(struct aws_socket *socket) { +static int s_socket_stop_accept(struct aws_socket *socket) { struct iocp_socket *socket_impl = socket->impl; - return socket_impl->vtable->stop_accept(socket); + return socket_impl->winsock_vtable->stop_accept(socket); } -int aws_socket_close(struct aws_socket *socket) { +static int s_socket_close(struct aws_socket *socket) { struct iocp_socket *socket_impl = socket->impl; - return socket_impl->vtable->close(socket); + return socket_impl->winsock_vtable->close(socket); } -int aws_socket_shutdown_dir(struct aws_socket *socket, enum aws_channel_direction dir) { +static int s_socket_shutdown_dir(struct aws_socket *socket, enum aws_channel_direction dir) { int how = dir == AWS_CHANNEL_DIR_READ ? 0 : 1; if (shutdown((SOCKET)socket->io_handle.data.handle, how)) { @@ -583,7 +629,7 @@ int aws_socket_shutdown_dir(struct aws_socket *socket, enum aws_channel_directio return AWS_OP_SUCCESS; } -int aws_socket_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read) { +static int s_socket_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size_t *amount_read) { struct iocp_socket *socket_impl = socket->impl; AWS_ASSERT(socket->readable_fn); @@ -605,10 +651,10 @@ int aws_socket_read(struct aws_socket *socket, struct aws_byte_buf *buffer, size return aws_raise_error(AWS_IO_SOCKET_NOT_CONNECTED); } - return socket_impl->vtable->read(socket, buffer, amount_read); + return socket_impl->winsock_vtable->read(socket, buffer, amount_read); } -int aws_socket_subscribe_to_readable_events( +static int s_socket_subscribe_to_readable_events( struct aws_socket *socket, aws_socket_on_readable_fn *on_readable, void *user_data) { @@ -625,7 +671,7 @@ int aws_socket_subscribe_to_readable_events( return aws_raise_error(AWS_IO_SOCKET_NOT_CONNECTED); } - return socket_impl->vtable->subscribe_to_read(socket, on_readable, user_data); + return socket_impl->winsock_vtable->subscribe_to_read(socket, on_readable, user_data); } static int s_determine_socket_error(int error) { @@ -735,7 +781,7 @@ static int s_ipv4_stream_connection_success(struct aws_socket *socket) { return AWS_OP_SUCCESS; error: socket->state = ERRORED; - socket_impl->vtable->connection_error(socket, aws_last_error()); + socket_impl->winsock_vtable->connection_error(socket, aws_last_error()); return AWS_OP_ERR; } @@ -798,7 +844,7 @@ static int s_ipv6_stream_connection_success(struct aws_socket *socket) { error: socket->state = ERRORED; - socket_impl->vtable->connection_error(socket, aws_last_error()); + socket_impl->winsock_vtable->connection_error(socket, aws_last_error()); return AWS_OP_ERR; } @@ -871,7 +917,7 @@ void s_socket_connection_completion( socket_args->socket = NULL; if (!status_code) { - socket_impl->vtable->connection_success(socket); + socket_impl->winsock_vtable->connection_success(socket); } else { AWS_LOGF_ERROR( AWS_LS_IO_SOCKET, @@ -880,7 +926,7 @@ void s_socket_connection_completion( (void *)socket->io_handle.data.handle, status_code); int error = s_determine_socket_error(status_code); - socket_impl->vtable->connection_error(socket, error); + socket_impl->winsock_vtable->connection_error(socket, error); } } @@ -1175,7 +1221,7 @@ static void s_connection_success_task(struct aws_task *task, void *arg, enum aws struct aws_socket *socket = io_data->socket; struct iocp_socket *socket_impl = socket->impl; - socket_impl->vtable->connection_success(socket); + socket_impl->winsock_vtable->connection_success(socket); } /* initiate the client end of a named pipe. */ @@ -1663,7 +1709,7 @@ static void s_incoming_pipe_connection_event( socket->state = ERRORED; } - socket_impl->vtable->connection_error(socket, aws_last_error()); + socket_impl->winsock_vtable->connection_error(socket, aws_last_error()); operation_data->in_use = false; return; } @@ -1681,7 +1727,7 @@ static void s_incoming_pipe_connection_event( if (!new_socket) { socket->state = ERRORED; operation_data->in_use = false; - socket_impl->vtable->connection_error(socket, AWS_ERROR_OOM); + socket_impl->winsock_vtable->connection_error(socket, AWS_ERROR_OOM); return; } @@ -1689,7 +1735,7 @@ static void s_incoming_pipe_connection_event( aws_mem_release(socket->allocator, new_socket); socket->state = ERRORED; operation_data->in_use = false; - socket_impl->vtable->connection_error(socket, aws_last_error()); + socket_impl->winsock_vtable->connection_error(socket, aws_last_error()); return; } @@ -1721,7 +1767,7 @@ static void s_incoming_pipe_connection_event( (int)GetLastError()); socket->state = ERRORED; operation_data->in_use = false; - socket_impl->vtable->connection_error(socket, aws_last_error()); + socket_impl->winsock_vtable->connection_error(socket, aws_last_error()); return; } @@ -1731,7 +1777,7 @@ static void s_incoming_pipe_connection_event( socket->state = ERRORED; operation_data->in_use = false; aws_socket_clean_up(new_socket); - socket_impl->vtable->connection_error(socket, aws_last_error()); + socket_impl->winsock_vtable->connection_error(socket, aws_last_error()); return; } @@ -1762,7 +1808,7 @@ static void s_incoming_pipe_connection_event( socket->state = ERRORED; socket_impl->read_io_data->in_use = false; int aws_err = s_determine_socket_error(error_code); - socket_impl->vtable->connection_error(socket, aws_err); + socket_impl->winsock_vtable->connection_error(socket, aws_err); return; } else if (error_code == ERROR_PIPE_CONNECTED) { continue_accept_loop = true; @@ -1953,7 +1999,7 @@ static void s_tcp_accept_event( if (err) { if (aws_last_error() != AWS_IO_READ_WOULD_BLOCK) { socket->state = ERRORED; - socket_impl->vtable->connection_error(socket, aws_last_error()); + socket_impl->winsock_vtable->connection_error(socket, aws_last_error()); } return; } @@ -1968,7 +2014,7 @@ static void s_tcp_accept_event( socket->state = ERRORED; int aws_error = s_determine_socket_error(status_code); aws_raise_error(aws_error); - socket_impl->vtable->connection_error(socket, aws_error); + socket_impl->winsock_vtable->connection_error(socket, aws_error); operation_data->in_use = false; } } @@ -2242,7 +2288,7 @@ static int s_dgram_stop_accept(struct aws_socket *socket) { return aws_raise_error(AWS_IO_SOCKET_ILLEGAL_OPERATION_FOR_STATE); } -int aws_socket_set_options(struct aws_socket *socket, const struct aws_socket_options *options) { +static int s_socket_set_options(struct aws_socket *socket, const struct aws_socket_options *options) { if (socket->options.domain != options->domain || socket->options.type != options->type) { return aws_raise_error(AWS_IO_SOCKET_INVALID_OPTIONS); } @@ -2369,8 +2415,6 @@ static bool s_close_predicate(void *arg) { return close_args->invoked; } -static int s_socket_close(struct aws_socket *socket); - static void s_close_task(struct aws_task *task, void *arg, enum aws_task_status status) { (void)task; @@ -2438,7 +2482,7 @@ static int s_wait_on_close(struct aws_socket *socket) { return AWS_OP_SUCCESS; } -static int s_socket_close(struct aws_socket *socket) { +static int s_protocol_socket_close(struct aws_socket *socket) { struct iocp_socket *socket_impl = socket->impl; AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "id=%p handle=%p: closing", (void *)socket, (void *)socket->io_handle.data.handle); @@ -2539,7 +2583,7 @@ int aws_socket_half_close(struct aws_socket *socket, enum aws_channel_direction int error = WSAGetLastError(); int aws_error = s_determine_socket_error(error); aws_raise_error(aws_error); - socket_impl->vtable->connection_error(socket, aws_error); + socket_impl->winsock_vtable->connection_error(socket, aws_error); return AWS_OP_ERR; } @@ -2550,7 +2594,7 @@ struct aws_io_handle *aws_socket_get_io_handle(struct aws_socket *socket) { return &socket->io_handle; } -int aws_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_loop *event_loop) { +static int s_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_loop *event_loop) { if (socket->event_loop) { return aws_raise_error(AWS_IO_EVENT_LOOP_ALREADY_ASSIGNED); } @@ -2559,10 +2603,6 @@ int aws_socket_assign_to_event_loop(struct aws_socket *socket, struct aws_event_ return aws_event_loop_connect_handle_to_io_completion_port(event_loop, &socket->io_handle); } -struct aws_event_loop *aws_socket_get_event_loop(struct aws_socket *socket) { - return socket->event_loop; -} - struct read_cb_args { struct aws_socket *socket; aws_socket_on_readable_fn *user_callback; @@ -3167,7 +3207,7 @@ static void s_socket_written_event( aws_mem_release(operation_data->allocator, write_cb_args); } -int aws_socket_write( +static int s_socket_write( struct aws_socket *socket, const struct aws_byte_cursor *cursor, aws_socket_on_write_completed_fn *written_fn, @@ -3241,7 +3281,7 @@ int aws_socket_write( return AWS_OP_SUCCESS; } -int aws_socket_get_error(struct aws_socket *socket) { +static int s_socket_get_error(struct aws_socket *socket) { if (socket->options.domain != AWS_SOCKET_LOCAL) { int connect_result; socklen_t result_length = sizeof(connect_result); @@ -3261,19 +3301,10 @@ int aws_socket_get_error(struct aws_socket *socket) { return AWS_OP_SUCCESS; } -bool aws_socket_is_open(struct aws_socket *socket) { +static bool s_socket_is_open(struct aws_socket *socket) { return socket->io_handle.data.handle != INVALID_HANDLE_VALUE; } -void aws_socket_endpoint_init_local_address_for_test(struct aws_socket_endpoint *endpoint) { - struct aws_uuid uuid; - AWS_FATAL_ASSERT(aws_uuid_init(&uuid) == AWS_OP_SUCCESS); - char uuid_str[AWS_UUID_STR_LEN] = {0}; - struct aws_byte_buf uuid_buf = aws_byte_buf_from_empty_array(uuid_str, sizeof(uuid_str)); - AWS_FATAL_ASSERT(aws_uuid_to_str(&uuid, &uuid_buf) == AWS_OP_SUCCESS); - snprintf(endpoint->address, sizeof(endpoint->address), "\\\\.\\pipe\\testsock" PRInSTR, AWS_BYTE_BUF_PRI(uuid_buf)); -} - bool aws_is_network_interface_name_valid(const char *interface_name) { (void)interface_name; AWS_LOGF_ERROR(AWS_LS_IO_SOCKET, "network_interface_names are not supported on Windows"); From d79b5b7ad4daabe9e9d51f1949ef9480d284f611 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 15:42:27 -0800 Subject: [PATCH 37/72] fix platform error code --- include/aws/io/socket.h | 2 +- source/event_loop.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index 5d187379d..e5b20cbb7 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -43,7 +43,7 @@ enum aws_socket_type { * iOS | AWS_SIT_APPLE_NETWORK_FRAMEWORK */ enum aws_socket_impl_type { - AWS_SIT_PLATFORM_DEFAULT, + AWS_SIT_PLATFORM_DEFAULT = 0, AWS_SIT_POSIX, AWS_SIT_WINSOCK, AWS_SIT_APPLE_NETWORK_FRAMEWORK, diff --git a/source/event_loop.c b/source/event_loop.c index 4017b09a3..2436c712a 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -69,7 +69,7 @@ struct aws_event_loop *aws_event_loop_new_with_options( break; default: AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type on the platform."); - aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); + aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); break; } @@ -588,30 +588,30 @@ static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) case AWS_ELT_EPOLL: #ifndef AWS_ENABLE_EPOLL AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type EPOLL is not supported on the platform."); - return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_EPOLL break; case AWS_ELT_IOCP: #ifndef AWS_ENABLE_IO_COMPLETION_PORTS AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type IOCP is not supported on the platform."); - return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_IO_COMPLETION_PORTS break; case AWS_ELT_KQUEUE: #ifndef AWS_ENABLE_KQUEUE AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type KQUEUE is not supported on the platform."); - return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_KQUEUE break; case AWS_ELT_DISPATCH_QUEUE: #ifndef AWS_ENABLE_DISPATCH_QUEUE AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type Dispatch Queue is not supported on the platform."); - return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_DISPATCH_QUEUE break; default: AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type."); - return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); break; } return AWS_OP_SUCCESS; From 3ce216c0d1a5edebfe254032556cc1be0222d794 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 16:32:14 -0800 Subject: [PATCH 38/72] remove global vtable --- include/aws/io/socket.h | 23 ++++++++++--- source/event_loop.c | 2 +- source/posix/socket.c | 9 ++--- source/socket.c | 67 +++++++++++++++++++++++++----------- source/windows/iocp/socket.c | 9 ++--- 5 files changed, 71 insertions(+), 39 deletions(-) diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index e5b20cbb7..0e2f9b2bd 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -140,10 +140,6 @@ struct aws_socket_endpoint { struct aws_socket; struct aws_socket_vtable { - int (*socket_init_fn)( - struct aws_socket *socket, - struct aws_allocator *alloc, - const struct aws_socket_options *options); void (*socket_cleanup_fn)(struct aws_socket *socket); int (*socket_connect_fn)( struct aws_socket *socket, @@ -210,6 +206,25 @@ aws_ms_fn_ptr aws_winsock_get_connectex_fn(void); aws_ms_fn_ptr aws_winsock_get_acceptex_fn(void); #endif + +AWS_IO_API int aws_socket_init_posix( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options); + + +AWS_IO_API int aws_socket_init_winsock( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options); + + +AWS_IO_API int aws_socket_init_apple_nw_socket( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options); + + AWS_EXTERN_C_BEGIN /** diff --git a/source/event_loop.c b/source/event_loop.c index 2436c712a..56e45fda2 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -611,7 +611,7 @@ static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) break; default: AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type."); - return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); + return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); break; } return AWS_OP_SUCCESS; diff --git a/source/posix/socket.c b/source/posix/socket.c index fd2f39bd8..9ea344280 100644 --- a/source/posix/socket.c +++ b/source/posix/socket.c @@ -188,10 +188,6 @@ struct posix_socket { bool *close_happened; }; -static int s_aws_socket_init( - struct aws_socket *socket, - struct aws_allocator *alloc, - const struct aws_socket_options *options); static void s_socket_clean_up(struct aws_socket *socket); static int s_socket_connect( struct aws_socket *socket, @@ -224,8 +220,7 @@ static int s_socket_write( static int s_socket_get_error(struct aws_socket *socket); static bool s_socket_is_open(struct aws_socket *socket); -static struct aws_socket_vtable g_posix_socket_vtable = { - .socket_init_fn = s_aws_socket_init, +struct aws_socket_vtable g_posix_socket_vtable = { .socket_cleanup_fn = s_socket_clean_up, .socket_connect_fn = s_socket_connect, .socket_bind_fn = s_socket_bind, @@ -297,7 +292,7 @@ static int s_socket_init( return AWS_OP_SUCCESS; } -static int s_aws_socket_init( +int aws_socket_init_posix( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options) { diff --git a/source/socket.c b/source/socket.c index 924e17d0c..cfecec59a 100644 --- a/source/socket.c +++ b/source/socket.c @@ -8,11 +8,6 @@ #include #include -// socket vtables, defined in socket implementation files. -extern struct aws_socket_vtable g_posix_socket_vtable; -extern struct aws_socket_vtable g_winsock_vtable; -// TODO: support extern struct aws_socket_vtable g_apple_nw_vtable; - void aws_socket_clean_up(struct aws_socket *socket) { AWS_PRECONDITION(socket->vtable && socket->vtable->socket_cleanup_fn); socket->vtable->socket_cleanup_fn(socket); @@ -127,28 +122,21 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons // 2. setup vtable based on socket type switch (type) { case AWS_SIT_POSIX: -#ifdef g_posix_socket_vtable - socket->vtable = &g_posix_socket_vtable; -#endif + return aws_socket_init_posix(socket, alloc, options); break; case AWS_SIT_WINSOCK: -#ifdef g_winsock_vtable - socket->vtable = &g_winsock_vtable; + return aws_socket_init_winsock(socket, alloc, options); break; -#endif + case AWS_SIT_APPLE_NETWORK_FRAMEWORK: AWS_ASSERT(false && "Invalid socket implementation on platform."); - // TODO: - // Apple network framework is not supported yet. - // socket->vtable = g_apple_nw_vtable; + return aws_socket_init_apple_nw_socket(socket, alloc, options); break; default: - AWS_ASSERT(false && "Invalid socket implementation on platform."); + break; } - - // 3. init the socket - AWS_PRECONDITION(socket->vtable && socket->vtable->socket_init_fn); - return socket->vtable->socket_init_fn(socket, alloc, options); + AWS_ASSERT(false && "Invalid socket implementation on platform."); + return AWS_ERROR_PLATFORM_NOT_SUPPORTED; } int aws_socket_get_bound_address(const struct aws_socket *socket, struct aws_socket_endpoint *out_address) { @@ -216,7 +204,7 @@ static enum aws_socket_impl_type aws_socket_get_default_impl_type(void) { static int aws_socket_impl_type_validate_platform(enum aws_socket_impl_type type) { switch (type) { case AWS_SIT_POSIX: -#if !defined(AWS_ENABLE_EPOLL) || !defined(AWS_ENABLE_KQUEUE) +#if !defined(AWS_ENABLE_EPOLL) && !defined(AWS_ENABLE_KQUEUE) AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Posix socket is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_SIT_POSIX @@ -240,3 +228,42 @@ static int aws_socket_impl_type_validate_platform(enum aws_socket_impl_type type } return AWS_OP_SUCCESS; } + +#if !defined(AWS_ENABLE_EPOLL) && !defined(AWS_ENABLE_KQUEUE) +int aws_socket_init_posix( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options) { + (void)socket; + (void)alloc; + (void)options; + AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Posix socket is not supported on the platform."); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); +} +#endif + +#ifndef AWS_ENABLE_IO_COMPLETION_PORTS +int aws_socket_init_winsock( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options) { + (void)socket; + (void)alloc; + (void)options; + AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "WINSOCK is not supported on the platform."); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); +} +#endif + +#ifndef AWS_ENABLE_DISPATCH_QUEUE +int aws_socket_init_apple_nw_socket( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options) { + (void)socket; + (void)alloc; + (void)options; + AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Apple Network Framework is not supported on the platform."); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); +} +#endif diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index dc15d2ea6..c398c9d5d 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -144,10 +144,6 @@ static int s_ipv6_stream_bind(struct aws_socket *socket, const struct aws_socket static int s_ipv6_dgram_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint); static int s_local_bind(struct aws_socket *socket, const struct aws_socket_endpoint *local_endpoint); -static int s_aws_socket_init( - struct aws_socket *socket, - struct aws_allocator *alloc, - const struct aws_socket_options *options); static void s_socket_clean_up(struct aws_socket *socket); static int s_socket_connect( struct aws_socket *socket, @@ -274,8 +270,7 @@ static struct winsock_vtable s_winsock_vtables[3][2] = { }, }; -static struct aws_socket_vtable g_winsock_vtable = { - .socket_init_fn = s_aws_socket_init, +struct aws_socket_vtable g_winsock_vtable = { .socket_cleanup_fn = s_socket_clean_up, .socket_connect_fn = s_socket_connect, .socket_bind_fn = s_socket_bind, @@ -449,7 +444,7 @@ static int s_socket_init( return AWS_OP_SUCCESS; } -static int s_aws_socket_init( +int aws_socket_init_winsock( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options) { From 6233c9dd916ee3bf8a470931c35a4641281fa073 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 16:42:34 -0800 Subject: [PATCH 39/72] fix flag --- include/aws/io/socket.h | 1 - source/socket.c | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index 0e2f9b2bd..ab295b576 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -171,7 +171,6 @@ struct aws_socket_vtable { void *user_data); int (*socket_get_error_fn)(struct aws_socket *socket); bool (*socket_is_open_fn)(struct aws_socket *socket); - int (*socket_get_bound_address_fn)(const struct aws_socket *socket, struct aws_socket_endpoint *out_address); }; struct aws_socket { diff --git a/source/socket.c b/source/socket.c index cfecec59a..a1fb739c1 100644 --- a/source/socket.c +++ b/source/socket.c @@ -133,7 +133,7 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons return aws_socket_init_apple_nw_socket(socket, alloc, options); break; default: - break; + break; } AWS_ASSERT(false && "Invalid socket implementation on platform."); return AWS_ERROR_PLATFORM_NOT_SUPPORTED; @@ -160,12 +160,12 @@ void aws_socket_endpoint_init_local_address_for_test(struct aws_socket_endpoint struct aws_byte_buf uuid_buf = aws_byte_buf_from_empty_array(uuid_str, sizeof(uuid_str)); AWS_FATAL_ASSERT(aws_uuid_to_str(&uuid, &uuid_buf) == AWS_OP_SUCCESS); -#if defined(AWS_USE_KQUEUE) || defined(AWS_USE_EPOLL) +#if defined(AWS_ENABLE_KQUEUE) || defined(AWS_ENABLE_EPOLL) snprintf(endpoint->address, sizeof(endpoint->address), "testsock" PRInSTR ".sock", AWS_BYTE_BUF_PRI(uuid_buf)); return; #endif -#if defined(AWS_USE_IO_COMPLETION_PORTS) +#if defined(AWS_ENABLE_IO_COMPLETION_PORTS) snprintf(endpoint->address, sizeof(endpoint->address), "\\\\.\\pipe\\testsock" PRInSTR, AWS_BYTE_BUF_PRI(uuid_buf)); return; #endif From 70008b15363c691b4b04e4631fcee16c194d4f83 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 17:05:01 -0800 Subject: [PATCH 40/72] fix implicit function call --- include/aws/io/event_loop.h | 8 ++++++++ source/event_loop.c | 3 +-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 0e01d2d04..441432cc7 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -69,6 +69,14 @@ struct aws_event_loop_group_options { aws_io_clock_fn *clock_override; }; +/** + * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to + * retrieve the default type value. + * If `aws_event_loop_override_default_type` has been called, return the override default type. + */ +AWS_IO_API +enum aws_event_loop_type aws_event_loop_get_default_type(void); + AWS_EXTERN_C_BEGIN /** diff --git a/source/event_loop.c b/source/event_loop.c index 1b95902a6..1a5103d5d 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -38,7 +38,6 @@ struct aws_event_loop *aws_event_loop_new_default_with_options( return aws_event_loop_new_with_options(alloc, &local_options); } -static enum aws_event_loop_type aws_event_loop_get_default_type(void); static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type); struct aws_event_loop *aws_event_loop_new_with_options( struct aws_allocator *alloc, @@ -558,7 +557,7 @@ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_ * retrieve the default type value. * If `aws_event_loop_override_default_type` has been called, return the override default type. */ -static enum aws_event_loop_type aws_event_loop_get_default_type(void) { +enum aws_event_loop_type aws_event_loop_get_default_type(void) { #ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK aws_event_loop_override_default_type(AWS_ELT_DISPATCH_QUEUE); #endif // AWS_USE_APPLE_NETWORK_FRAMEWORK From 0f751853ccbc8907a77ff98484dadb51ec21ab4d Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 17:14:48 -0800 Subject: [PATCH 41/72] set apple networkframework flag --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0e9f52ab..f33fb1bc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,6 +218,10 @@ if (USE_VSOCK) target_compile_definitions(${PROJECT_NAME} PUBLIC "-DUSE_VSOCK") endif() +if (AWS_USE_APPLE_NETWORK_FRAMEWORK) + target_compile_definitions(${PROJECT_NAME} PRIVATE "-DAWS_USE_APPLE_NETWORK_FRAMEWORK") +endif() + target_include_directories(${PROJECT_NAME} PUBLIC $ $) From f7fb5a2cfdb66c4230305ad16e6349cb7b5f28cc Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 17:18:42 -0800 Subject: [PATCH 42/72] prevent fail fast --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79ff62a5d..3d423b936 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -159,6 +159,7 @@ jobs: macos: runs-on: macos-14 # latest strategy: + fail-fast: false matrix: eventloop: ["-DAWS_USE_APPLE_NETWORK_FRAMEWORK=ON", "-DAWS_USE_APPLE_NETWORK_FRAMEWORK=OFF"] steps: @@ -180,6 +181,7 @@ jobs: macos-debug: runs-on: macos-14 # latest strategy: + fail-fast: false matrix: eventloop: ["-DAWS_USE_APPLE_NETWORK_FRAMEWORK=ON", "-DAWS_USE_APPLE_NETWORK_FRAMEWORK=OFF"] steps: From 28b75463aa88b891ad19c240429a94f2ffd08ee4 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 17:52:01 -0800 Subject: [PATCH 43/72] update socket api changes for network framework --- source/darwin/nw_socket.c | 21 --------------------- source/socket.c | 5 +++++ tests/CMakeLists.txt | 6 +++--- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/source/darwin/nw_socket.c b/source/darwin/nw_socket.c index a54367aa5..25fd09750 100644 --- a/source/darwin/nw_socket.c +++ b/source/darwin/nw_socket.c @@ -1587,24 +1587,3 @@ static bool s_socket_is_open_fn(struct aws_socket *socket) { return nw_socket->last_error == AWS_OP_SUCCESS; } -void aws_socket_endpoint_init_local_address_for_test(struct aws_socket_endpoint *endpoint) { - struct aws_uuid uuid; - AWS_FATAL_ASSERT(aws_uuid_init(&uuid) == AWS_OP_SUCCESS); - char uuid_str[AWS_UUID_STR_LEN] = {0}; - struct aws_byte_buf uuid_buf = aws_byte_buf_from_empty_array(uuid_str, sizeof(uuid_str)); - AWS_FATAL_ASSERT(aws_uuid_to_str(&uuid, &uuid_buf) == AWS_OP_SUCCESS); - snprintf(endpoint->address, sizeof(endpoint->address), "testsock" PRInSTR ".local", AWS_BYTE_BUF_PRI(uuid_buf)); -} - -int aws_socket_get_bound_address(const struct aws_socket *socket, struct aws_socket_endpoint *out_address) { - if (socket->local_endpoint.address[0] == 0) { - AWS_LOGF_ERROR( - AWS_LS_IO_SOCKET, - "id=%p fd=%d: Socket has no local address. Socket must be bound first.", - (void *)socket, - socket->io_handle.data.fd); - return aws_raise_error(AWS_IO_SOCKET_ILLEGAL_OPERATION_FOR_STATE); - } - *out_address = socket->local_endpoint; - return AWS_OP_SUCCESS; -} diff --git a/source/socket.c b/source/socket.c index a1fb739c1..ed5c1a762 100644 --- a/source/socket.c +++ b/source/socket.c @@ -160,6 +160,11 @@ void aws_socket_endpoint_init_local_address_for_test(struct aws_socket_endpoint struct aws_byte_buf uuid_buf = aws_byte_buf_from_empty_array(uuid_str, sizeof(uuid_str)); AWS_FATAL_ASSERT(aws_uuid_to_str(&uuid, &uuid_buf) == AWS_OP_SUCCESS); +#if defined(WS_USE_APPLE_NETWORK_FRAMEWORK) + snprintf(endpoint->address, sizeof(endpoint->address), "testsock" PRInSTR ".local", AWS_BYTE_BUF_PRI(uuid_buf)); + return; +#endif + #if defined(AWS_ENABLE_KQUEUE) || defined(AWS_ENABLE_EPOLL) snprintf(endpoint->address, sizeof(endpoint->address), "testsock" PRInSTR ".sock", AWS_BYTE_BUF_PRI(uuid_buf)); return; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 56bebddd0..f96080aee 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,7 +18,7 @@ add_test_case(io_library_init) add_test_case(io_library_init_cleanup_init_cleanup) # Dispatch Queue does not support pipe -if(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) +if(NOT AWS_USE_APPLE_NETWORK_FRAMEWORK) add_pipe_test_case(pipe_open_close) add_pipe_test_case(pipe_read_write) add_pipe_test_case(pipe_read_write_large_buffer) @@ -39,7 +39,7 @@ add_test_case(event_loop_canceled_tasks_run_in_el_thread) if(USE_IO_COMPLETION_PORTS) add_test_case(event_loop_completion_events) -elseif(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) # Dispatch Queue does not support pipe +elseif(NOT AWS_USE_APPLE_NETWORK_FRAMEWORK) # Dispatch Queue does not support pipe add_test_case(event_loop_subscribe_unsubscribe) add_test_case(event_loop_writable_event_on_subscribe) add_test_case(event_loop_no_readable_event_before_write) @@ -83,7 +83,7 @@ add_test_case(cleanup_in_write_cb_doesnt_explode) add_test_case(sock_write_cb_is_async) add_test_case(socket_validate_port) -if(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) +if(NOT AWS_USE_APPLE_NETWORK_FRAMEWORK) # Apple Network Framework does not support bind+connect add_test_case(udp_bind_connect_communication) # The read/write will always run a different thread for Apple Network Framework From 16861b9946f252186aa7066052aad07ca9dd3667 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 18:00:11 -0800 Subject: [PATCH 44/72] update cmake event loop defines --- CMakeLists.txt | 14 ++++++++------ source/event_loop.c | 2 -- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f33fb1bc0..95ad373aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ if (WIN32) ) list(APPEND AWS_IO_OS_SRC ${AWS_IO_IOCP_SRC}) - set(EVENT_LOOP_DEFINE "IO_COMPLETION_PORTS") + list(APPEND EVENT_LOOP_DEFINES "IO_COMPLETION_PORTS") endif () if (MSVC) @@ -102,7 +102,7 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "Androi ) set(PLATFORM_LIBS "") - set(EVENT_LOOP_DEFINE "EPOLL") + list(APPEND EVENT_LOOP_DEFINES "EPOLL") set(USE_S2N ON) elseif (APPLE) @@ -126,7 +126,7 @@ elseif (APPLE) #No choice on TLS for apple, darwinssl will always be used. list(APPEND PLATFORM_LIBS "-framework Security -framework Network") - set(EVENT_LOOP_DEFINES "DISPATCH_QUEUE" ) + list(APPEND EVENT_LOOP_DEFINES "DISPATCH_QUEUE") # Enable KQUEUE on MacOS if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") @@ -135,7 +135,7 @@ elseif (APPLE) "source/posix/*.c" ) list(APPEND AWS_IO_OS_SRC ${AWS_IO_KUEUE_SRC}) - set(EVENT_LOOP_DEFINE "KQUEUE") + list(APPEND EVENT_LOOP_DEFINES "KQUEUE") endif() elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") @@ -147,7 +147,7 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "NetB "source/posix/*.c" ) - set(EVENT_LOOP_DEFINE "KQUEUE") + list(APPEND EVENT_LOOP_DEFINES "KQUEUE") set(USE_S2N ON) endif() @@ -200,7 +200,9 @@ aws_add_sanitizers(${PROJECT_NAME}) # We are not ABI stable yet set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0) -target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_ENABLE_${EVENT_LOOP_DEFINE}") +foreach(EVENT_LOOP_DEFINE IN LISTS EVENT_LOOP_DEFINES) + target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_ENABLE_${EVENT_LOOP_DEFINE}") +endforeach() if (BYO_CRYPTO) target_compile_definitions(${PROJECT_NAME} PUBLIC "-DBYO_CRYPTO") diff --git a/source/event_loop.c b/source/event_loop.c index 56e45fda2..68430346e 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -617,7 +617,6 @@ static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) return AWS_OP_SUCCESS; } -#ifndef AWS_ENABLE_DISPATCH_QUEUE struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { @@ -628,7 +627,6 @@ struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Dispatch Queue is not supported on the platform"); return NULL; } -#endif // AWS_ENABLE_DISPATCH_QUEUE #ifndef AWS_ENABLE_IO_COMPLETION_PORTS struct aws_event_loop *aws_event_loop_new_iocp_with_options( From 8d946dbce853fa48ab280e28b87e0752e5e671a2 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 18:02:47 -0800 Subject: [PATCH 45/72] temporary remove dispatch queue wrap --- source/socket.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/socket.c b/source/socket.c index a1fb739c1..c4a8e9759 100644 --- a/source/socket.c +++ b/source/socket.c @@ -255,7 +255,6 @@ int aws_socket_init_winsock( } #endif -#ifndef AWS_ENABLE_DISPATCH_QUEUE int aws_socket_init_apple_nw_socket( struct aws_socket *socket, struct aws_allocator *alloc, @@ -266,4 +265,3 @@ int aws_socket_init_apple_nw_socket( AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Apple Network Framework is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); } -#endif From 17c7cca73006c8793692183fc7a4b506ee11f945 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 18:03:46 -0800 Subject: [PATCH 46/72] temporary remove dispatch queue wrap --- source/socket.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/socket.c b/source/socket.c index a1fb739c1..c4a8e9759 100644 --- a/source/socket.c +++ b/source/socket.c @@ -255,7 +255,6 @@ int aws_socket_init_winsock( } #endif -#ifndef AWS_ENABLE_DISPATCH_QUEUE int aws_socket_init_apple_nw_socket( struct aws_socket *socket, struct aws_allocator *alloc, @@ -266,4 +265,3 @@ int aws_socket_init_apple_nw_socket( AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Apple Network Framework is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); } -#endif From afd634da2552991e80ffeb2626bfa3c71545d407 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 18:23:49 -0800 Subject: [PATCH 47/72] update dispatch queue related flags --- CMakeLists.txt | 3 +++ source/event_loop.c | 2 ++ source/socket.c | 7 +++++-- tests/CMakeLists.txt | 18 +++++++++++++----- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd3bfd387..fb14f7f35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,9 @@ endif() if (AWS_USE_APPLE_NETWORK_FRAMEWORK) target_compile_definitions(${PROJECT_NAME} PRIVATE "-DAWS_USE_APPLE_NETWORK_FRAMEWORK") + option(AWS_USE_APPLE_NETWORK_FRAMEWORK + "Use apple network framework as default event loop and socket options." + ON) endif() target_include_directories(${PROJECT_NAME} PUBLIC diff --git a/source/event_loop.c b/source/event_loop.c index f78c3b89d..1a5103d5d 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -618,6 +618,7 @@ static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) return AWS_OP_SUCCESS; } +#ifndef AWS_ENABLE_DISPATCH_QUEUE struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { @@ -628,6 +629,7 @@ struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Dispatch Queue is not supported on the platform"); return NULL; } +#endif // AWS_ENABLE_DISPATCH_QUEUE #ifndef AWS_ENABLE_IO_COMPLETION_PORTS struct aws_event_loop *aws_event_loop_new_iocp_with_options( diff --git a/source/socket.c b/source/socket.c index c4a8e9759..f373e23fc 100644 --- a/source/socket.c +++ b/source/socket.c @@ -127,9 +127,7 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons case AWS_SIT_WINSOCK: return aws_socket_init_winsock(socket, alloc, options); break; - case AWS_SIT_APPLE_NETWORK_FRAMEWORK: - AWS_ASSERT(false && "Invalid socket implementation on platform."); return aws_socket_init_apple_nw_socket(socket, alloc, options); break; default: @@ -160,6 +158,11 @@ void aws_socket_endpoint_init_local_address_for_test(struct aws_socket_endpoint struct aws_byte_buf uuid_buf = aws_byte_buf_from_empty_array(uuid_str, sizeof(uuid_str)); AWS_FATAL_ASSERT(aws_uuid_to_str(&uuid, &uuid_buf) == AWS_OP_SUCCESS); +#if defined(WS_USE_APPLE_NETWORK_FRAMEWORK) + snprintf(endpoint->address, sizeof(endpoint->address), "testsock" PRInSTR ".local", AWS_BYTE_BUF_PRI(uuid_buf)); + return; +#endif + #if defined(AWS_ENABLE_KQUEUE) || defined(AWS_ENABLE_EPOLL) snprintf(endpoint->address, sizeof(endpoint->address), "testsock" PRInSTR ".sock", AWS_BYTE_BUF_PRI(uuid_buf)); return; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index afcc1979c..f96080aee 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,7 +18,7 @@ add_test_case(io_library_init) add_test_case(io_library_init_cleanup_init_cleanup) # Dispatch Queue does not support pipe -if(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) +if(NOT AWS_USE_APPLE_NETWORK_FRAMEWORK) add_pipe_test_case(pipe_open_close) add_pipe_test_case(pipe_read_write) add_pipe_test_case(pipe_read_write_large_buffer) @@ -39,7 +39,7 @@ add_test_case(event_loop_canceled_tasks_run_in_el_thread) if(USE_IO_COMPLETION_PORTS) add_test_case(event_loop_completion_events) -elseif(NOT AWS_EVENT_LOOP_DISPATCH_QUEUE_OVERRIDE) # Dispatch Queue does not support pipe +elseif(NOT AWS_USE_APPLE_NETWORK_FRAMEWORK) # Dispatch Queue does not support pipe add_test_case(event_loop_subscribe_unsubscribe) add_test_case(event_loop_writable_event_on_subscribe) add_test_case(event_loop_no_readable_event_before_write) @@ -63,7 +63,6 @@ add_net_test_case(udp_socket_communication) add_net_test_case(test_socket_with_bind_to_interface) add_net_test_case(test_socket_with_bind_to_invalid_interface) add_net_test_case(test_is_network_interface_name_valid) -add_test_case(udp_bind_connect_communication) add_net_test_case(connect_timeout) add_net_test_case(connect_timeout_cancelation) @@ -75,17 +74,26 @@ endif() add_test_case(outgoing_local_sock_errors) add_test_case(outgoing_tcp_sock_error) add_test_case(incoming_tcp_sock_errors) -add_test_case(incoming_duplicate_tcp_bind_errors) add_net_test_case(bind_on_zero_port_tcp_ipv4) add_net_test_case(bind_on_zero_port_udp_ipv4) add_test_case(incoming_udp_sock_errors) -add_test_case(wrong_thread_read_write_fails) add_net_test_case(cleanup_before_connect_or_timeout_doesnt_explode) add_test_case(cleanup_in_accept_doesnt_explode) add_test_case(cleanup_in_write_cb_doesnt_explode) add_test_case(sock_write_cb_is_async) add_test_case(socket_validate_port) +if(NOT AWS_USE_APPLE_NETWORK_FRAMEWORK) +# Apple Network Framework does not support bind+connect +add_test_case(udp_bind_connect_communication) +# The read/write will always run a different thread for Apple Network Framework +add_test_case(wrong_thread_read_write_fails) +# Apple Network Framework would not validate the binding endpoint until we start the +# listen. The test does not apply here. +add_test_case(incoming_duplicate_tcp_bind_errors) +endif() + + if(WIN32) add_test_case(local_socket_pipe_connected_race) endif() From 0d69dd70e9df42d11abae8de344a243db0b8edec Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 19:37:24 -0800 Subject: [PATCH 48/72] add apple socket init --- source/darwin/nw_socket.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/darwin/nw_socket.c b/source/darwin/nw_socket.c index 25fd09750..d959cf6f9 100644 --- a/source/darwin/nw_socket.c +++ b/source/darwin/nw_socket.c @@ -323,7 +323,10 @@ static void s_socket_impl_destroy(void *sock_ptr) { nw_socket = NULL; } -int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options) { +int aws_socket_init_apple_nw_socket( + struct aws_socket *socket, + struct aws_allocator *alloc, + const struct aws_socket_options *options) { AWS_ASSERT(options); AWS_ZERO_STRUCT(*socket); From d68acdb80838ee024538d7ebec9ba6ce0c81fa8e Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Mon, 11 Nov 2024 07:26:43 -0800 Subject: [PATCH 49/72] Doc comments --- include/aws/io/event_loop.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 093e632f5..f5815e583 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -192,9 +192,20 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou uint16_t cpu_group, const struct aws_shutdown_callback_options *shutdown_options); +/** + * Returns the opaque internal user data of an event loop. Can be cast into a specific implementation by + * privileged consumers. + * + * @internal - Don't use outside of testing. + */ AWS_IO_API void *aws_event_loop_get_impl(struct aws_event_loop *event_loop); +/** + * Initializes the base structure used by all event loop implementations with test-oriented overrides. + * + * @internal - Don't use outside of testing. + */ AWS_IO_API struct aws_event_loop *aws_event_loop_new_base( struct aws_allocator *allocator, @@ -205,6 +216,8 @@ struct aws_event_loop *aws_event_loop_new_base( /** * Common cleanup code for all implementations. * This is only called from the *destroy() function of event loop implementations. + * + * @internal - Don't use outside of testing. */ AWS_IO_API void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); @@ -215,6 +228,8 @@ void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); * If you do not want this function to block, call aws_event_loop_stop() manually first. * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads * must ensure their API calls to the event loop happen-before the call to destroy. + * + * @internal - Don't use outside of testing. */ AWS_IO_API void aws_event_loop_destroy(struct aws_event_loop *event_loop); From b28743ce88b2d0906685c44474d5cab682ac8369 Mon Sep 17 00:00:00 2001 From: subdiox Date: Tue, 12 Nov 2024 01:51:50 +0900 Subject: [PATCH 50/72] Add cxx support (#689) --- include/aws/testing/io_testing_channel.h | 50 +++++++++++++----------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/include/aws/testing/io_testing_channel.h b/include/aws/testing/io_testing_channel.h index d2f1c13a5..192a269b0 100644 --- a/include/aws/testing/io_testing_channel.h +++ b/include/aws/testing/io_testing_channel.h @@ -33,7 +33,7 @@ static int s_testing_loop_wait_for_stop_completion(struct aws_event_loop *event_ } static void s_testing_loop_schedule_task_now(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; aws_task_scheduler_schedule_now(&testing_loop->scheduler, task); } @@ -42,22 +42,22 @@ static void s_testing_loop_schedule_task_future( struct aws_task *task, uint64_t run_at_nanos) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; aws_task_scheduler_schedule_future(&testing_loop->scheduler, task, run_at_nanos); } static void s_testing_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; aws_task_scheduler_cancel_task(&testing_loop->scheduler, task); } static bool s_testing_loop_is_on_callers_thread(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; return testing_loop->mock_on_callers_thread; } static void s_testing_loop_destroy(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; aws_task_scheduler_clean_up(&testing_loop->scheduler); aws_mem_release(event_loop->alloc, testing_loop); aws_event_loop_clean_up_base(event_loop); @@ -76,10 +76,12 @@ static struct aws_event_loop_vtable s_testing_loop_vtable = { }; static struct aws_event_loop *s_testing_loop_new(struct aws_allocator *allocator, aws_io_clock_fn clock) { - struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); + struct aws_event_loop *event_loop = + (struct aws_event_loop *)aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); aws_event_loop_init_base(event_loop, allocator, clock); - struct testing_loop *testing_loop = aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); + struct testing_loop *testing_loop = + (struct testing_loop *)aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); aws_task_scheduler_init(&testing_loop->scheduler, allocator); testing_loop->mock_on_callers_thread = true; event_loop->impl_data = testing_loop; @@ -113,7 +115,7 @@ static int s_testing_channel_handler_process_read_message( (void)slot; (void)message; - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; aws_linked_list_push_back(&testing_handler->messages, &message->queueing_handle); return AWS_OP_SUCCESS; } @@ -124,7 +126,7 @@ static int s_testing_channel_handler_process_write_message( struct aws_io_message *message) { (void)slot; - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; aws_linked_list_push_back(&testing_handler->messages, &message->queueing_handle); /* Invoke completion callback if this is the left-most handler */ @@ -142,7 +144,7 @@ static int s_testing_channel_handler_increment_read_window( size_t size) { (void)slot; - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; testing_handler->latest_window_update = size; return AWS_OP_SUCCESS; } @@ -154,7 +156,7 @@ static int s_testing_channel_handler_shutdown( int error_code, bool free_scarce_resources_immediately) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; /* If user has registered a callback, invoke it */ if (testing_handler->on_shutdown) { @@ -183,7 +185,7 @@ static int s_testing_channel_handler_shutdown( } static size_t s_testing_channel_handler_initial_window_size(struct aws_channel_handler *handler) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; return testing_handler->initial_window; } @@ -193,7 +195,7 @@ static size_t s_testing_channel_handler_message_overhead(struct aws_channel_hand } static void s_testing_channel_handler_destroy(struct aws_channel_handler *handler) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; while (!aws_linked_list_empty(&testing_handler->messages)) { struct aws_linked_list_node *node = aws_linked_list_pop_front(&testing_handler->messages); @@ -206,7 +208,7 @@ static void s_testing_channel_handler_destroy(struct aws_channel_handler *handle } static void s_testing_channel_handler_reset_statistics(struct aws_channel_handler *handler) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; aws_crt_statistics_socket_reset(&testing_handler->stats); } @@ -214,7 +216,7 @@ static void s_testing_channel_handler_reset_statistics(struct aws_channel_handle static void s_testing_channel_handler_gather_statistics( struct aws_channel_handler *handler, struct aws_array_list *stats) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; void *stats_base = &testing_handler->stats; aws_array_list_push_back(stats, &stats_base); @@ -235,9 +237,10 @@ static struct aws_channel_handler_vtable s_testing_channel_handler_vtable = { static struct aws_channel_handler *s_new_testing_channel_handler( struct aws_allocator *allocator, size_t initial_window) { - struct aws_channel_handler *handler = aws_mem_calloc(allocator, 1, sizeof(struct aws_channel_handler)); + struct aws_channel_handler *handler = + (struct aws_channel_handler *)aws_mem_calloc(allocator, 1, sizeof(struct aws_channel_handler)); struct testing_channel_handler *testing_handler = - aws_mem_calloc(allocator, 1, sizeof(struct testing_channel_handler)); + (struct testing_channel_handler *)aws_mem_calloc(allocator, 1, sizeof(struct testing_channel_handler)); aws_linked_list_init(&testing_handler->messages); testing_handler->initial_window = initial_window; testing_handler->latest_window_update = 0; @@ -270,14 +273,14 @@ struct testing_channel { static void s_testing_channel_on_setup_completed(struct aws_channel *channel, int error_code, void *user_data) { (void)channel; (void)error_code; - struct testing_channel *testing = user_data; + struct testing_channel *testing = (struct testing_channel *)user_data; testing->channel_setup_completed = true; } static void s_testing_channel_on_shutdown_completed(struct aws_channel *channel, int error_code, void *user_data) { (void)channel; (void)error_code; - struct testing_channel *testing = user_data; + struct testing_channel *testing = (struct testing_channel *)user_data; testing->channel_shutdown_completed = true; testing->channel_shutdown_error_code = error_code; @@ -393,7 +396,7 @@ static inline int testing_channel_init( AWS_ZERO_STRUCT(*testing); testing->loop = s_testing_loop_new(allocator, options->clock_fn); - testing->loop_impl = testing->loop->impl_data; + testing->loop_impl = (struct testing_loop *)testing->loop->impl_data; struct aws_channel_options args = { .on_setup_completed = s_testing_channel_on_setup_completed, @@ -411,8 +414,9 @@ static inline int testing_channel_init( ASSERT_TRUE(testing->channel_setup_completed); testing->left_handler_slot = aws_channel_slot_new(testing->channel); - struct aws_channel_handler *handler = s_new_testing_channel_handler(allocator, 16 * 1024); - testing->left_handler_impl = handler->impl; + struct aws_channel_handler *handler = + (struct aws_channel_handler *)s_new_testing_channel_handler(allocator, 16 * 1024); + testing->left_handler_impl = (struct testing_channel_handler *)handler->impl; ASSERT_SUCCESS(aws_channel_slot_set_handler(testing->left_handler_slot, handler)); return AWS_OP_SUCCESS; @@ -445,7 +449,7 @@ static inline int testing_channel_install_downstream_handler(struct testing_chan struct aws_channel_handler *handler = s_new_testing_channel_handler(testing->left_handler_slot->alloc, initial_window); ASSERT_NOT_NULL(handler); - testing->right_handler_impl = handler->impl; + testing->right_handler_impl = (struct testing_channel_handler *)handler->impl; ASSERT_SUCCESS(aws_channel_slot_set_handler(testing->right_handler_slot, handler)); return AWS_OP_SUCCESS; From 6b92e59986118aec09d3fa404fbb6086cab95092 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 11 Nov 2024 09:37:17 -0800 Subject: [PATCH 51/72] hide dispatch queue header --- {include/aws/io/private => source/darwin}/dispatch_queue.h | 0 source/darwin/dispatch_queue_event_loop.c | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename {include/aws/io/private => source/darwin}/dispatch_queue.h (100%) diff --git a/include/aws/io/private/dispatch_queue.h b/source/darwin/dispatch_queue.h similarity index 100% rename from include/aws/io/private/dispatch_queue.h rename to source/darwin/dispatch_queue.h diff --git a/source/darwin/dispatch_queue_event_loop.c b/source/darwin/dispatch_queue_event_loop.c index 8bb7b50c9..d83816e75 100644 --- a/source/darwin/dispatch_queue_event_loop.c +++ b/source/darwin/dispatch_queue_event_loop.c @@ -16,7 +16,7 @@ #include #include -#include +#include "dispatch_queue.h" #include #include From 145e7d72cbe29f104cbf5901b2a9601c71209bcc Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 11 Nov 2024 09:48:17 -0800 Subject: [PATCH 52/72] hide dispatch_queue.h --- source/darwin/nw_socket.c | 3 ++- source/darwin/secure_transport_tls_channel_handler.c | 3 ++- source/windows/iocp/socket.c | 1 - tests/socket_test.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/source/darwin/nw_socket.c b/source/darwin/nw_socket.c index d959cf6f9..c967b346f 100644 --- a/source/darwin/nw_socket.c +++ b/source/darwin/nw_socket.c @@ -12,12 +12,13 @@ #include #include -#include #include #include #include +#include "dispatch_queue.h" + static int s_determine_socket_error(int error) { switch (error) { case ECONNREFUSED: diff --git a/source/darwin/secure_transport_tls_channel_handler.c b/source/darwin/secure_transport_tls_channel_handler.c index fbf46a3ba..cb1277f72 100644 --- a/source/darwin/secure_transport_tls_channel_handler.c +++ b/source/darwin/secure_transport_tls_channel_handler.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -25,6 +24,8 @@ #include #include +#include "dispatch_queue.h" + #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-variable" #pragma clang diagnostic ignored "-Wdeprecated-declarations" diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index ccd47549f..345371fb9 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -456,7 +456,6 @@ int aws_socket_init_winsock( return err; } -#endif // AWS_USE_IO_COMPLETION_PORTS static void s_socket_clean_up(struct aws_socket *socket) { if (!socket->impl) { diff --git a/tests/socket_test.c b/tests/socket_test.c index f99a765b2..ceff35c79 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -687,7 +687,7 @@ static int s_test_socket_with_bind_to_invalid_interface(struct aws_allocator *al options.domain = AWS_SOCKET_IPV4; strncpy(options.network_interface_name, "invalid", AWS_NETWORK_INTERFACE_NAME_MAX); struct aws_socket outgoing; -#if (defined(AWS_OS_APPLE) && defined(AWS_USE_KQUEUE)) || defined(AWS_OS_LINUX) +#if (defined(AWS_OS_APPLE) && !defined(AWS_USE_APPLE_NETWORK_FRAMEWORK)) || defined(AWS_OS_LINUX) ASSERT_ERROR(AWS_IO_SOCKET_INVALID_OPTIONS, aws_socket_init(&outgoing, allocator, &options)); #else ASSERT_ERROR(AWS_ERROR_PLATFORM_NOT_SUPPORTED, aws_socket_init(&outgoing, allocator, &options)); From 3a4eacaa4f26cc01613d353b013767082b5d77bc Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 11 Nov 2024 10:41:20 -0800 Subject: [PATCH 53/72] fix merge error --- source/windows/iocp/socket.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index 345371fb9..c398c9d5d 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -525,7 +525,6 @@ static int s_socket_bind(struct aws_socket *socket, const struct aws_socket_endp struct iocp_socket *socket_impl = socket->impl; return socket_impl->winsock_vtable->bind(socket, local_endpoint); } -#endif // AWS_USE_IO_COMPLETION_PORTS /* Update IPV4 or IPV6 socket->local_endpoint based on the results of getsockname() */ static int s_update_local_endpoint_ipv4_ipv6(struct aws_socket *socket) { From 39991969a2a5b9f7657e37aa8e7477f993b73541 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 11 Nov 2024 13:14:41 -0800 Subject: [PATCH 54/72] make apple network framework public --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95ad373aa..5589f394d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,7 +221,7 @@ if (USE_VSOCK) endif() if (AWS_USE_APPLE_NETWORK_FRAMEWORK) - target_compile_definitions(${PROJECT_NAME} PRIVATE "-DAWS_USE_APPLE_NETWORK_FRAMEWORK") + target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_USE_APPLE_NETWORK_FRAMEWORK") endif() target_include_directories(${PROJECT_NAME} PUBLIC From 8d84d1162e77293c60957588865d62f14a515c23 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 11 Nov 2024 13:38:28 -0800 Subject: [PATCH 55/72] Apply suggestions from code review Co-authored-by: Michael Graeb --- include/aws/io/socket.h | 2 +- source/event_loop.c | 13 ++++--------- source/socket.c | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index ab295b576..7351525a5 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -99,7 +99,7 @@ typedef void(aws_socket_on_connection_result_fn)(struct aws_socket *socket, int * A user may want to call aws_socket_set_options() on the new socket if different options are desired. * * new_socket is not yet assigned to an event-loop. The user should call aws_socket_assign_to_event_loop() before - * performing IO operations. The user is responsible to releasing the socket memory after use. + * performing IO operations. The user must call `aws_socket_release()` when they're done with the socket, to free it. * * When error_code is AWS_ERROR_SUCCESS, new_socket is the recently accepted connection. * If error_code is non-zero, an error occurred and you should aws_socket_close() the socket. diff --git a/source/event_loop.c b/source/event_loop.c index 867eb7591..3b05fc3ba 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -57,23 +57,17 @@ struct aws_event_loop *aws_event_loop_new_with_options( switch (type) { case AWS_ELT_EPOLL: return aws_event_loop_new_epoll_with_options(alloc, options); - break; case AWS_ELT_IOCP: return aws_event_loop_new_iocp_with_options(alloc, options); - break; case AWS_ELT_KQUEUE: return aws_event_loop_new_kqueue_with_options(alloc, options); - break; case AWS_ELT_DISPATCH_QUEUE: return aws_event_loop_new_dispatch_queue_with_options(alloc, options); - break; default: AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type on the platform."); aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); - break; + return NULL; } - - return NULL; } static void s_event_loop_group_thread_exit(void *user_data) { @@ -547,10 +541,11 @@ int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_ * AWS_ELT_PLATFORM_DEFAULT. */ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_override) { - if (aws_event_loop_type_validate_platform(default_type_override)) { + if (aws_event_loop_type_validate_platform(default_type_override) == AWS_OP_SUCCESS) { + s_default_event_loop_type_override = default_type_override; + } else { s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; } - s_default_event_loop_type_override = default_type_override; } /** diff --git a/source/socket.c b/source/socket.c index c4a8e9759..f7eb77520 100644 --- a/source/socket.c +++ b/source/socket.c @@ -116,7 +116,7 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons if (aws_socket_impl_type_validate_platform(type)) { AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Invalid event loop type on the platform."); - return AWS_ERROR_PLATFORM_NOT_SUPPORTED; + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); } // 2. setup vtable based on socket type From 71fae6fcc8c11bb3e82ef08f1e884c309243bcb6 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 11 Nov 2024 14:33:45 -0800 Subject: [PATCH 56/72] update cr changes --- CMakeLists.txt | 1 - include/aws/io/event_loop.h | 9 +++++++++ include/aws/io/private/event_loop_impl.h | 4 ---- include/aws/io/socket.h | 9 +++++---- source/event_loop.c | 12 ++++++++---- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5589f394d..1a128c7e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,6 @@ elseif (APPLE) message(FATAL_ERROR "Network framework not found") endif () - #No choice on TLS for apple, darwinssl will always be used. list(APPEND PLATFORM_LIBS "-framework Security -framework Network") list(APPEND EVENT_LOOP_DEFINES "DISPATCH_QUEUE") diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 09da591c0..f44c431a2 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -12,6 +12,7 @@ AWS_PUSH_SANE_WARNING_LEVEL struct aws_event_loop; struct aws_event_loop_group; +struct aws_event_loop_options; struct aws_shutdown_callback_options; struct aws_task; @@ -246,6 +247,14 @@ struct aws_event_loop *aws_event_loop_new_base( AWS_IO_API void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); +/** + * Creates an instance of the event loop implementation from the options. + */ +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); + /** * Invokes the destroy() fn for the event loop implementation. * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 365d51f80..2e1992eed 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -98,19 +98,15 @@ struct aws_event_loop_options { enum aws_event_loop_type type; }; -AWS_IO_API struct aws_event_loop *aws_event_loop_new_iocp_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -AWS_IO_API struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -AWS_IO_API struct aws_event_loop *aws_event_loop_new_kqueue_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -AWS_IO_API struct aws_event_loop *aws_event_loop_new_epoll_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index ab295b576..8ce623d84 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -116,7 +116,8 @@ typedef void(aws_socket_on_accept_result_fn)( * Callback for when the data passed to a call to aws_socket_write() has either completed or failed. * On success, error_code will be AWS_ERROR_SUCCESS. * - * socket is possible to be a NULL pointer in the callback. + * `socket` may be NULL in the callback if the socket is released and cleaned up before a callback is triggered. + * by the system I/O handler, */ typedef void( aws_socket_on_write_completed_fn)(struct aws_socket *socket, int error_code, size_t bytes_written, void *user_data); @@ -206,19 +207,19 @@ aws_ms_fn_ptr aws_winsock_get_acceptex_fn(void); #endif -AWS_IO_API int aws_socket_init_posix( +int aws_socket_init_posix( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options); -AWS_IO_API int aws_socket_init_winsock( +int aws_socket_init_winsock( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options); -AWS_IO_API int aws_socket_init_apple_nw_socket( +int aws_socket_init_apple_nw_socket( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options); diff --git a/source/event_loop.c b/source/event_loop.c index 867eb7591..e1d728f2d 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -14,7 +14,11 @@ #include #include -static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; +#ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK + static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_DISPATCH_QUEUE; +#else + static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; +#endif struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock) { struct aws_event_loop_options options = { @@ -559,9 +563,6 @@ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_ * If `aws_event_loop_override_default_type` has been called, return the override default type. */ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { -#ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK - aws_event_loop_override_default_type(AWS_ELT_DISPATCH_QUEUE); -#endif // AWS_USE_APPLE_NETWORK_FRAMEWORK if (s_default_event_loop_type_override != AWS_ELT_PLATFORM_DEFAULT) { return s_default_event_loop_type_override; } @@ -625,6 +626,7 @@ struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( AWS_ASSERT(0); AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Dispatch Queue is not supported on the platform"); + aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); return NULL; } @@ -637,6 +639,7 @@ struct aws_event_loop *aws_event_loop_new_iocp_with_options( AWS_ASSERT(0); AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "IOCP is not supported on the platform"); + aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); return NULL; } #endif // AWS_ENABLE_IO_COMPLETION_PORTS @@ -650,6 +653,7 @@ struct aws_event_loop *aws_event_loop_new_kqueue_with_options( AWS_ASSERT(0); AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Kqueue is not supported on the platform"); + aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); return NULL; } #endif // AWS_ENABLE_EPOLL From b6bff6f557ecf8b92131471d5668e7b90a196fab Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 12 Nov 2024 09:45:08 -0800 Subject: [PATCH 57/72] Event loop public api (#691) Co-authored-by: Bret Ambrose --- include/aws/io/event_loop.h | 411 ++++---------------- include/aws/io/private/event_loop_impl.h | 299 ++++++++++++++ include/aws/testing/io_testing_channel.h | 29 +- source/bsd/kqueue_event_loop.c | 4 +- source/channel.c | 1 + source/event_loop.c | 164 ++++---- source/exponential_backoff_retry_strategy.c | 5 +- source/linux/epoll_event_loop.c | 7 +- source/posix/pipe.c | 1 + source/posix/socket.c | 1 + source/s2n/s2n_tls_channel_handler.c | 11 +- source/windows/iocp/iocp_event_loop.c | 1 + source/windows/iocp/pipe.c | 1 + source/windows/iocp/socket.c | 1 + tests/alpn_handler_test.c | 1 + tests/byo_crypto_test.c | 6 +- tests/channel_test.c | 6 +- tests/default_host_resolver_test.c | 60 ++- tests/event_loop_test.c | 31 +- tests/exponential_backoff_retry_test.c | 25 +- tests/future_test.c | 1 + tests/pipe_test.c | 1 + tests/pkcs11_test.c | 6 +- tests/socket_handler_test.c | 15 +- tests/socket_test.c | 16 +- tests/standard_retry_test.c | 8 +- tests/tls_handler_test.c | 19 +- 27 files changed, 655 insertions(+), 476 deletions(-) create mode 100644 include/aws/io/private/event_loop_impl.h diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 58041a4c7..098e9428e 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -6,80 +6,27 @@ * SPDX-License-Identifier: Apache-2.0. */ -#include -#include -#include - #include AWS_PUSH_SANE_WARNING_LEVEL -enum aws_io_event_type { - AWS_IO_EVENT_TYPE_READABLE = 1, - AWS_IO_EVENT_TYPE_WRITABLE = 2, - AWS_IO_EVENT_TYPE_REMOTE_HANG_UP = 4, - AWS_IO_EVENT_TYPE_CLOSED = 8, - AWS_IO_EVENT_TYPE_ERROR = 16, -}; - struct aws_event_loop; +struct aws_event_loop_group; +struct aws_shutdown_callback_options; struct aws_task; -struct aws_thread_options; - -#if AWS_USE_IO_COMPLETION_PORTS - -struct aws_overlapped; - -typedef void(aws_event_loop_on_completion_fn)( - struct aws_event_loop *event_loop, - struct aws_overlapped *overlapped, - int status_code, - size_t num_bytes_transferred); - -/** - * The aws_win32_OVERLAPPED struct is layout-compatible with OVERLAPPED as defined in . It is used - * here to avoid pulling in a dependency on which would also bring along a lot of bad macros, such - * as redefinitions of GetMessage and GetObject. Note that the OVERLAPPED struct layout in the Windows SDK can - * never be altered without breaking binary compatibility for every existing third-party executable, so there - * is no need to worry about keeping this definition in sync. - */ -struct aws_win32_OVERLAPPED { - uintptr_t Internal; - uintptr_t InternalHigh; - union { - struct { - uint32_t Offset; - uint32_t OffsetHigh; - } s; - void *Pointer; - } u; - void *hEvent; -}; /** - * Use aws_overlapped when a handle connected to the event loop needs an OVERLAPPED struct. - * OVERLAPPED structs are needed to make OS-level async I/O calls. - * When the I/O completes, the assigned aws_event_loop_on_completion_fn is called from the event_loop's thread. - * While the I/O is pending, it is not safe to modify or delete aws_overlapped. - * Call aws_overlapped_init() before first use. If the aws_overlapped will be used multiple times, call - * aws_overlapped_reset() or aws_overlapped_init() between uses. + * @internal */ -struct aws_overlapped { - struct aws_win32_OVERLAPPED overlapped; - aws_event_loop_on_completion_fn *on_completion; - void *user_data; -}; - -#else /* !AWS_USE_IO_COMPLETION_PORTS */ - typedef void(aws_event_loop_on_event_fn)( struct aws_event_loop *event_loop, struct aws_io_handle *handle, int events, void *user_data); -#endif /* AWS_USE_IO_COMPLETION_PORTS */ - +/** + * @internal + */ struct aws_event_loop_vtable { void (*destroy)(struct aws_event_loop *event_loop); int (*run)(struct aws_event_loop *event_loop); @@ -88,203 +35,49 @@ struct aws_event_loop_vtable { void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); -#if AWS_USE_IO_COMPLETION_PORTS int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); -#else int (*subscribe_to_io_events)( struct aws_event_loop *event_loop, struct aws_io_handle *handle, int events, aws_event_loop_on_event_fn *on_event, void *user_data); -#endif int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); void (*free_io_event_resources)(void *user_data); bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); }; -struct aws_event_loop { - struct aws_event_loop_vtable *vtable; - struct aws_allocator *alloc; - aws_io_clock_fn *clock; - struct aws_hash_table local_data; - struct aws_atomic_var current_load_factor; - uint64_t latest_tick_start; - size_t current_tick_latency_sum; - struct aws_atomic_var next_flush_time; - void *impl_data; -}; - -struct aws_event_loop_local_object; -typedef void(aws_event_loop_on_local_object_removed_fn)(struct aws_event_loop_local_object *); - -struct aws_event_loop_local_object { - const void *key; - void *object; - aws_event_loop_on_local_object_removed_fn *on_object_removed; -}; - -struct aws_event_loop_options { - aws_io_clock_fn *clock; - struct aws_thread_options *thread_options; -}; - -typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, - const struct aws_event_loop_options *options, - void *new_loop_user_data); - -struct aws_event_loop_group { - struct aws_allocator *allocator; - struct aws_array_list event_loops; - struct aws_ref_count ref_count; - struct aws_shutdown_callback_options shutdown_options; -}; - -AWS_EXTERN_C_BEGIN - -#ifdef AWS_USE_IO_COMPLETION_PORTS -/** - * Prepares aws_overlapped for use, and sets a function to call when the overlapped operation completes. - */ -AWS_IO_API -void aws_overlapped_init( - struct aws_overlapped *overlapped, - aws_event_loop_on_completion_fn *on_completion, - void *user_data); - /** - * Prepares aws_overlapped for re-use without changing the assigned aws_event_loop_on_completion_fn. - * Call aws_overlapped_init(), instead of aws_overlapped_reset(), to change the aws_event_loop_on_completion_fn. + * Event loop group configuration options */ -AWS_IO_API -void aws_overlapped_reset(struct aws_overlapped *overlapped); +struct aws_event_loop_group_options { -/** - * Casts an aws_overlapped pointer for use as a LPOVERLAPPED parameter to Windows API functions - */ -AWS_IO_API -struct _OVERLAPPED *aws_overlapped_to_windows_overlapped(struct aws_overlapped *overlapped); -#endif /* AWS_USE_IO_COMPLETION_PORTS */ + /** + * How many event loops that event loop group should contain. For most group types, this implies + * the creation and management of an analagous amount of managed threads + */ + uint16_t loop_count; -/** - * Creates an instance of the default event loop implementation for the current architecture and operating system. - */ -AWS_IO_API -struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock); + /** + * Optional callback to invoke when the event loop group finishes destruction. + */ + const struct aws_shutdown_callback_options *shutdown_options; -/** - * Creates an instance of the default event loop implementation for the current architecture and operating system using - * extendable options. - */ -AWS_IO_API -struct aws_event_loop *aws_event_loop_new_default_with_options( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options); - -/** - * Invokes the destroy() fn for the event loop implementation. - * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. - * If you do not want this function to block, call aws_event_loop_stop() manually first. - * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads - * must ensure their API calls to the event loop happen-before the call to destroy. - */ -AWS_IO_API -void aws_event_loop_destroy(struct aws_event_loop *event_loop); - -/** - * Initializes common event-loop data structures. - * This is only called from the *new() function of event loop implementations. - */ -AWS_IO_API -int aws_event_loop_init_base(struct aws_event_loop *event_loop, struct aws_allocator *alloc, aws_io_clock_fn *clock); - -/** - * Common cleanup code for all implementations. - * This is only called from the *destroy() function of event loop implementations. - */ -AWS_IO_API -void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); - -/** - * Fetches an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to - * by key. This function is not thread safe and should be called inside the event-loop's thread. - */ -AWS_IO_API -int aws_event_loop_fetch_local_object( - struct aws_event_loop *event_loop, - void *key, - struct aws_event_loop_local_object *obj); - -/** - * Puts an item object the event-loop's data store. Key will be taken as the memory address of the memory pointed to by - * key. The lifetime of item must live until remove or a put item overrides it. This function is not thread safe and - * should be called inside the event-loop's thread. - */ -AWS_IO_API -int aws_event_loop_put_local_object(struct aws_event_loop *event_loop, struct aws_event_loop_local_object *obj); - -/** - * Removes an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to - * by key. If removed_item is not null, the removed item will be moved to it if it exists. Otherwise, the default - * deallocation strategy will be used. This function is not thread safe and should be called inside the event-loop's - * thread. - */ -AWS_IO_API -int aws_event_loop_remove_local_object( - struct aws_event_loop *event_loop, - void *key, - struct aws_event_loop_local_object *removed_obj); - -/** - * Triggers the running of the event loop. This function must not block. The event loop is not active until this - * function is invoked. This function can be called again on an event loop after calling aws_event_loop_stop() and - * aws_event_loop_wait_for_stop_completion(). - */ -AWS_IO_API -int aws_event_loop_run(struct aws_event_loop *event_loop); - -/** - * Triggers the event loop to stop, but does not wait for the loop to stop completely. - * This function may be called from outside or inside the event loop thread. It is safe to call multiple times. - * This function is called from destroy(). - * - * If you do not call destroy(), an event loop can be run again by calling stop(), wait_for_stop_completion(), run(). - */ -AWS_IO_API -int aws_event_loop_stop(struct aws_event_loop *event_loop); + /** + * Optional configuration to control how the event loop group's threads bind to CPU groups + */ + const uint16_t *cpu_group; -/** - * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the - * event-loop load balancer to take into account load when vending another event-loop to a caller. - * - * Call this function at the beginning of your event-loop tick: after wake-up, but before processing any IO or tasks. - */ -AWS_IO_API -void aws_event_loop_register_tick_start(struct aws_event_loop *event_loop); - -/** - * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the - * event-loop load balancer to take into account load when vending another event-loop to a caller. - * - * Call this function at the end of your event-loop tick: after processing IO and tasks. - */ -AWS_IO_API -void aws_event_loop_register_tick_end(struct aws_event_loop *event_loop); - -/** - * Returns the current load factor (however that may be calculated). If the event-loop is not invoking - * aws_event_loop_register_tick_start() and aws_event_loop_register_tick_end(), this value will always be 0. - */ -AWS_IO_API -size_t aws_event_loop_get_load_factor(struct aws_event_loop *event_loop); + /** + * Override for the clock function that event loops should use. Defaults to the system's high resolution + * timer. + * + * Do not bind this value to managed code; it is only used in timing-sensitive tests. + */ + aws_io_clock_fn *clock_override; +}; -/** - * Blocks until the event loop stops completely. - * If you want to call aws_event_loop_run() again, you must call this after aws_event_loop_stop(). - * It is not safe to call this function from inside the event loop thread. - */ -AWS_IO_API -int aws_event_loop_wait_for_stop_completion(struct aws_event_loop *event_loop); +AWS_EXTERN_C_BEGIN /** * The event loop will schedule the task and run it on the event loop thread as soon as possible. @@ -319,105 +112,63 @@ void aws_event_loop_schedule_task_future( AWS_IO_API void aws_event_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task); -#if AWS_USE_IO_COMPLETION_PORTS - /** - * Associates an aws_io_handle with the event loop's I/O Completion Port. - * - * The handle must use aws_overlapped for all async operations requiring an OVERLAPPED struct. - * When the operation completes, the aws_overlapped's completion function will run on the event loop thread. - * Note that completion functions will not be invoked while the event loop is stopped. Users should wait for all async - * operations on connected handles to complete before cleaning up or destroying the event loop. - * - * A handle may only be connected to one event loop in its lifetime. + * Returns true if the event loop's thread is the same thread that called this function, otherwise false. */ AWS_IO_API -int aws_event_loop_connect_handle_to_io_completion_port( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle); - -#else /* !AWS_USE_IO_COMPLETION_PORTS */ +bool aws_event_loop_thread_is_callers_thread(struct aws_event_loop *event_loop); /** - * Subscribes on_event to events on the event-loop for handle. events is a bitwise concatenation of the events that were - * received. The definition for these values can be found in aws_io_event_type. Currently, only - * AWS_IO_EVENT_TYPE_READABLE and AWS_IO_EVENT_TYPE_WRITABLE are honored. You always are registered for error conditions - * and closure. This function may be called from outside or inside the event loop thread. However, the unsubscribe - * function must be called inside the event-loop's thread. + * Gets the current timestamp for the event loop's clock, in nanoseconds. This function is thread-safe. */ AWS_IO_API -int aws_event_loop_subscribe_to_io_events( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - aws_event_loop_on_event_fn *on_event, - void *user_data); - -#endif /* AWS_USE_IO_COMPLETION_PORTS */ +int aws_event_loop_current_clock_time(const struct aws_event_loop *event_loop, uint64_t *time_nanos); /** - * Unsubscribes handle from event-loop notifications. - * This function is not thread safe and should be called inside the event-loop's thread. - * - * NOTE: if you are using io completion ports, this is a risky call. We use it in places, but only when we're certain - * there's no pending events. If you want to use it, it's your job to make sure you don't have pending events before - * calling it. + * Creation function for event loop groups. */ AWS_IO_API -int aws_event_loop_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struct aws_io_handle *handle); +struct aws_event_loop_group *aws_event_loop_group_new( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options); /** - * Cleans up resources (user_data) associated with the I/O eventing subsystem for a given handle. This should only - * ever be necessary in the case where you are cleaning up an event loop during shutdown and its thread has already - * been joined. + * Increments the reference count on the event loop group, allowing the caller to take a reference to it. + * + * Returns the same event loop group passed in. */ AWS_IO_API -void aws_event_loop_free_io_event_resources(struct aws_event_loop *event_loop, struct aws_io_handle *handle); +struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group); /** - * Returns true if the event loop's thread is the same thread that called this function, otherwise false. + * Decrements an event loop group's ref count. When the ref count drops to zero, the event loop group will be + * destroyed. */ AWS_IO_API -bool aws_event_loop_thread_is_callers_thread(struct aws_event_loop *event_loop); +void aws_event_loop_group_release(struct aws_event_loop_group *el_group); /** - * Gets the current timestamp for the event loop's clock, in nanoseconds. This function is thread-safe. + * Returns the event loop at a particular index. If the index is out of bounds, null is returned. */ AWS_IO_API -int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_t *time_nanos); +struct aws_event_loop *aws_event_loop_group_get_loop_at(struct aws_event_loop_group *el_group, size_t index); /** - * Creates an event loop group, with clock, number of loops to manage, and the function to call for creating a new - * event loop. + * Gets the number of event loops managed by an event loop group. */ AWS_IO_API -struct aws_event_loop_group *aws_event_loop_group_new( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options); +size_t aws_event_loop_group_get_loop_count(const struct aws_event_loop_group *el_group); -/** Creates an event loop group, with clock, number of loops to manage, the function to call for creating a new - * event loop, and also pins all loops to hw threads on the same cpu_group (e.g. NUMA nodes). Note: - * If el_count exceeds the number of hw threads in the cpu_group it will be ignored on the assumption that if you - * care about NUMA, you don't want hyper-threads doing your IO and you especially don't want IO on a different node. +/** + * Fetches the next loop for use. The purpose is to enable load balancing across loops. You should not depend on how + * this load balancing is done as it is subject to change in the future. Currently it uses the "best-of-two" algorithm + * based on the load factor of each loop. */ AWS_IO_API -struct aws_event_loop_group *aws_event_loop_group_new_pinned_to_cpu_group( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - uint16_t cpu_group, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options); +struct aws_event_loop *aws_event_loop_group_get_next_loop(struct aws_event_loop_group *el_group); /** - * Initializes an event loop group with platform defaults. If max_threads == 0, then the - * loop count will be the number of available processors on the machine / 2 (to exclude hyper-threads). - * Otherwise, max_threads will be the number of event loops in the group. + * @deprecated - use aws_event_loop_group_new() instead */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new_default( @@ -425,14 +176,8 @@ struct aws_event_loop_group *aws_event_loop_group_new_default( uint16_t max_threads, const struct aws_shutdown_callback_options *shutdown_options); -/** Creates an event loop group, with clock, number of loops to manage, the function to call for creating a new - * event loop, and also pins all loops to hw threads on the same cpu_group (e.g. NUMA nodes). Note: - * If el_count exceeds the number of hw threads in the cpu_group it will be clamped to the number of hw threads - * on the assumption that if you care about NUMA, you don't want hyper-threads doing your IO and you especially - * don't want IO on a different node. - * - * If max_threads == 0, then the - * loop count will be the number of available processors in the cpu_group / 2 (to exclude hyper-threads) +/** + * @deprecated - use aws_event_loop_group_new() instead */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( @@ -442,35 +187,49 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou const struct aws_shutdown_callback_options *shutdown_options); /** - * Increments the reference count on the event loop group, allowing the caller to take a reference to it. + * @internal - Don't use outside of testing. * - * Returns the same event loop group passed in. + * Returns the opaque internal user data of an event loop. Can be cast into a specific implementation by + * privileged consumers. */ AWS_IO_API -struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group); +void *aws_event_loop_get_impl(struct aws_event_loop *event_loop); /** - * Decrements an event loop group's ref count. When the ref count drops to zero, the event loop group will be - * destroyed. + * @internal - Don't use outside of testing. + * + * Initializes the base structure used by all event loop implementations with test-oriented overrides. */ AWS_IO_API -void aws_event_loop_group_release(struct aws_event_loop_group *el_group); - -AWS_IO_API -struct aws_event_loop *aws_event_loop_group_get_loop_at(struct aws_event_loop_group *el_group, size_t index); +struct aws_event_loop *aws_event_loop_new_base( + struct aws_allocator *allocator, + aws_io_clock_fn *clock, + struct aws_event_loop_vtable *vtable, + void *impl); +/** + * @internal - Don't use outside of testing. + * + * Common cleanup code for all implementations. + * This is only called from the *destroy() function of event loop implementations. + */ AWS_IO_API -size_t aws_event_loop_group_get_loop_count(struct aws_event_loop_group *el_group); +void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); /** - * Fetches the next loop for use. The purpose is to enable load balancing across loops. You should not depend on how - * this load balancing is done as it is subject to change in the future. Currently it uses the "best-of-two" algorithm - * based on the load factor of each loop. + * @internal - Don't use outside of testing. + * + * Invokes the destroy() fn for the event loop implementation. + * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. + * If you do not want this function to block, call aws_event_loop_stop() manually first. + * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads + * must ensure their API calls to the event loop happen-before the call to destroy. */ AWS_IO_API -struct aws_event_loop *aws_event_loop_group_get_next_loop(struct aws_event_loop_group *el_group); +void aws_event_loop_destroy(struct aws_event_loop *event_loop); AWS_EXTERN_C_END + AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_IO_EVENT_LOOP_H */ diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h new file mode 100644 index 000000000..4eb2f6230 --- /dev/null +++ b/include/aws/io/private/event_loop_impl.h @@ -0,0 +1,299 @@ +#ifndef AWS_IO_EVENT_LOOP_IMPL_H +#define AWS_IO_EVENT_LOOP_IMPL_H + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include + +#include +#include +#include +#include + +AWS_PUSH_SANE_WARNING_LEVEL + +struct aws_event_loop; +struct aws_overlapped; + +typedef void(aws_event_loop_on_completion_fn)( + struct aws_event_loop *event_loop, + struct aws_overlapped *overlapped, + int status_code, + size_t num_bytes_transferred); + +/** + * The aws_win32_OVERLAPPED struct is layout-compatible with OVERLAPPED as defined in . It is used + * here to avoid pulling in a dependency on which would also bring along a lot of bad macros, such + * as redefinitions of GetMessage and GetObject. Note that the OVERLAPPED struct layout in the Windows SDK can + * never be altered without breaking binary compatibility for every existing third-party executable, so there + * is no need to worry about keeping this definition in sync. + */ +struct aws_win32_OVERLAPPED { + uintptr_t Internal; + uintptr_t InternalHigh; + union { + struct { + uint32_t Offset; + uint32_t OffsetHigh; + } s; + void *Pointer; + } u; + void *hEvent; +}; + +/** + * Use aws_overlapped when a handle connected to the event loop needs an OVERLAPPED struct. + * OVERLAPPED structs are needed to make OS-level async I/O calls. + * When the I/O completes, the assigned aws_event_loop_on_completion_fn is called from the event_loop's thread. + * While the I/O is pending, it is not safe to modify or delete aws_overlapped. + * Call aws_overlapped_init() before first use. If the aws_overlapped will be used multiple times, call + * aws_overlapped_reset() or aws_overlapped_init() between uses. + */ +struct aws_overlapped { + struct aws_win32_OVERLAPPED overlapped; + aws_event_loop_on_completion_fn *on_completion; + void *user_data; +}; + +enum aws_io_event_type { + AWS_IO_EVENT_TYPE_READABLE = 1, + AWS_IO_EVENT_TYPE_WRITABLE = 2, + AWS_IO_EVENT_TYPE_REMOTE_HANG_UP = 4, + AWS_IO_EVENT_TYPE_CLOSED = 8, + AWS_IO_EVENT_TYPE_ERROR = 16, +}; + +struct aws_event_loop { + struct aws_event_loop_vtable *vtable; + struct aws_allocator *alloc; + aws_io_clock_fn *clock; + struct aws_hash_table local_data; + struct aws_atomic_var current_load_factor; + uint64_t latest_tick_start; + size_t current_tick_latency_sum; + struct aws_atomic_var next_flush_time; + void *impl_data; +}; + +struct aws_event_loop_local_object; +typedef void(aws_event_loop_on_local_object_removed_fn)(struct aws_event_loop_local_object *); + +struct aws_event_loop_local_object { + const void *key; + void *object; + aws_event_loop_on_local_object_removed_fn *on_object_removed; +}; + +struct aws_event_loop_options { + aws_io_clock_fn *clock; + struct aws_thread_options *thread_options; +}; + +typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, + const struct aws_event_loop_options *options, + void *new_loop_user_data); + +struct aws_event_loop_group { + struct aws_allocator *allocator; + struct aws_array_list event_loops; + struct aws_ref_count ref_count; + struct aws_shutdown_callback_options shutdown_options; +}; + +AWS_EXTERN_C_BEGIN + +#ifdef AWS_USE_IO_COMPLETION_PORTS + +/** + * Prepares aws_overlapped for use, and sets a function to call when the overlapped operation completes. + */ +AWS_IO_API +void aws_overlapped_init( + struct aws_overlapped *overlapped, + aws_event_loop_on_completion_fn *on_completion, + void *user_data); + +/** + * Prepares aws_overlapped for re-use without changing the assigned aws_event_loop_on_completion_fn. + * Call aws_overlapped_init(), instead of aws_overlapped_reset(), to change the aws_event_loop_on_completion_fn. + */ +AWS_IO_API +void aws_overlapped_reset(struct aws_overlapped *overlapped); + +/** + * Casts an aws_overlapped pointer for use as a LPOVERLAPPED parameter to Windows API functions + */ +AWS_IO_API +struct _OVERLAPPED *aws_overlapped_to_windows_overlapped(struct aws_overlapped *overlapped); + +/** + * Associates an aws_io_handle with the event loop's I/O Completion Port. + * + * The handle must use aws_overlapped for all async operations requiring an OVERLAPPED struct. + * When the operation completes, the aws_overlapped's completion function will run on the event loop thread. + * Note that completion functions will not be invoked while the event loop is stopped. Users should wait for all async + * operations on connected handles to complete before cleaning up or destroying the event loop. + * + * A handle may only be connected to one event loop in its lifetime. + */ +AWS_IO_API +int aws_event_loop_connect_handle_to_io_completion_port( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle); + +#else + +/** + * Subscribes on_event to events on the event-loop for handle. events is a bitwise concatenation of the events that were + * received. The definition for these values can be found in aws_io_event_type. Currently, only + * AWS_IO_EVENT_TYPE_READABLE and AWS_IO_EVENT_TYPE_WRITABLE are honored. You always are registered for error conditions + * and closure. This function may be called from outside or inside the event loop thread. However, the unsubscribe + * function must be called inside the event-loop's thread. + */ +AWS_IO_API +int aws_event_loop_subscribe_to_io_events( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + aws_event_loop_on_event_fn *on_event, + void *user_data); + +#endif /* AWS_USE_IO_COMPLETION_PORTS */ + +/** + * Creates an instance of the default event loop implementation for the current architecture and operating system. + */ +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock); + +/** + * Creates an instance of the default event loop implementation for the current architecture and operating system using + * extendable options. + */ +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_default_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); + +/** + * Initializes common event-loop data structures. + * This is only called from the *new() function of event loop implementations. + */ +AWS_IO_API +int aws_event_loop_init_base(struct aws_event_loop *event_loop, struct aws_allocator *alloc, aws_io_clock_fn *clock); + +/** + * Fetches an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to + * by key. This function is not thread safe and should be called inside the event-loop's thread. + */ +AWS_IO_API +int aws_event_loop_fetch_local_object( + struct aws_event_loop *event_loop, + void *key, + struct aws_event_loop_local_object *obj); + +/** + * Puts an item object the event-loop's data store. Key will be taken as the memory address of the memory pointed to by + * key. The lifetime of item must live until remove or a put item overrides it. This function is not thread safe and + * should be called inside the event-loop's thread. + */ +AWS_IO_API +int aws_event_loop_put_local_object(struct aws_event_loop *event_loop, struct aws_event_loop_local_object *obj); + +/** + * Removes an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to + * by key. If removed_item is not null, the removed item will be moved to it if it exists. Otherwise, the default + * deallocation strategy will be used. This function is not thread safe and should be called inside the event-loop's + * thread. + */ +AWS_IO_API +int aws_event_loop_remove_local_object( + struct aws_event_loop *event_loop, + void *key, + struct aws_event_loop_local_object *removed_obj); + +/** + * Triggers the running of the event loop. This function must not block. The event loop is not active until this + * function is invoked. This function can be called again on an event loop after calling aws_event_loop_stop() and + * aws_event_loop_wait_for_stop_completion(). + */ +AWS_IO_API +int aws_event_loop_run(struct aws_event_loop *event_loop); + +/** + * Triggers the event loop to stop, but does not wait for the loop to stop completely. + * This function may be called from outside or inside the event loop thread. It is safe to call multiple times. + * This function is called from destroy(). + * + * If you do not call destroy(), an event loop can be run again by calling stop(), wait_for_stop_completion(), run(). + */ +AWS_IO_API +int aws_event_loop_stop(struct aws_event_loop *event_loop); + +/** + * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the + * event-loop load balancer to take into account load when vending another event-loop to a caller. + * + * Call this function at the beginning of your event-loop tick: after wake-up, but before processing any IO or tasks. + */ +AWS_IO_API +void aws_event_loop_register_tick_start(struct aws_event_loop *event_loop); + +/** + * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the + * event-loop load balancer to take into account load when vending another event-loop to a caller. + * + * Call this function at the end of your event-loop tick: after processing IO and tasks. + */ +AWS_IO_API +void aws_event_loop_register_tick_end(struct aws_event_loop *event_loop); + +/** + * Returns the current load factor (however that may be calculated). If the event-loop is not invoking + * aws_event_loop_register_tick_start() and aws_event_loop_register_tick_end(), this value will always be 0. + */ +AWS_IO_API +size_t aws_event_loop_get_load_factor(struct aws_event_loop *event_loop); + +/** + * Blocks until the event loop stops completely. + * If you want to call aws_event_loop_run() again, you must call this after aws_event_loop_stop(). + * It is not safe to call this function from inside the event loop thread. + */ +AWS_IO_API +int aws_event_loop_wait_for_stop_completion(struct aws_event_loop *event_loop); + +/** + * Unsubscribes handle from event-loop notifications. + * This function is not thread safe and should be called inside the event-loop's thread. + * + * NOTE: if you are using io completion ports, this is a risky call. We use it in places, but only when we're certain + * there's no pending events. If you want to use it, it's your job to make sure you don't have pending events before + * calling it. + */ +AWS_IO_API +int aws_event_loop_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + +/** + * Cleans up resources (user_data) associated with the I/O eventing subsystem for a given handle. This should only + * ever be necessary in the case where you are cleaning up an event loop during shutdown and its thread has already + * been joined. + */ +AWS_IO_API +void aws_event_loop_free_io_event_resources(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + +AWS_IO_API +struct aws_event_loop_group *aws_event_loop_group_new_internal( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options, + aws_new_event_loop_fn *new_loop_fn, + void *new_loop_user_data); + +AWS_EXTERN_C_END + +AWS_POP_SANE_WARNING_LEVEL + +#endif /* AWS_IO_EVENT_LOOP_IMPL_H */ diff --git a/include/aws/testing/io_testing_channel.h b/include/aws/testing/io_testing_channel.h index 192a269b0..c202168cb 100644 --- a/include/aws/testing/io_testing_channel.h +++ b/include/aws/testing/io_testing_channel.h @@ -9,10 +9,12 @@ #include #include #include +// #include #include #include struct testing_loop { + struct aws_allocator *allocator; struct aws_task_scheduler scheduler; bool mock_on_callers_thread; }; @@ -33,7 +35,7 @@ static int s_testing_loop_wait_for_stop_completion(struct aws_event_loop *event_ } static void s_testing_loop_schedule_task_now(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); aws_task_scheduler_schedule_now(&testing_loop->scheduler, task); } @@ -42,26 +44,27 @@ static void s_testing_loop_schedule_task_future( struct aws_task *task, uint64_t run_at_nanos) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); aws_task_scheduler_schedule_future(&testing_loop->scheduler, task, run_at_nanos); } static void s_testing_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); aws_task_scheduler_cancel_task(&testing_loop->scheduler, task); } static bool s_testing_loop_is_on_callers_thread(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); return testing_loop->mock_on_callers_thread; } static void s_testing_loop_destroy(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); + struct aws_allocator *allocator = testing_loop->allocator; aws_task_scheduler_clean_up(&testing_loop->scheduler); - aws_mem_release(event_loop->alloc, testing_loop); + aws_mem_release(allocator, testing_loop); aws_event_loop_clean_up_base(event_loop); - aws_mem_release(event_loop->alloc, event_loop); + aws_mem_release(allocator, event_loop); } static struct aws_event_loop_vtable s_testing_loop_vtable = { @@ -76,18 +79,14 @@ static struct aws_event_loop_vtable s_testing_loop_vtable = { }; static struct aws_event_loop *s_testing_loop_new(struct aws_allocator *allocator, aws_io_clock_fn clock) { - struct aws_event_loop *event_loop = - (struct aws_event_loop *)aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); - aws_event_loop_init_base(event_loop, allocator, clock); - struct testing_loop *testing_loop = (struct testing_loop *)aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); + aws_task_scheduler_init(&testing_loop->scheduler, allocator); testing_loop->mock_on_callers_thread = true; - event_loop->impl_data = testing_loop; - event_loop->vtable = &s_testing_loop_vtable; + testing_loop->allocator = allocator; - return event_loop; + return aws_event_loop_new_base(allocator, clock, &s_testing_loop_vtable, testing_loop); } typedef void(testing_channel_handler_on_shutdown_fn)( @@ -396,7 +395,7 @@ static inline int testing_channel_init( AWS_ZERO_STRUCT(*testing); testing->loop = s_testing_loop_new(allocator, options->clock_fn); - testing->loop_impl = (struct testing_loop *)testing->loop->impl_data; + testing->loop_impl = (struct testing_loop *)aws_event_loop_get_impl(testing->loop); struct aws_channel_options args = { .on_setup_completed = s_testing_channel_on_setup_completed, diff --git a/source/bsd/kqueue_event_loop.c b/source/bsd/kqueue_event_loop.c index 33a517e7b..e0f8ed63b 100644 --- a/source/bsd/kqueue_event_loop.c +++ b/source/bsd/kqueue_event_loop.c @@ -5,14 +5,14 @@ #include -#include - #include #include #include #include #include #include +#include +#include #if defined(__FreeBSD__) || defined(__NetBSD__) # define __BSD_VISIBLE 1 diff --git a/source/channel.c b/source/channel.c index 55903fc1d..3e3d33932 100644 --- a/source/channel.c +++ b/source/channel.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #ifdef _MSC_VER diff --git a/source/event_loop.c b/source/event_loop.c index 1e7aef676..2e0861964 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -5,6 +5,9 @@ #include +#include +#include + #include #include #include @@ -72,30 +75,32 @@ static void s_aws_event_loop_group_shutdown_async(struct aws_event_loop_group *e aws_thread_launch(&cleanup_thread, s_event_loop_destroy_async_thread_fn, el_group, &thread_options); } -static struct aws_event_loop_group *s_event_loop_group_new( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - uint16_t cpu_group, - bool pin_threads, +struct aws_event_loop_group *aws_event_loop_group_new_internal( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options, aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options) { - AWS_ASSERT(new_loop_fn); + void *new_loop_user_data) { + AWS_FATAL_ASSERT(new_loop_fn); + + aws_io_clock_fn *clock = options->clock_override; + if (!clock) { + clock = aws_high_res_clock_get_ticks; + } size_t group_cpu_count = 0; struct aws_cpu_info *usable_cpus = NULL; + bool pin_threads = options->cpu_group != NULL; if (pin_threads) { + uint16_t cpu_group = *options->cpu_group; group_cpu_count = aws_get_cpu_count_for_group(cpu_group); - if (!group_cpu_count) { + // LOG THIS aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); return NULL; } - usable_cpus = aws_mem_calloc(alloc, group_cpu_count, sizeof(struct aws_cpu_info)); - + usable_cpus = aws_mem_calloc(allocator, group_cpu_count, sizeof(struct aws_cpu_info)); if (usable_cpus == NULL) { return NULL; } @@ -103,16 +108,23 @@ static struct aws_event_loop_group *s_event_loop_group_new( aws_get_cpu_ids_for_group(cpu_group, usable_cpus, group_cpu_count); } - struct aws_event_loop_group *el_group = aws_mem_calloc(alloc, 1, sizeof(struct aws_event_loop_group)); + struct aws_event_loop_group *el_group = aws_mem_calloc(allocator, 1, sizeof(struct aws_event_loop_group)); if (el_group == NULL) { return NULL; } - el_group->allocator = alloc; + el_group->allocator = allocator; aws_ref_count_init( &el_group->ref_count, el_group, (aws_simple_completion_callback *)s_aws_event_loop_group_shutdown_async); - if (aws_array_list_init_dynamic(&el_group->event_loops, alloc, el_count, sizeof(struct aws_event_loop *))) { + uint16_t el_count = options->loop_count; + if (el_count == 0) { + uint16_t processor_count = (uint16_t)aws_system_info_processor_count(); + /* cut them in half to avoid using hyper threads for the IO work. */ + el_count = processor_count > 1 ? processor_count / 2 : processor_count; + } + + if (aws_array_list_init_dynamic(&el_group->event_loops, allocator, el_count, sizeof(struct aws_event_loop *))) { goto on_error; } @@ -121,7 +133,7 @@ static struct aws_event_loop_group *s_event_loop_group_new( if (!pin_threads || (i < group_cpu_count && !usable_cpus[i].suspected_hyper_thread)) { struct aws_thread_options thread_options = *aws_default_thread_options(); - struct aws_event_loop_options options = { + struct aws_event_loop_options el_options = { .clock = clock, .thread_options = &thread_options, }; @@ -138,8 +150,7 @@ static struct aws_event_loop_group *s_event_loop_group_new( } thread_options.name = aws_byte_cursor_from_c_str(thread_name); - struct aws_event_loop *loop = new_loop_fn(alloc, &options, new_loop_user_data); - + struct aws_event_loop *loop = new_loop_fn(allocator, &el_options, new_loop_user_data); if (!loop) { goto on_error; } @@ -155,12 +166,12 @@ static struct aws_event_loop_group *s_event_loop_group_new( } } - if (shutdown_options != NULL) { - el_group->shutdown_options = *shutdown_options; + if (options->shutdown_options != NULL) { + el_group->shutdown_options = *options->shutdown_options; } if (pin_threads) { - aws_mem_release(alloc, usable_cpus); + aws_mem_release(allocator, usable_cpus); } return el_group; @@ -169,7 +180,7 @@ on_error:; /* cache the error code to prevent any potential side effects */ int cached_error_code = aws_last_error(); - aws_mem_release(alloc, usable_cpus); + aws_mem_release(allocator, usable_cpus); s_aws_event_loop_group_shutdown_sync(el_group); s_event_loop_group_thread_exit(el_group); @@ -178,20 +189,6 @@ on_error:; return NULL; } -struct aws_event_loop_group *aws_event_loop_group_new( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options) { - - AWS_ASSERT(new_loop_fn); - AWS_ASSERT(el_count); - - return s_event_loop_group_new(alloc, clock, el_count, 0, false, new_loop_fn, new_loop_user_data, shutdown_options); -} - static struct aws_event_loop *s_default_new_event_loop( struct aws_allocator *allocator, const struct aws_event_loop_options *options, @@ -201,49 +198,11 @@ static struct aws_event_loop *s_default_new_event_loop( return aws_event_loop_new_default_with_options(allocator, options); } -struct aws_event_loop_group *aws_event_loop_group_new_default( - struct aws_allocator *alloc, - uint16_t max_threads, - const struct aws_shutdown_callback_options *shutdown_options) { - if (!max_threads) { - uint16_t processor_count = (uint16_t)aws_system_info_processor_count(); - /* cut them in half to avoid using hyper threads for the IO work. */ - max_threads = processor_count > 1 ? processor_count / 2 : processor_count; - } - - return aws_event_loop_group_new( - alloc, aws_high_res_clock_get_ticks, max_threads, s_default_new_event_loop, NULL, shutdown_options); -} - -struct aws_event_loop_group *aws_event_loop_group_new_pinned_to_cpu_group( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - uint16_t cpu_group, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options) { - AWS_ASSERT(new_loop_fn); - AWS_ASSERT(el_count); - - return s_event_loop_group_new( - alloc, clock, el_count, cpu_group, true, new_loop_fn, new_loop_user_data, shutdown_options); -} - -struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( - struct aws_allocator *alloc, - uint16_t max_threads, - uint16_t cpu_group, - const struct aws_shutdown_callback_options *shutdown_options) { - - if (!max_threads) { - uint16_t processor_count = (uint16_t)aws_system_info_processor_count(); - /* cut them in half to avoid using hyper threads for the IO work. */ - max_threads = processor_count > 1 ? processor_count / 2 : processor_count; - } +struct aws_event_loop_group *aws_event_loop_group_new( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options) { - return aws_event_loop_group_new_pinned_to_cpu_group( - alloc, aws_high_res_clock_get_ticks, max_threads, cpu_group, s_default_new_event_loop, NULL, shutdown_options); + return aws_event_loop_group_new_internal(allocator, options, s_default_new_event_loop, NULL); } struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group) { @@ -260,7 +219,7 @@ void aws_event_loop_group_release(struct aws_event_loop_group *el_group) { } } -size_t aws_event_loop_group_get_loop_count(struct aws_event_loop_group *el_group) { +size_t aws_event_loop_group_get_loop_count(const struct aws_event_loop_group *el_group) { return aws_array_list_length(&el_group->event_loops); } @@ -524,7 +483,52 @@ bool aws_event_loop_thread_is_callers_thread(struct aws_event_loop *event_loop) return event_loop->vtable->is_on_callers_thread(event_loop); } -int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_t *time_nanos) { +int aws_event_loop_current_clock_time(const struct aws_event_loop *event_loop, uint64_t *time_nanos) { AWS_ASSERT(event_loop->clock); return event_loop->clock(time_nanos); } + +struct aws_event_loop_group *aws_event_loop_group_new_default( + struct aws_allocator *alloc, + uint16_t max_threads, + const struct aws_shutdown_callback_options *shutdown_options) { + + struct aws_event_loop_group_options elg_options = { + .loop_count = max_threads, + .shutdown_options = shutdown_options, + }; + + return aws_event_loop_group_new(alloc, &elg_options); +} + +struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( + struct aws_allocator *alloc, + uint16_t max_threads, + uint16_t cpu_group, + const struct aws_shutdown_callback_options *shutdown_options) { + + struct aws_event_loop_group_options elg_options = { + .loop_count = max_threads, + .shutdown_options = shutdown_options, + .cpu_group = &cpu_group, + }; + + return aws_event_loop_group_new(alloc, &elg_options); +} + +void *aws_event_loop_get_impl(struct aws_event_loop *event_loop) { + return event_loop->impl_data; +} + +struct aws_event_loop *aws_event_loop_new_base( + struct aws_allocator *allocator, + aws_io_clock_fn *clock, + struct aws_event_loop_vtable *vtable, + void *impl) { + struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); + aws_event_loop_init_base(event_loop, allocator, clock); + event_loop->impl_data = impl; + event_loop->vtable = vtable; + + return event_loop; +} diff --git a/source/exponential_backoff_retry_strategy.c b/source/exponential_backoff_retry_strategy.c index cf2472269..2110cbd46 100644 --- a/source/exponential_backoff_retry_strategy.c +++ b/source/exponential_backoff_retry_strategy.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,7 @@ static void s_exponential_retry_destroy(struct aws_retry_strategy *retry_strateg if (completion_callback != NULL) { completion_callback(completion_user_data); } - aws_ref_count_release(&el_group->ref_count); + aws_event_loop_group_release(el_group); } } @@ -361,7 +362,7 @@ struct aws_retry_strategy *aws_retry_strategy_new_exponential_backoff( aws_atomic_init_int(&exponential_backoff_strategy->base.ref_count, 1); exponential_backoff_strategy->config = *config; exponential_backoff_strategy->config.el_group = - aws_ref_count_acquire(&exponential_backoff_strategy->config.el_group->ref_count); + aws_event_loop_group_acquire(exponential_backoff_strategy->config.el_group); if (!exponential_backoff_strategy->config.generate_random && !exponential_backoff_strategy->config.generate_random_impl) { diff --git a/source/linux/epoll_event_loop.c b/source/linux/epoll_event_loop.c index 094a7836a..a99d5a8cf 100644 --- a/source/linux/epoll_event_loop.c +++ b/source/linux/epoll_event_loop.c @@ -3,17 +3,16 @@ * SPDX-License-Identifier: Apache-2.0. */ -#include - #include #include #include #include #include #include -#include - +#include #include +#include +#include #include diff --git a/source/posix/pipe.c b/source/posix/pipe.c index f727b021c..449ab1318 100644 --- a/source/posix/pipe.c +++ b/source/posix/pipe.c @@ -6,6 +6,7 @@ #include #include +#include #ifdef __GLIBC__ # define __USE_GNU diff --git a/source/posix/socket.c b/source/posix/socket.c index cdd69d2d0..49e18f47e 100644 --- a/source/posix/socket.c +++ b/source/posix/socket.c @@ -13,6 +13,7 @@ #include #include +#include #include #include diff --git a/source/s2n/s2n_tls_channel_handler.c b/source/s2n/s2n_tls_channel_handler.c index e9560608e..8326543e8 100644 --- a/source/s2n/s2n_tls_channel_handler.c +++ b/source/s2n/s2n_tls_channel_handler.c @@ -5,21 +5,20 @@ #include #include +#include #include - +#include +#include +#include #include #include #include #include +#include #include #include #include -#include -#include -#include -#include - #include #ifdef AWS_S2N_INSOURCE_PATH # include diff --git a/source/windows/iocp/iocp_event_loop.c b/source/windows/iocp/iocp_event_loop.c index 313344ab9..1d0801e4b 100644 --- a/source/windows/iocp/iocp_event_loop.c +++ b/source/windows/iocp/iocp_event_loop.c @@ -11,6 +11,7 @@ #include #include +#include #include diff --git a/source/windows/iocp/pipe.c b/source/windows/iocp/pipe.c index 04145c679..a9e2185e5 100644 --- a/source/windows/iocp/pipe.c +++ b/source/windows/iocp/pipe.c @@ -7,6 +7,7 @@ #include #include +#include #include #include diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index 755950f0c..7286bd6ba 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -26,6 +26,7 @@ below, clang-format doesn't work (at least on my version) with the c-style comme #include #include #include +#include #include #include diff --git a/tests/alpn_handler_test.c b/tests/alpn_handler_test.c index 5d83bad4e..fa6d88e27 100644 --- a/tests/alpn_handler_test.c +++ b/tests/alpn_handler_test.c @@ -5,6 +5,7 @@ #include #include +#include #include #include diff --git a/tests/byo_crypto_test.c b/tests/byo_crypto_test.c index 878889646..1414f8652 100644 --- a/tests/byo_crypto_test.c +++ b/tests/byo_crypto_test.c @@ -54,7 +54,11 @@ static struct byo_crypto_common_tester c_tester; static int s_byo_crypto_common_tester_init(struct aws_allocator *allocator, struct byo_crypto_common_tester *tester) { AWS_ZERO_STRUCT(*tester); aws_io_library_init(allocator); - tester->el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; tester->mutex = mutex; diff --git a/tests/channel_test.c b/tests/channel_test.c index 9a730a351..8fc530f99 100644 --- a/tests/channel_test.c +++ b/tests/channel_test.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -684,7 +685,10 @@ static int s_test_channel_connect_some_hosts_timeout(struct aws_allocator *alloc .shutdown = false, }; - struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); /* resolve our s3 test bucket and an EC2 host with an ACL that blackholes the connection */ const struct aws_string *addr1_ipv4 = NULL; diff --git a/tests/default_host_resolver_test.c b/tests/default_host_resolver_test.c index 2d0178a73..f47b346bf 100644 --- a/tests/default_host_resolver_test.c +++ b/tests/default_host_resolver_test.c @@ -96,7 +96,10 @@ static int s_test_default_with_ipv6_lookup_fn(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -189,7 +192,10 @@ static int s_test_default_host_resolver_ipv6_address_variations_fn(struct aws_al }; - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -263,7 +269,10 @@ static int s_test_default_with_ipv4_only_lookup_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -333,7 +342,10 @@ static int s_test_default_with_multiple_lookups_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -460,7 +472,10 @@ static int s_test_resolver_ttls_fn(struct aws_allocator *allocator, void *ctx) { s_set_time(0); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, .max_entries = 10, .system_clock_override_fn = s_clock_fn}; @@ -672,7 +687,10 @@ static int s_test_resolver_connect_failure_recording_fn(struct aws_allocator *al aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -864,7 +882,10 @@ static int s_test_resolver_ttl_refreshes_on_resolve_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1044,7 +1065,10 @@ static int s_test_resolver_ipv4_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1105,7 +1129,10 @@ static int s_test_resolver_purge_host_cache(struct aws_allocator *allocator, voi (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1220,7 +1247,10 @@ static int s_test_resolver_purge_cache(struct aws_allocator *allocator, void *ct (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1369,7 +1399,10 @@ static int s_test_resolver_ipv6_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1431,7 +1464,10 @@ static int s_test_resolver_low_frequency_starvation_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index e86448c8b..92b739156 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -8,9 +8,9 @@ #include #include #include -#include - #include +#include +#include #include struct task_args { @@ -1041,7 +1041,10 @@ static int test_event_loop_group_setup_and_shutdown(struct aws_allocator *alloca (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new_default(allocator, 0, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); size_t cpu_count = aws_system_info_processor_count(); size_t el_count = aws_event_loop_group_get_loop_count(event_loop_group); @@ -1074,10 +1077,16 @@ static int test_numa_aware_event_loop_group_setup_and_shutdown(struct aws_alloca size_t cpus_for_group = aws_get_cpu_count_for_group(0); size_t el_count = 1; - /* pass UINT16_MAX here to check the boundary conditions on numa cpu detection. It should never create more threads - * than hw cpus available */ - struct aws_event_loop_group *event_loop_group = - aws_event_loop_group_new_default_pinned_to_cpu_group(allocator, UINT16_MAX, 0, NULL); + uint16_t cpu_group = 0; + struct aws_event_loop_group_options elg_options = { + /* + * pass UINT16_MAX here to check the boundary conditions on numa cpu detection. It should never create more + * threads than hw cpus available + */ + .loop_count = UINT16_MAX, + .cpu_group = &cpu_group, + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); el_count = aws_event_loop_group_get_loop_count(event_loop_group); @@ -1154,8 +1163,12 @@ static int test_event_loop_group_setup_and_shutdown_async(struct aws_allocator * async_shutdown_options.shutdown_callback_user_data = &task_args; async_shutdown_options.shutdown_callback_fn = s_async_shutdown_complete_callback; - struct aws_event_loop_group *event_loop_group = - aws_event_loop_group_new_default(allocator, 0, &async_shutdown_options); + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + .shutdown_options = &async_shutdown_options, + }; + + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(event_loop_group); diff --git a/tests/exponential_backoff_retry_test.c b/tests/exponential_backoff_retry_test.c index a3bf7bde0..779a4f50f 100644 --- a/tests/exponential_backoff_retry_test.c +++ b/tests/exponential_backoff_retry_test.c @@ -66,7 +66,10 @@ static int s_test_exponential_backoff_retry_too_many_retries_for_jitter_mode( aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, .jitter_mode = jitter_mode, @@ -157,7 +160,10 @@ static int s_test_exponential_backoff_retry_client_errors_do_not_count_fn(struct aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .el_group = el_group, .max_retries = 3, @@ -201,7 +207,10 @@ static int s_test_exponential_backoff_retry_no_jitter_time_taken_fn(struct aws_a aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, .jitter_mode = AWS_EXPONENTIAL_BACKOFF_JITTER_NONE, @@ -253,7 +262,10 @@ static int s_test_exponential_max_backoff_retry_no_jitter_fn(struct aws_allocato aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, .jitter_mode = AWS_EXPONENTIAL_BACKOFF_JITTER_NONE, @@ -310,7 +322,10 @@ static int s_test_exponential_backoff_retry_invalid_options_fn(struct aws_alloca aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 64, .el_group = el_group, diff --git a/tests/future_test.c b/tests/future_test.c index 1ac94b551..795d30bb5 100644 --- a/tests/future_test.c +++ b/tests/future_test.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "future_test.h" diff --git a/tests/pipe_test.c b/tests/pipe_test.c index 053c5aefd..f15f4da33 100644 --- a/tests/pipe_test.c +++ b/tests/pipe_test.c @@ -8,6 +8,7 @@ #include #include #include +#include #include enum pipe_loop_setup { diff --git a/tests/pkcs11_test.c b/tests/pkcs11_test.c index 792ed5fa4..4af9d0fb0 100644 --- a/tests/pkcs11_test.c +++ b/tests/pkcs11_test.c @@ -1653,8 +1653,10 @@ static int s_test_pkcs11_tls_negotiation_succeeds_common( ASSERT_SUCCESS(aws_mutex_init(&s_tls_tester.synced.mutex)); ASSERT_SUCCESS(aws_condition_variable_init(&s_tls_tester.synced.cvar)); - struct aws_event_loop_group *event_loop_group = - aws_event_loop_group_new_default(allocator, 1, NULL /*shutdown_opts*/); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); ASSERT_NOT_NULL(event_loop_group); struct aws_host_resolver_default_options resolver_opts = { diff --git a/tests/socket_handler_test.c b/tests/socket_handler_test.c index 85c7c7c39..ee7290d4e 100644 --- a/tests/socket_handler_test.c +++ b/tests/socket_handler_test.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include #include @@ -59,7 +60,10 @@ static int s_socket_common_tester_init(struct aws_allocator *allocator, struct s AWS_ZERO_STRUCT(*tester); aws_io_library_init(allocator); - tester->el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, @@ -1006,8 +1010,13 @@ static int s_socket_common_tester_statistics_init( aws_io_library_init(allocator); AWS_ZERO_STRUCT(*tester); - tester->el_group = - aws_event_loop_group_new(allocator, s_statistic_test_clock_fn, 1, s_default_new_event_loop, NULL, NULL); + + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + .clock_override = s_statistic_test_clock_fn, + }; + tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_default_new_event_loop, NULL); + struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; tester->mutex = mutex; diff --git a/tests/socket_test.c b/tests/socket_test.c index 097d6ef66..e01834a75 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -12,6 +12,7 @@ #include #include +#include #include #ifdef _MSC_VER @@ -624,7 +625,10 @@ static int s_test_connect_timeout(struct aws_allocator *allocator, void *ctx) { aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -704,7 +708,10 @@ static int s_test_connect_timeout_cancelation(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -1147,7 +1154,10 @@ static int s_cleanup_before_connect_or_timeout_doesnt_explode(struct aws_allocat aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); diff --git a/tests/standard_retry_test.c b/tests/standard_retry_test.c index bb62de691..11991a3e0 100644 --- a/tests/standard_retry_test.c +++ b/tests/standard_retry_test.c @@ -8,6 +8,7 @@ #include #include +#include #include @@ -49,7 +50,12 @@ static int s_fixture_setup(struct aws_allocator *allocator, void *ctx) { .shutdown_callback_user_data = ctx, }; - test_data->el_group = aws_event_loop_group_new_default(allocator, 1, &shutdown_options); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + .shutdown_options = &shutdown_options, + }; + test_data->el_group = aws_event_loop_group_new(allocator, &elg_options); + ASSERT_NOT_NULL(test_data->el_group); struct aws_standard_retry_options retry_options = { .initial_bucket_capacity = 15, diff --git a/tests/tls_handler_test.c b/tests/tls_handler_test.c index a55d26077..7b1a68c32 100644 --- a/tests/tls_handler_test.c +++ b/tests/tls_handler_test.c @@ -10,6 +10,7 @@ # include # include # include +# include # include # include @@ -177,7 +178,10 @@ static int s_tls_common_tester_init(struct aws_allocator *allocator, struct tls_ aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - tester->el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, @@ -532,7 +536,11 @@ static int s_tls_channel_server_client_tester_init(struct aws_allocator *allocat AWS_ZERO_STRUCT(s_server_client_tester); ASSERT_SUCCESS(aws_mutex_init(&s_server_client_tester.server_mutex)); ASSERT_SUCCESS(aws_condition_variable_init(&s_server_client_tester.server_condition_variable)); - s_server_client_tester.client_el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + s_server_client_tester.client_el_group = aws_event_loop_group_new(allocator, &elg_options); ASSERT_SUCCESS(s_tls_rw_args_init( &s_server_client_tester.server_rw_args, @@ -1904,8 +1912,11 @@ static int s_tls_common_tester_statistics_init(struct aws_allocator *allocator, aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - tester->el_group = - aws_event_loop_group_new(allocator, s_statistic_test_clock_fn, 1, s_default_new_event_loop, NULL, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + .clock_override = s_statistic_test_clock_fn, + }; + tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_default_new_event_loop, NULL); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, From 405c988df9d0523939c2f8169740c1d384a9e7f7 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 09:50:54 -0800 Subject: [PATCH 58/72] rename enum --- include/aws/io/event_loop.h | 24 ++++++------- include/aws/io/private/event_loop_impl.h | 2 +- include/aws/io/socket.h | 20 +++++------ source/event_loop.c | 42 +++++++++++----------- source/socket.c | 44 +++++++++++------------- 5 files changed, 64 insertions(+), 68 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index f44c431a2..3900e8db9 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -43,21 +43,21 @@ struct aws_event_loop_vtable { }; /** - * Event Loop Type. If set to `AWS_ELT_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default. + * Event Loop Type. If set to `AWS_EVENT_LOOP_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default. * * Default Event Loop Type - * Linux | AWS_ELT_EPOLL - * Windows | AWS_ELT_IOCP - * BSD Variants| AWS_ELT_KQUEUE - * MacOS | AWS_ELT_KQUEUE - * iOS | AWS_ELT_DISPATCH_QUEUE + * Linux | AWS_EVENT_LOOP_EPOLL + * Windows | AWS_EVENT_LOOP_IOCP + * BSD Variants| AWS_EVENT_LOOP_KQUEUE + * MacOS | AWS_EVENT_LOOP_KQUEUE + * iOS | AWS_EVENT_LOOP_DISPATCH_QUEUE */ enum aws_event_loop_type { - AWS_ELT_PLATFORM_DEFAULT = 0, - AWS_ELT_EPOLL, - AWS_ELT_IOCP, - AWS_ELT_KQUEUE, - AWS_ELT_DISPATCH_QUEUE, + AWS_EVENT_LOOP_PLATFORM_DEFAULT = 0, + AWS_EVENT_LOOP_EPOLL, + AWS_EVENT_LOOP_IOCP, + AWS_EVENT_LOOP_KQUEUE, + AWS_EVENT_LOOP_DISPATCH_QUEUE, }; /** @@ -72,7 +72,7 @@ struct aws_event_loop_group_options { uint16_t loop_count; /** - * Event loop type. If the event loop type is set to AWS_ELT_PLATFORM_DEFAULT, the + * Event loop type. If the event loop type is set to AWS_EVENT_LOOP_PLATFORM_DEFAULT, the * creation function will automatically use the platform’s default event loop type. */ enum aws_event_loop_type type; diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 2e1992eed..528c7514c 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -92,7 +92,7 @@ struct aws_event_loop_options { struct aws_thread_options *thread_options; /** - * Event loop type. If the event loop type is set to AWS_ELT_PLATFORM_DEFAULT, the + * Event loop type. If the event loop type is set to AWS_EVENT_LOOP_PLATFORM_DEFAULT, the * creation function will automatically use the platform’s default event loop type. */ enum aws_event_loop_type type; diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index e0aaf9f84..916f62171 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -32,21 +32,21 @@ enum aws_socket_type { }; /** - * Socket Implementation type. Decides which socket implementation is used. If set to `AWS_SIT_PLATFORM_DEFAULT`, it + * Socket Implementation type. Decides which socket implementation is used. If set to `AWS_SOCKET_IMPL_PLATFORM_DEFAULT`, it * will automatically use the platform’s default. * * PLATFORM DEFAULT SOCKET IMPLEMENTATION TYPE - * Linux | AWS_SIT_POSIX - * Windows | AWS_SIT_WINSOCK - * BSD Variants| AWS_SIT_POSIX - * MacOS | AWS_SIT_POSIX - * iOS | AWS_SIT_APPLE_NETWORK_FRAMEWORK + * Linux | AWS_SOCKET_IMPL_POSIX + * Windows | AWS_SOCKET_IMPL_WINSOCK + * BSD Variants| AWS_SOCKET_IMPL_POSIX + * MacOS | AWS_SOCKET_IMPL_POSIX + * iOS | AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK */ enum aws_socket_impl_type { - AWS_SIT_PLATFORM_DEFAULT = 0, - AWS_SIT_POSIX, - AWS_SIT_WINSOCK, - AWS_SIT_APPLE_NETWORK_FRAMEWORK, + AWS_SOCKET_IMPL_PLATFORM_DEFAULT = 0, + AWS_SOCKET_IMPL_POSIX, + AWS_SOCKET_IMPL_WINSOCK, + AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK, }; #define AWS_NETWORK_INTERFACE_NAME_MAX 16 diff --git a/source/event_loop.c b/source/event_loop.c index cd87c3ff0..e7b285339 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -15,16 +15,16 @@ #include #ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK - static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_DISPATCH_QUEUE; + static enum aws_event_loop_type s_default_event_loop_type_override = AWS_EVENT_LOOP_DISPATCH_QUEUE; #else - static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; + static enum aws_event_loop_type s_default_event_loop_type_override = AWS_EVENT_LOOP_PLATFORM_DEFAULT; #endif struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock) { struct aws_event_loop_options options = { .thread_options = NULL, .clock = clock, - .type = AWS_ELT_PLATFORM_DEFAULT, + .type = AWS_EVENT_LOOP_PLATFORM_DEFAULT, }; return aws_event_loop_new_with_options(alloc, &options); @@ -36,7 +36,7 @@ struct aws_event_loop *aws_event_loop_new_default_with_options( struct aws_event_loop_options local_options = { .thread_options = options->thread_options, .clock = options->clock, - .type = AWS_ELT_PLATFORM_DEFAULT, + .type = AWS_EVENT_LOOP_PLATFORM_DEFAULT, }; return aws_event_loop_new_with_options(alloc, &local_options); @@ -49,7 +49,7 @@ struct aws_event_loop *aws_event_loop_new_with_options( const struct aws_event_loop_options *options) { enum aws_event_loop_type type = options->type; - if (type == AWS_ELT_PLATFORM_DEFAULT) { + if (type == AWS_EVENT_LOOP_PLATFORM_DEFAULT) { type = aws_event_loop_get_default_type(); } @@ -59,13 +59,13 @@ struct aws_event_loop *aws_event_loop_new_with_options( } switch (type) { - case AWS_ELT_EPOLL: + case AWS_EVENT_LOOP_EPOLL: return aws_event_loop_new_epoll_with_options(alloc, options); - case AWS_ELT_IOCP: + case AWS_EVENT_LOOP_IOCP: return aws_event_loop_new_iocp_with_options(alloc, options); - case AWS_ELT_KQUEUE: + case AWS_EVENT_LOOP_KQUEUE: return aws_event_loop_new_kqueue_with_options(alloc, options); - case AWS_ELT_DISPATCH_QUEUE: + case AWS_EVENT_LOOP_DISPATCH_QUEUE: return aws_event_loop_new_dispatch_queue_with_options(alloc, options); default: AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type on the platform."); @@ -542,23 +542,23 @@ int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_ * Override default event loop type. Only used internally in tests. * * If the defined type is not supported on the current platform, the event loop type would reset to - * AWS_ELT_PLATFORM_DEFAULT. + * AWS_EVENT_LOOP_PLATFORM_DEFAULT. */ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_override) { if (aws_event_loop_type_validate_platform(default_type_override) == AWS_OP_SUCCESS) { s_default_event_loop_type_override = default_type_override; } else { - s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; + s_default_event_loop_type_override = AWS_EVENT_LOOP_PLATFORM_DEFAULT; } } /** - * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to + * Return the default event loop type. If the return value is `AWS_EVENT_LOOP_PLATFORM_DEFAULT`, the function failed to * retrieve the default type value. * If `aws_event_loop_override_default_type` has been called, return the override default type. */ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { - if (s_default_event_loop_type_override != AWS_ELT_PLATFORM_DEFAULT) { + if (s_default_event_loop_type_override != AWS_EVENT_LOOP_PLATFORM_DEFAULT) { return s_default_event_loop_type_override; } /** @@ -566,40 +566,40 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { * definition was declared in aws-c-common. We probably do not want to introduce extra dependency here. */ #ifdef AWS_ENABLE_KQUEUE - return AWS_ELT_KQUEUE; + return AWS_EVENT_LOOP_KQUEUE; #endif #ifdef AWS_ENABLE_DISPATCH_QUEUE - return AWS_ELT_DISPATCH_QUEUE; + return AWS_EVENT_LOOP_DISPATCH_QUEUE; #endif #ifdef AWS_ENABLE_EPOLL - return AWS_ELT_EPOLL; + return AWS_EVENT_LOOP_EPOLL; #endif #ifdef AWS_OS_WINDOWS - return AWS_ELT_IOCP; + return AWS_EVENT_LOOP_IOCP; #endif } static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) { switch (type) { - case AWS_ELT_EPOLL: + case AWS_EVENT_LOOP_EPOLL: #ifndef AWS_ENABLE_EPOLL AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type EPOLL is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_EPOLL break; - case AWS_ELT_IOCP: + case AWS_EVENT_LOOP_IOCP: #ifndef AWS_ENABLE_IO_COMPLETION_PORTS AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type IOCP is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_IO_COMPLETION_PORTS break; - case AWS_ELT_KQUEUE: + case AWS_EVENT_LOOP_KQUEUE: #ifndef AWS_ENABLE_KQUEUE AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type KQUEUE is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_KQUEUE break; - case AWS_ELT_DISPATCH_QUEUE: + case AWS_EVENT_LOOP_DISPATCH_QUEUE: #ifndef AWS_ENABLE_DISPATCH_QUEUE AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type Dispatch Queue is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); diff --git a/source/socket.c b/source/socket.c index f7eb77520..2fcdef0e8 100644 --- a/source/socket.c +++ b/source/socket.c @@ -110,7 +110,7 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons // 1. get socket type & validate type is avliable the platform enum aws_socket_impl_type type = options->impl_type; - if (type == AWS_SIT_PLATFORM_DEFAULT) { + if (type == AWS_SOCKET_IMPL_PLATFORM_DEFAULT) { type = aws_socket_get_default_impl_type(); } @@ -121,22 +121,18 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons // 2. setup vtable based on socket type switch (type) { - case AWS_SIT_POSIX: + case AWS_SOCKET_IMPL_POSIX: return aws_socket_init_posix(socket, alloc, options); - break; - case AWS_SIT_WINSOCK: + case AWS_SOCKET_IMPL_WINSOCK: return aws_socket_init_winsock(socket, alloc, options); - break; - - case AWS_SIT_APPLE_NETWORK_FRAMEWORK: + case AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK: + // Apple Network Framework is not implemented yet. We should not use it yet. AWS_ASSERT(false && "Invalid socket implementation on platform."); return aws_socket_init_apple_nw_socket(socket, alloc, options); - break; default: - break; + AWS_ASSERT(false && "Invalid socket implementation on platform."); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); } - AWS_ASSERT(false && "Invalid socket implementation on platform."); - return AWS_ERROR_PLATFORM_NOT_SUPPORTED; } int aws_socket_get_bound_address(const struct aws_socket *socket, struct aws_socket_endpoint *out_address) { @@ -172,16 +168,16 @@ void aws_socket_endpoint_init_local_address_for_test(struct aws_socket_endpoint } /** - * Return the default socket implementation type. If the return value is `AWS_SIT_PLATFORM_DEFAULT`, the function failed - * to retrieve the default type value. + * Return the default socket implementation type. If the return value is `AWS_SOCKET_IMPL_PLATFORM_DEFAULT`, the + * function failed to retrieve the default type value. */ static enum aws_socket_impl_type aws_socket_get_default_impl_type(void) { - enum aws_socket_impl_type type = AWS_SIT_PLATFORM_DEFAULT; + enum aws_socket_impl_type type = AWS_SOCKET_IMPL_PLATFORM_DEFAULT; // override default socket #ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK - type = AWS_SIT_APPLE_NETWORK_FRAMEWORK; + type = AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; #endif // AWS_USE_APPLE_NETWORK_FRAMEWORK - if (type != AWS_SIT_PLATFORM_DEFAULT) { + if (type != AWS_SOCKET_IMPL_PLATFORM_DEFAULT) { return type; } /** @@ -189,33 +185,33 @@ static enum aws_socket_impl_type aws_socket_get_default_impl_type(void) { * definition was declared in aws-c-common. We probably do not want to introduce extra dependency here. */ #if defined(AWS_ENABLE_KQUEUE) || defined(AWS_ENABLE_EPOLL) - return AWS_SIT_POSIX; + return AWS_SOCKET_IMPL_POSIX; #endif #ifdef AWS_ENABLE_DISPATCH_QUEUE - return AWS_SIT_APPLE_NETWORK_FRAMEWORK; + return AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; #endif #ifdef AWS_ENABLE_IO_COMPLETION_PORTS - return AWS_SIT_WINSOCK; + return AWS_SOCKET_IMPL_WINSOCK; #else - return AWS_SIT_PLATFORM_DEFAULT; + return AWS_SOCKET_IMPL_PLATFORM_DEFAULT; #endif } static int aws_socket_impl_type_validate_platform(enum aws_socket_impl_type type) { switch (type) { - case AWS_SIT_POSIX: + case AWS_SOCKET_IMPL_POSIX: #if !defined(AWS_ENABLE_EPOLL) && !defined(AWS_ENABLE_KQUEUE) AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Posix socket is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); -#endif // AWS_SIT_POSIX +#endif // AWS_SOCKET_IMPL_POSIX break; - case AWS_SIT_WINSOCK: + case AWS_SOCKET_IMPL_WINSOCK: #ifndef AWS_ENABLE_IO_COMPLETION_PORTS AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "WINSOCK is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_IO_COMPLETION_PORTS break; - case AWS_SIT_APPLE_NETWORK_FRAMEWORK: + case AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK: #ifndef AWS_ENABLE_DISPATCH_QUEUE AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Apple Network Framework is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); From 11c9be9a03f1beb1c8cf76cd03ecd8c58bba556c Mon Sep 17 00:00:00 2001 From: Alex Weibel Date: Tue, 12 Nov 2024 10:30:58 -0800 Subject: [PATCH 59/72] Add ML-KEM Support (#693) --- include/aws/io/tls_channel_handler.h | 10 +++++----- source/s2n/s2n_tls_channel_handler.c | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/aws/io/tls_channel_handler.h b/include/aws/io/tls_channel_handler.h index f44335b12..087b333a3 100644 --- a/include/aws/io/tls_channel_handler.h +++ b/include/aws/io/tls_channel_handler.h @@ -34,14 +34,14 @@ enum aws_tls_cipher_pref { /* Deprecated */ AWS_IO_TLS_CIPHER_PREF_KMS_PQ_TLSv1_0_2020_02 = 3, /* Deprecated */ AWS_IO_TLS_CIPHER_PREF_KMS_PQ_SIKE_TLSv1_0_2020_02 = 4, /* Deprecated */ AWS_IO_TLS_CIPHER_PREF_KMS_PQ_TLSv1_0_2020_07 = 5, + /* Deprecated */ AWS_IO_TLS_CIPHER_PREF_PQ_TLSv1_0_2021_05 = 6, /* - * This TLS cipher preference list contains post-quantum key exchange algorithms that have been submitted to NIST - * for potential future standardization. Support for this preference list, or PQ algorithms present in it, may be - * removed at any time in the future. PQ algorithms in this preference list will be used in hybrid mode, and always - * combined with a classical ECDHE key exchange. + * This TLS cipher preference list contains post-quantum key exchange algorithms that have been standardized by + * NIST. PQ algorithms in this preference list will be used in hybrid mode, and always combined with a classical + * ECDHE key exchange. */ - AWS_IO_TLS_CIPHER_PREF_PQ_TLSv1_0_2021_05 = 6, + AWS_IO_TLS_CIPHER_PREF_PQ_TLSV1_2_2024_10 = 7, AWS_IO_TLS_CIPHER_PREF_END_RANGE = 0xFFFF }; diff --git a/source/s2n/s2n_tls_channel_handler.c b/source/s2n/s2n_tls_channel_handler.c index 8326543e8..af8fbd834 100644 --- a/source/s2n/s2n_tls_channel_handler.c +++ b/source/s2n/s2n_tls_channel_handler.c @@ -270,6 +270,8 @@ bool aws_tls_is_cipher_pref_supported(enum aws_tls_cipher_pref cipher_pref) { #ifndef ANDROID case AWS_IO_TLS_CIPHER_PREF_PQ_TLSv1_0_2021_05: return true; + case AWS_IO_TLS_CIPHER_PREF_PQ_TLSV1_2_2024_10: + return true; #endif default: @@ -1536,6 +1538,9 @@ static struct aws_tls_ctx *s_tls_ctx_new( case AWS_IO_TLS_CIPHER_PREF_PQ_TLSv1_0_2021_05: security_policy = "PQ-TLS-1-0-2021-05-26"; break; + case AWS_IO_TLS_CIPHER_PREF_PQ_TLSV1_2_2024_10: + security_policy = "AWS-CRT-SDK-TLSv1.2-2023-PQ"; + break; default: AWS_LOGF_ERROR(AWS_LS_IO_TLS, "Unrecognized TLS Cipher Preference: %d", options->cipher_pref); aws_raise_error(AWS_IO_TLS_CIPHER_PREF_UNSUPPORTED); From c15417b1f2d6bc3c1d9ee7aac1ed18ae052652c6 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 12 Nov 2024 10:57:13 -0800 Subject: [PATCH 60/72] Update checksum based on previous PR changes (#695) Co-authored-by: Bret Ambrose --- .github/workflows/proof-alarm.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/proof-alarm.yml b/.github/workflows/proof-alarm.yml index b6e34c10c..4e33d77f7 100644 --- a/.github/workflows/proof-alarm.yml +++ b/.github/workflows/proof-alarm.yml @@ -16,7 +16,7 @@ jobs: - name: Check run: | TMPFILE=$(mktemp) - echo "c624a28de5af7f851a240a1e65a26c01 source/linux/epoll_event_loop.c" > $TMPFILE + echo "1fdf8e7a914412cc7242b8d64732fa89 source/linux/epoll_event_loop.c" > $TMPFILE md5sum --check $TMPFILE # No further steps if successful From 51e2d5a5ad64e2666a5de50ab7e84442e34e2c05 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 10:57:17 -0800 Subject: [PATCH 61/72] eliminate event loop constructor --- include/aws/io/event_loop.h | 10 ---------- include/aws/io/private/event_loop_impl.h | 4 +--- source/event_loop.c | 20 +++----------------- tests/socket_handler_test.c | 2 +- tests/tls_handler_test.c | 2 +- 5 files changed, 6 insertions(+), 32 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index b810e55f0..4cc428def 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -241,16 +241,6 @@ struct aws_event_loop *aws_event_loop_new_base( AWS_IO_API void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); -/** - * @internal - Don't use outside of testing. - * - * Creates an instance of the event loop implementation from the options. - */ -AWS_IO_API -struct aws_event_loop *aws_event_loop_new_with_options( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options); - /** * @internal - Don't use outside of testing. * diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 528c7514c..3d9bb99c4 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -192,9 +192,7 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a * Please note the event loop type defined in the options will be ignored. */ AWS_IO_API -struct aws_event_loop *aws_event_loop_new_default_with_options( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options); +struct aws_event_loop *aws_event_loop_new(struct aws_allocator *alloc, const struct aws_event_loop_options *options); /** * Initializes common event-loop data structures. diff --git a/source/event_loop.c b/source/event_loop.c index e6f84294b..3d432d18f 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -28,26 +28,12 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a .type = AWS_EVENT_LOOP_PLATFORM_DEFAULT, }; - return aws_event_loop_new_with_options(alloc, &options); -} - -struct aws_event_loop *aws_event_loop_new_default_with_options( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options) { - struct aws_event_loop_options local_options = { - .thread_options = options->thread_options, - .clock = options->clock, - .type = AWS_EVENT_LOOP_PLATFORM_DEFAULT, - }; - - return aws_event_loop_new_with_options(alloc, &local_options); + return aws_event_loop_new(alloc, &options); } static enum aws_event_loop_type aws_event_loop_get_default_type(void); static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type); -struct aws_event_loop *aws_event_loop_new_with_options( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options) { +struct aws_event_loop *aws_event_loop_new(struct aws_allocator *alloc, const struct aws_event_loop_options *options) { enum aws_event_loop_type type = options->type; if (type == AWS_EVENT_LOOP_PLATFORM_DEFAULT) { @@ -246,7 +232,7 @@ static struct aws_event_loop *s_default_new_event_loop( void *user_data) { (void)user_data; - return aws_event_loop_new_default_with_options(allocator, options); + return aws_event_loop_new(allocator, options); } struct aws_event_loop_group *aws_event_loop_group_new( diff --git a/tests/socket_handler_test.c b/tests/socket_handler_test.c index ee7290d4e..1f301bfee 100644 --- a/tests/socket_handler_test.c +++ b/tests/socket_handler_test.c @@ -994,7 +994,7 @@ static struct aws_event_loop *s_default_new_event_loop( void *user_data) { (void)user_data; - return aws_event_loop_new_default_with_options(allocator, options); + return aws_event_loop_new(allocator, options); } static int s_statistic_test_clock_fn(uint64_t *timestamp) { diff --git a/tests/tls_handler_test.c b/tests/tls_handler_test.c index 7b1a68c32..f943c3371 100644 --- a/tests/tls_handler_test.c +++ b/tests/tls_handler_test.c @@ -1890,7 +1890,7 @@ static struct aws_event_loop *s_default_new_event_loop( void *user_data) { (void)user_data; - return aws_event_loop_new_default_with_options(allocator, options); + return aws_event_loop_new(allocator, options); } static int s_statistic_test_clock_fn(uint64_t *timestamp) { From 8be6cd2b2ce8cb2f3ad0ff8186a1692dad166a7e Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 13:37:02 -0800 Subject: [PATCH 62/72] clean up and format --- .github/workflows/ci.yml | 2 +- include/aws/io/private/event_loop_impl.h | 2 -- include/aws/io/socket.h | 8 ++------ source/event_loop.c | 6 ++---- source/exponential_backoff_retry_strategy.c | 1 - 5 files changed, 5 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d423b936..d0e25f7f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -227,4 +227,4 @@ jobs: sudo pkg_add py3-urllib3 python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder')" chmod a+x builder - ./builder build -p ${{ env.PACKAGE_NAME }} \ No newline at end of file + ./builder build -p ${{ env.PACKAGE_NAME }} diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 3d9bb99c4..ac5318a3c 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -188,8 +188,6 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a /** * Creates an instance of the default event loop implementation for the current architecture and operating system using * extendable options. - * - * Please note the event loop type defined in the options will be ignored. */ AWS_IO_API struct aws_event_loop *aws_event_loop_new(struct aws_allocator *alloc, const struct aws_event_loop_options *options); diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index 916f62171..eddc259ab 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -32,8 +32,8 @@ enum aws_socket_type { }; /** - * Socket Implementation type. Decides which socket implementation is used. If set to `AWS_SOCKET_IMPL_PLATFORM_DEFAULT`, it - * will automatically use the platform’s default. + * Socket Implementation type. Decides which socket implementation is used. If set to + * `AWS_SOCKET_IMPL_PLATFORM_DEFAULT`, it will automatically use the platform’s default. * * PLATFORM DEFAULT SOCKET IMPLEMENTATION TYPE * Linux | AWS_SOCKET_IMPL_POSIX @@ -206,25 +206,21 @@ aws_ms_fn_ptr aws_winsock_get_connectex_fn(void); aws_ms_fn_ptr aws_winsock_get_acceptex_fn(void); #endif - int aws_socket_init_posix( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options); - int aws_socket_init_winsock( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options); - int aws_socket_init_apple_nw_socket( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options); - AWS_EXTERN_C_BEGIN /** diff --git a/source/event_loop.c b/source/event_loop.c index 3d432d18f..04bf8dd98 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -16,9 +16,9 @@ #include #ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK - static enum aws_event_loop_type s_default_event_loop_type_override = AWS_EVENT_LOOP_DISPATCH_QUEUE; +static enum aws_event_loop_type s_default_event_loop_type_override = AWS_EVENT_LOOP_DISPATCH_QUEUE; #else - static enum aws_event_loop_type s_default_event_loop_type_override = AWS_EVENT_LOOP_PLATFORM_DEFAULT; +static enum aws_event_loop_type s_default_event_loop_type_override = AWS_EVENT_LOOP_PLATFORM_DEFAULT; #endif struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock) { @@ -697,5 +697,3 @@ struct aws_event_loop *aws_event_loop_new_epoll_with_options( return NULL; } #endif // AWS_ENABLE_KQUEUE - - diff --git a/source/exponential_backoff_retry_strategy.c b/source/exponential_backoff_retry_strategy.c index 14452dd05..2110cbd46 100644 --- a/source/exponential_backoff_retry_strategy.c +++ b/source/exponential_backoff_retry_strategy.c @@ -12,7 +12,6 @@ #include #include #include -#include #include From 61cbc9034b32d46a2f91b63d955120419e795425 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 13:40:48 -0800 Subject: [PATCH 63/72] lint --- include/aws/io/event_loop.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 4cc428def..bc3f4c03a 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -49,7 +49,8 @@ struct aws_event_loop_vtable { }; /** - * Event Loop Type. If set to `AWS_EVENT_LOOP_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default. + * Event Loop Type. If set to `AWS_EVENT_LOOP_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s + * default. * * Default Event Loop Type * Linux | AWS_EVENT_LOOP_EPOLL From c507d137e25fba8283674a7f89564d771f21930d Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 13:58:50 -0800 Subject: [PATCH 64/72] update comments --- include/aws/io/event_loop.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index fc5af7544..7778edd7d 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -104,6 +104,8 @@ struct aws_event_loop_group_options { }; /** + * @internal - Don't use outside of testing. + * * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to * retrieve the default type value. * If `aws_event_loop_override_default_type` has been called, return the override default type. From c54b99e5fe0c5e15b5144956d595a98847f080cd Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 14:08:42 -0800 Subject: [PATCH 65/72] rename enum --- source/event_loop.c | 2 +- tests/event_loop_test.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/event_loop.c b/source/event_loop.c index 8d1ba9802..e49515d73 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -588,7 +588,7 @@ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_ * retrieve the default type value. * If `aws_event_loop_override_default_type` has been called, return the override default type. */ -static enum aws_event_loop_type aws_event_loop_get_default_type(void) { +enum aws_event_loop_type aws_event_loop_get_default_type(void) { if (s_default_event_loop_type_override != AWS_EVENT_LOOP_PLATFORM_DEFAULT) { return s_default_event_loop_type_override; } diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index 3bd5829b9..6fa75ef02 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -80,7 +80,7 @@ static int s_test_event_loop_xthread_scheduled_tasks_execute(struct aws_allocato // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, // therefore we do not validate the thread id for dispatch queue. - if (aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE) { + if (aws_event_loop_get_default_type() != AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_FALSE(aws_thread_thread_id_equal(task_args.thread_id, aws_thread_current_thread_id())); } @@ -156,7 +156,7 @@ static int s_test_event_loop_canceled_tasks_run_in_el_thread(struct aws_allocato ASSERT_TRUE(task1_args.was_in_thread); // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, // therefore we do not validate the thread id for dispatch queue. - if (aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE) { + if (aws_event_loop_get_default_type() != AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_FALSE(aws_thread_thread_id_equal(task1_args.thread_id, aws_thread_current_thread_id())); } ASSERT_INT_EQUALS(AWS_TASK_STATUS_RUN_READY, task1_args.status); @@ -174,7 +174,7 @@ static int s_test_event_loop_canceled_tasks_run_in_el_thread(struct aws_allocato ASSERT_TRUE(task2_args.was_in_thread); // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, // therefore we do not validate the thread id for dispatch queue. - if (aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE) { + if (aws_event_loop_get_default_type() != AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_TRUE(aws_thread_thread_id_equal(task2_args.thread_id, aws_thread_current_thread_id())); } ASSERT_INT_EQUALS(AWS_TASK_STATUS_CANCELED, task2_args.status); From 11d0f8478a9746540dbcfca9d838748be43d6e13 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 14:10:53 -0800 Subject: [PATCH 66/72] rename enum --- tests/socket_test.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/socket_test.c b/tests/socket_test.c index ceff35c79..aeb9f458e 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -247,7 +247,7 @@ static int s_test_socket_ex( // The Apple Network Framework always require a "start listener/start connection" // for setup a server socket - if (options->type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { + if (options->type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_SUCCESS(aws_socket_listen(&listener, 1024)); ASSERT_SUCCESS(aws_socket_start_accept(&listener, event_loop, s_local_listener_incoming, &listener_args)); } @@ -262,7 +262,7 @@ static int s_test_socket_ex( } ASSERT_SUCCESS(aws_socket_connect(&outgoing, endpoint, event_loop, s_local_outgoing_connection, &outgoing_args)); - if (listener.options.type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { + if (listener.options.type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_SUCCESS(aws_mutex_lock(&mutex)); ASSERT_SUCCESS( aws_condition_variable_wait_pred(&condition_variable, &mutex, s_incoming_predicate, &listener_args)); @@ -275,7 +275,7 @@ static int s_test_socket_ex( struct aws_socket *server_sock = &listener; - if (options->type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { + if (options->type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_TRUE(listener_args.incoming_invoked); ASSERT_FALSE(listener_args.error_invoked); server_sock = listener_args.incoming; @@ -486,7 +486,7 @@ static int s_test_socket_udp_dispatch_queue( ASSERT_SUCCESS(aws_mutex_unlock(&mutex)); ASSERT_INT_EQUALS(AWS_OP_SUCCESS, io_args.error_code); - if (listener.options.type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { + if (listener.options.type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_SUCCESS(aws_mutex_lock(&mutex)); ASSERT_SUCCESS( aws_condition_variable_wait_pred(&condition_variable, &mutex, s_incoming_predicate, &listener_args)); @@ -586,7 +586,7 @@ static int s_test_socket( struct aws_socket_options *options, struct aws_socket_endpoint *endpoint) { - if (aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE && options->type == AWS_SOCKET_DGRAM) + if (aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE && options->type == AWS_SOCKET_DGRAM) return s_test_socket_udp_dispatch_queue(allocator, options, endpoint); else return s_test_socket_ex(allocator, options, NULL, endpoint); @@ -1049,7 +1049,7 @@ static int s_test_outgoing_local_sock_errors(struct aws_allocator *allocator, vo int socket_connect_result = aws_socket_connect(&outgoing, &endpoint, event_loop, s_null_sock_connection, &args); // As Apple network framework has a async API design, we would not get the error back on connect - if(aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE){ + if(aws_event_loop_get_default_type() != AWS_EVENT_LOOP_DISPATCH_QUEUE){ ASSERT_FAILS(socket_connect_result); ASSERT_TRUE( aws_last_error() == AWS_IO_SOCKET_CONNECTION_REFUSED || aws_last_error() == AWS_ERROR_FILE_INVALID_PATH); @@ -1263,7 +1263,7 @@ static int s_test_bind_on_zero_port( ASSERT_SUCCESS(aws_socket_get_bound_address(&incoming, &local_address1)); - if (aws_event_loop_get_default_type() == AWS_ELT_DISPATCH_QUEUE) { + if (aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE) { struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; From 69cbb092f696bd841e90294b7b4f7828232b1561 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 14:11:19 -0800 Subject: [PATCH 67/72] lint --- source/darwin/dispatch_queue_event_loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/darwin/dispatch_queue_event_loop.c b/source/darwin/dispatch_queue_event_loop.c index d83816e75..cc7a66fa6 100644 --- a/source/darwin/dispatch_queue_event_loop.c +++ b/source/darwin/dispatch_queue_event_loop.c @@ -15,8 +15,8 @@ #include -#include #include "dispatch_queue.h" +#include #include #include From 652195b559c94f99a7d65b2968c2ebc9ddf0b9db Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 14:30:22 -0800 Subject: [PATCH 68/72] remove warning on nw socket --- source/socket.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/socket.c b/source/socket.c index 7e7016132..bdcfe46b9 100644 --- a/source/socket.c +++ b/source/socket.c @@ -126,8 +126,6 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons case AWS_SOCKET_IMPL_WINSOCK: return aws_socket_init_winsock(socket, alloc, options); case AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK: - // Apple Network Framework is not implemented yet. We should not use it yet. - AWS_ASSERT(false && "Invalid socket implementation on platform."); return aws_socket_init_apple_nw_socket(socket, alloc, options); default: AWS_ASSERT(false && "Invalid socket implementation on platform."); From 7b51b56e6e24c956893fa2343406e76dcbbf048a Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 14:46:12 -0800 Subject: [PATCH 69/72] wrap the kqueue function --- source/bsd/kqueue_event_loop.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/bsd/kqueue_event_loop.c b/source/bsd/kqueue_event_loop.c index a03f8daf4..fa962cbca 100644 --- a/source/bsd/kqueue_event_loop.c +++ b/source/bsd/kqueue_event_loop.c @@ -131,6 +131,7 @@ struct aws_event_loop_vtable s_kqueue_vtable = { .is_on_callers_thread = s_is_event_thread, }; +#ifdef AWS_ENABLE_KQUEUE struct aws_event_loop *aws_event_loop_new_kqueue_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { @@ -291,6 +292,7 @@ struct aws_event_loop *aws_event_loop_new_kqueue_with_options( } return NULL; } +#endif //AWS_ENABLE_KQUEUE static void s_destroy(struct aws_event_loop *event_loop) { AWS_LOGF_INFO(AWS_LS_IO_EVENT_LOOP, "id=%p: destroying event_loop", (void *)event_loop); From aa876a1b1b4bdb09188cf615074668268c2a57db Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 15:01:04 -0800 Subject: [PATCH 70/72] add posix file for non-darwin Apple platform --- CMakeLists.txt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a128c7e0..52e41d482 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,8 @@ elseif (APPLE) ) file(GLOB AWS_IO_OS_SRC + "source/bsd/*.c" + "source/posix/*.c" "source/darwin/*.c" ) @@ -129,11 +131,6 @@ elseif (APPLE) # Enable KQUEUE on MacOS if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - file(GLOB AWS_IO_KUEUE_SRC - "source/bsd/*.c" - "source/posix/*.c" - ) - list(APPEND AWS_IO_OS_SRC ${AWS_IO_KUEUE_SRC}) list(APPEND EVENT_LOOP_DEFINES "KQUEUE") endif() From ee7fa7644938ff24d244e49e98c402b8e59e80ab Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 15:02:10 -0800 Subject: [PATCH 71/72] fix lint --- source/bsd/kqueue_event_loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/bsd/kqueue_event_loop.c b/source/bsd/kqueue_event_loop.c index fa962cbca..0cd2a04bc 100644 --- a/source/bsd/kqueue_event_loop.c +++ b/source/bsd/kqueue_event_loop.c @@ -292,7 +292,7 @@ struct aws_event_loop *aws_event_loop_new_kqueue_with_options( } return NULL; } -#endif //AWS_ENABLE_KQUEUE +#endif // AWS_ENABLE_KQUEUE static void s_destroy(struct aws_event_loop *event_loop) { AWS_LOGF_INFO(AWS_LS_IO_EVENT_LOOP, "id=%p: destroying event_loop", (void *)event_loop); From d0dddda255cbcdc472d7955e4e6ac0a04a9c28c1 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 15:07:14 -0800 Subject: [PATCH 72/72] extend the shutdown wait time --- tests/socket_test.c | 8 +++++--- tests/tls_handler_test.c | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/socket_test.c b/tests/socket_test.c index aeb9f458e..9f6c10935 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -262,7 +262,8 @@ static int s_test_socket_ex( } ASSERT_SUCCESS(aws_socket_connect(&outgoing, endpoint, event_loop, s_local_outgoing_connection, &outgoing_args)); - if (listener.options.type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE) { + if (listener.options.type == AWS_SOCKET_STREAM || + aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_SUCCESS(aws_mutex_lock(&mutex)); ASSERT_SUCCESS( aws_condition_variable_wait_pred(&condition_variable, &mutex, s_incoming_predicate, &listener_args)); @@ -486,7 +487,8 @@ static int s_test_socket_udp_dispatch_queue( ASSERT_SUCCESS(aws_mutex_unlock(&mutex)); ASSERT_INT_EQUALS(AWS_OP_SUCCESS, io_args.error_code); - if (listener.options.type == AWS_SOCKET_STREAM || aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE) { + if (listener.options.type == AWS_SOCKET_STREAM || + aws_event_loop_get_default_type() == AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_SUCCESS(aws_mutex_lock(&mutex)); ASSERT_SUCCESS( aws_condition_variable_wait_pred(&condition_variable, &mutex, s_incoming_predicate, &listener_args)); @@ -1049,7 +1051,7 @@ static int s_test_outgoing_local_sock_errors(struct aws_allocator *allocator, vo int socket_connect_result = aws_socket_connect(&outgoing, &endpoint, event_loop, s_null_sock_connection, &args); // As Apple network framework has a async API design, we would not get the error back on connect - if(aws_event_loop_get_default_type() != AWS_EVENT_LOOP_DISPATCH_QUEUE){ + if (aws_event_loop_get_default_type() != AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_FAILS(socket_connect_result); ASSERT_TRUE( aws_last_error() == AWS_IO_SOCKET_CONNECTION_REFUSED || aws_last_error() == AWS_ERROR_FILE_INVALID_PATH); diff --git a/tests/tls_handler_test.c b/tests/tls_handler_test.c index af8b3f63f..2e0dbda42 100644 --- a/tests/tls_handler_test.c +++ b/tests/tls_handler_test.c @@ -904,7 +904,7 @@ static int s_tls_channel_shutdown_with_cache_test_helper(struct aws_allocator *a ASSERT_SUCCESS(s_tls_channel_server_client_tester_cleanup()); // wait for socket ref count drop and released - aws_thread_current_sleep(1000000000); + aws_thread_current_sleep(3000000000); return AWS_OP_SUCCESS; }