From 9d973027737bba6b404dd0b7aa0a279f5d3f7eab Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 30 Oct 2024 16:28:48 -0700 Subject: [PATCH 01/61] 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 02/61] 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 03/61] 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 04/61] 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 05/61] 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 06/61] 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 07/61] 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 08/61] 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 09/61] [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 10/61] 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 11/61] 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 12/61] 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 13/61] 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 14/61] 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 15/61] 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 16/61] 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 9323cc38734f61cebf4695d7977116b696bd8823 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Thu, 7 Nov 2024 14:16:19 -0800 Subject: [PATCH 17/61] 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 18/61] 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 19/61] 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 20/61] 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 21/61] 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 22/61] 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 23/61] 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 24/61] 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 25/61] 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 7cb09361985fd8a9fd03cdcabbf8aa8b7608856f Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 11:42:50 -0800 Subject: [PATCH 26/61] 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 e84a1a6a8776ce17589e5256cef123f429872def Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 15:35:03 -0800 Subject: [PATCH 27/61] 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 28/61] 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 29/61] 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 30/61] 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 0f751853ccbc8907a77ff98484dadb51ec21ab4d Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 17:14:48 -0800 Subject: [PATCH 31/61] 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 32/61] 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 16861b9946f252186aa7066052aad07ca9dd3667 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 18:00:11 -0800 Subject: [PATCH 33/61] 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 17c7cca73006c8793692183fc7a4b506ee11f945 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 8 Nov 2024 18:03:46 -0800 Subject: [PATCH 34/61] 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 d68acdb80838ee024538d7ebec9ba6ce0c81fa8e Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Mon, 11 Nov 2024 07:26:43 -0800 Subject: [PATCH 35/61] 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 39991969a2a5b9f7657e37aa8e7477f993b73541 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 11 Nov 2024 13:14:41 -0800 Subject: [PATCH 36/61] 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 37/61] 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 38/61] 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 405c988df9d0523939c2f8169740c1d384a9e7f7 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 09:50:54 -0800 Subject: [PATCH 39/61] 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 51e2d5a5ad64e2666a5de50ab7e84442e34e2c05 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 10:57:17 -0800 Subject: [PATCH 40/61] 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 41/61] 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 42/61] 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 7b51b56e6e24c956893fa2343406e76dcbbf048a Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 14:46:12 -0800 Subject: [PATCH 43/61] 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 44/61] 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 45/61] 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 2fb32ab79942bccb8f651ff4f93d5f1a1fa0954a Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 15:25:15 -0800 Subject: [PATCH 46/61] handling library error in cmake --- CMakeLists.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52e41d482..ba759dc21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,17 +117,13 @@ elseif (APPLE) ) find_library(SECURITY_LIB Security) - if (NOT SECURITY_LIB) - 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 () - list(APPEND PLATFORM_LIBS "-framework Security -framework Network") - list(APPEND EVENT_LOOP_DEFINES "DISPATCH_QUEUE") + # Enable dispatch queue if the libraries are avaliable + if (NETWORK_LIB AND SECURITY_LIB) + list(APPEND PLATFORM_LIBS "-framework Security -framework Network") + list(APPEND EVENT_LOOP_DEFINES "DISPATCH_QUEUE") + endif () # Enable KQUEUE on MacOS if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") @@ -196,6 +192,9 @@ aws_add_sanitizers(${PROJECT_NAME}) # We are not ABI stable yet set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0) +if (NOT EVENT_LOOP_DEFINES) + message(FATAL_ERROR "Event Loop is not setup on the platform.") +endif() foreach(EVENT_LOOP_DEFINE IN LISTS EVENT_LOOP_DEFINES) target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_ENABLE_${EVENT_LOOP_DEFINE}") endforeach() From 7ea8588cf17f831a21250518856a38fca6848e24 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Wed, 13 Nov 2024 14:27:32 -0800 Subject: [PATCH 47/61] renmae event loop new function --- include/aws/io/event_loop.h | 4 ++-- include/aws/io/private/event_loop_impl.h | 11 +++++++---- source/bsd/kqueue_event_loop.c | 2 +- source/event_loop.c | 16 ++++++++-------- source/windows/iocp/iocp_event_loop.c | 2 +- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index bc3f4c03a..ac3532424 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -54,9 +54,9 @@ struct aws_event_loop_vtable { * * Default Event Loop Type * Linux | AWS_EVENT_LOOP_EPOLL - * Windows | AWS_EVENT_LOOP_IOCP + * Windows | AWS_EVENT_LOOP_IOCP * BSD Variants| AWS_EVENT_LOOP_KQUEUE - * MacOS | AWS_EVENT_LOOP_KQUEUE + * MacOS | AWS_EVENT_LOOP_KQUEUE * iOS | AWS_EVENT_LOOP_DISPATCH_QUEUE */ enum aws_event_loop_type { diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index ac5318a3c..ec47bb685 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -98,16 +98,19 @@ struct aws_event_loop_options { enum aws_event_loop_type type; }; -struct aws_event_loop *aws_event_loop_new_iocp_with_options( +struct aws_event_loop *aws_event_loop_new_with_iocp( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( + +struct aws_event_loop *aws_event_loop_new_with_dispatch_queue( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -struct aws_event_loop *aws_event_loop_new_kqueue_with_options( + +struct aws_event_loop *aws_event_loop_new_with_kqueue( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -struct aws_event_loop *aws_event_loop_new_epoll_with_options( + +struct aws_event_loop *aws_event_loop_new_with_epoll( struct aws_allocator *alloc, const struct aws_event_loop_options *options); diff --git a/source/bsd/kqueue_event_loop.c b/source/bsd/kqueue_event_loop.c index 0cd2a04bc..7e6b918d9 100644 --- a/source/bsd/kqueue_event_loop.c +++ b/source/bsd/kqueue_event_loop.c @@ -132,7 +132,7 @@ struct aws_event_loop_vtable s_kqueue_vtable = { }; #ifdef AWS_ENABLE_KQUEUE -struct aws_event_loop *aws_event_loop_new_kqueue_with_options( +struct aws_event_loop *aws_event_loop_new_with_kqueue( 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 04bf8dd98..60eb609e9 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -47,13 +47,13 @@ struct aws_event_loop *aws_event_loop_new(struct aws_allocator *alloc, const str switch (type) { case AWS_EVENT_LOOP_EPOLL: - return aws_event_loop_new_epoll_with_options(alloc, options); + return aws_event_loop_new_with_epoll(alloc, options); case AWS_EVENT_LOOP_IOCP: - return aws_event_loop_new_iocp_with_options(alloc, options); + return aws_event_loop_new_with_iocp(alloc, options); case AWS_EVENT_LOOP_KQUEUE: - return aws_event_loop_new_kqueue_with_options(alloc, options); + return aws_event_loop_new_with_kqueue(alloc, options); case AWS_EVENT_LOOP_DISPATCH_QUEUE: - return aws_event_loop_new_dispatch_queue_with_options(alloc, options); + return aws_event_loop_new_with_dispatch_queue(alloc, options); default: AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type on the platform."); aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); @@ -645,7 +645,7 @@ static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) return AWS_OP_SUCCESS; } -struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( +struct aws_event_loop *aws_event_loop_new_with_dispatch_queue( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { (void)alloc; @@ -658,7 +658,7 @@ struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( } #ifndef AWS_ENABLE_IO_COMPLETION_PORTS -struct aws_event_loop *aws_event_loop_new_iocp_with_options( +struct aws_event_loop *aws_event_loop_new_with_iocp( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { (void)alloc; @@ -672,7 +672,7 @@ struct aws_event_loop *aws_event_loop_new_iocp_with_options( #endif // AWS_ENABLE_IO_COMPLETION_PORTS #ifndef AWS_ENABLE_KQUEUE -struct aws_event_loop *aws_event_loop_new_kqueue_with_options( +struct aws_event_loop *aws_event_loop_new_with_kqueue( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { (void)alloc; @@ -686,7 +686,7 @@ struct aws_event_loop *aws_event_loop_new_kqueue_with_options( #endif // AWS_ENABLE_EPOLL #ifndef AWS_ENABLE_EPOLL -struct aws_event_loop *aws_event_loop_new_epoll_with_options( +struct aws_event_loop *aws_event_loop_new_with_epoll( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { (void)alloc; diff --git a/source/windows/iocp/iocp_event_loop.c b/source/windows/iocp/iocp_event_loop.c index 473629de9..584ba0b1c 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_iocp_with_options( +struct aws_event_loop *aws_event_loop_new_with_iocp_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { AWS_ASSERT(alloc); From 1cbe98942906d9a185f5cf967a60698426270469 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 21 Nov 2024 10:45:28 -0800 Subject: [PATCH 48/61] update code review comments --- source/event_loop.c | 67 +++++++++++++++++---------------- source/posix/socket.c | 4 +- source/socket.c | 73 +++++++++++++++++------------------- source/windows/iocp/socket.c | 4 +- 4 files changed, 72 insertions(+), 76 deletions(-) diff --git a/source/event_loop.c b/source/event_loop.c index 60eb609e9..ad1e47f1d 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -31,7 +31,36 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a return aws_event_loop_new(alloc, &options); } -static enum aws_event_loop_type aws_event_loop_get_default_type(void); +/** + * 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_EVENT_LOOP_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_ENABLE_KQUEUE + return AWS_EVENT_LOOP_KQUEUE; +#endif +#ifdef AWS_ENABLE_DISPATCH_QUEUE + return AWS_EVENT_LOOP_DISPATCH_QUEUE; +#endif +#ifdef AWS_ENABLE_EPOLL + return AWS_EVENT_LOOP_EPOLL; +#endif +#ifdef AWS_OS_WINDOWS + return AWS_EVENT_LOOP_IOCP; +#endif + AWS_LOGF_ERROR( + AWS_LS_IO_EVENT_LOOP, + "Failed to get default event loop type. The library is not built correctly on the platform."); +} + static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type); struct aws_event_loop *aws_event_loop_new(struct aws_allocator *alloc, const struct aws_event_loop_options *options) { @@ -173,7 +202,10 @@ 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; @@ -584,33 +616,6 @@ 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_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_EVENT_LOOP_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_ENABLE_KQUEUE - return AWS_EVENT_LOOP_KQUEUE; -#endif -#ifdef AWS_ENABLE_DISPATCH_QUEUE - return AWS_EVENT_LOOP_DISPATCH_QUEUE; -#endif -#ifdef AWS_ENABLE_EPOLL - return AWS_EVENT_LOOP_EPOLL; -#endif -#ifdef AWS_OS_WINDOWS - return AWS_EVENT_LOOP_IOCP; -#endif -} - static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) { switch (type) { case AWS_EVENT_LOOP_EPOLL: @@ -650,7 +655,6 @@ struct aws_event_loop *aws_event_loop_new_with_dispatch_queue( const struct aws_event_loop_options *options) { (void)alloc; (void)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); @@ -663,7 +667,6 @@ struct aws_event_loop *aws_event_loop_new_with_iocp( const struct aws_event_loop_options *options) { (void)alloc; (void)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); @@ -677,7 +680,6 @@ struct aws_event_loop *aws_event_loop_new_with_kqueue( const struct aws_event_loop_options *options) { (void)alloc; (void)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); @@ -691,7 +693,6 @@ struct aws_event_loop *aws_event_loop_new_with_epoll( const struct aws_event_loop_options *options) { (void)alloc; (void)options; - AWS_ASSERT(0); AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Epoll is not supported on the platform"); return NULL; diff --git a/source/posix/socket.c b/source/posix/socket.c index 9ea344280..91f54f0d3 100644 --- a/source/posix/socket.c +++ b/source/posix/socket.c @@ -220,7 +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); -struct aws_socket_vtable g_posix_socket_vtable = { +struct aws_socket_vtable s_posix_socket_vtable = { .socket_cleanup_fn = s_socket_clean_up, .socket_connect_fn = s_socket_connect, .socket_bind_fn = s_socket_bind, @@ -263,7 +263,7 @@ static int s_socket_init( socket->state = INIT; socket->options = *options; socket->impl = posix_socket; - socket->vtable = &g_posix_socket_vtable; + socket->vtable = &s_posix_socket_vtable; if (existing_socket_fd < 0) { int err = s_create_socket(socket, options); diff --git a/source/socket.c b/source/socket.c index 2fcdef0e8..ea1b5b00a 100644 --- a/source/socket.c +++ b/source/socket.c @@ -104,7 +104,34 @@ bool aws_socket_is_open(struct aws_socket *socket) { return socket->vtable->socket_is_open_fn(socket); } -static enum aws_socket_impl_type aws_socket_get_default_impl_type(void); +/** + * 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_SOCKET_IMPL_PLATFORM_DEFAULT; +// override default socket +#ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK + type = AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; +#endif // AWS_USE_APPLE_NETWORK_FRAMEWORK + if (type != AWS_SOCKET_IMPL_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_SOCKET_IMPL_POSIX; +#elif AWS_ENABLE_DISPATCH_QUEUE + return AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; +#elif AWS_ENABLE_IO_COMPLETION_PORTS + return AWS_SOCKET_IMPL_WINSOCK; +#else + return AWS_SOCKET_IMPL_PLATFORM_DEFAULT; +#endif +} + 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) { @@ -156,45 +183,13 @@ 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_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_ENABLE_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_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_SOCKET_IMPL_PLATFORM_DEFAULT; -// override default socket -#ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK - type = AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; -#endif // AWS_USE_APPLE_NETWORK_FRAMEWORK - if (type != AWS_SOCKET_IMPL_PLATFORM_DEFAULT) { - return type; + enum aws_socket_impl_type socket_type = aws_socket_get_default_impl_type(); + if (socket_type == AWS_SOCKET_IMPL_POSIX) + snprintf(endpoint->address, sizeof(endpoint->address), "testsock" PRInSTR ".sock", AWS_BYTE_BUF_PRI(uuid_buf)); + else if (socket_type == AWS_SOCKET_IMPL_WINSOCK) { + snprintf( + endpoint->address, sizeof(endpoint->address), "\\\\.\\pipe\\testsock" PRInSTR, AWS_BYTE_BUF_PRI(uuid_buf)); } -/** - * 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_SOCKET_IMPL_POSIX; -#endif -#ifdef AWS_ENABLE_DISPATCH_QUEUE - return AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; -#endif -#ifdef AWS_ENABLE_IO_COMPLETION_PORTS - return AWS_SOCKET_IMPL_WINSOCK; -#else - return AWS_SOCKET_IMPL_PLATFORM_DEFAULT; -#endif } static int aws_socket_impl_type_validate_platform(enum aws_socket_impl_type type) { diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index c398c9d5d..48f512859 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -270,7 +270,7 @@ static struct winsock_vtable s_winsock_vtables[3][2] = { }, }; -struct aws_socket_vtable g_winsock_vtable = { +struct aws_socket_vtable s_winsock_vtable = { .socket_cleanup_fn = s_socket_clean_up, .socket_connect_fn = s_socket_connect, .socket_bind_fn = s_socket_bind, @@ -406,7 +406,7 @@ static int s_socket_init( return AWS_OP_ERR; } - socket->vtable = &g_winsock_vtable; + socket->vtable = &s_winsock_vtable; impl->winsock_vtable = &s_winsock_vtables[options->domain][options->type]; if (!impl->winsock_vtable || !impl->winsock_vtable->connection_success) { From 667e41afb7cb77750096f6c20232220c2436f62c Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 21 Nov 2024 16:01:05 -0800 Subject: [PATCH 49/61] add unit test --- source/socket.c | 2 +- tests/CMakeLists.txt | 2 ++ tests/event_loop_test.c | 53 +++++++++++++++++++++++++++++++++++++++++ tests/socket_test.c | 40 +++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 1 deletion(-) diff --git a/source/socket.c b/source/socket.c index ea1b5b00a..dfe89b0b5 100644 --- a/source/socket.c +++ b/source/socket.c @@ -135,7 +135,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); 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 + // 1. get socket type & validate type is available on the platform enum aws_socket_impl_type type = options->impl_type; if (type == AWS_SOCKET_IMPL_PLATFORM_DEFAULT) { type = aws_socket_get_default_impl_type(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dc4c07b41..294f86060 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -50,9 +50,11 @@ add_test_case(event_loop_multiple_stops) add_test_case(event_loop_group_setup_and_shutdown) add_test_case(event_loop_group_setup_and_shutdown_async) add_test_case(numa_aware_event_loop_group_setup_and_shutdown) +add_test_case(event_loop_all_types_creation) add_test_case(io_testing_channel) +add_test_case(test_socket_impl_types_creation) add_test_case(local_socket_communication) add_net_test_case(tcp_socket_communication) add_net_test_case(udp_socket_communication) diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index 5004bb18e..d8521d565 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -862,6 +862,59 @@ static int s_state_wait_1sec(struct thread_tester *tester) { } } +/* Verify default event loop type */ +static int s_test_event_loop_creation( + struct aws_allocator *allocator, + enum aws_event_loop_type type, + bool expect_success) { + struct aws_event_loop_options event_loop_options = { + .thread_options = NULL, + .clock = aws_high_res_clock_get_ticks, + .type = type, + }; + + struct aws_event_loop *event_loop = aws_event_loop_new(allocator, &event_loop_options); + + if (expect_success) { + ASSERT_NOT_NULL(event_loop); + /* Clean up tester*/ + aws_event_loop_destroy(event_loop); + } else { + ASSERT_NULL(event_loop); + } + + return AWS_OP_SUCCESS; +} + +/* Verify default event loop type */ +static int s_test_event_loop_all_types_creation(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + bool enable_kqueue = false; + bool enable_epoll = false; + bool enable_iocp = false; + bool enable_dispatch_queue = false; +# ifdef AWS_ENABLE_KQUEUE + enable_kqueue = true; +# endif +# ifdef AWS_ENABLE_EPOLL + enable_epoll = true; +# endif +# ifdef AWS_ENABLE_IO_COMPLETION_PORTS + enable_iocp = true; +# endif +# ifdef AWS_ENABLE_DISPATCH_QUEUE +// TODO: Dispatch queue support is not yet implemented. Uncomment the following line once the dispatch queue is ready. +// enable_dispatch_queue = true; +# endif + + return s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_EPOLL, enable_epoll) || + s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_IOCP, enable_iocp) || + s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_KQUEUE, enable_kqueue) || + s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_DISPATCH_QUEUE, enable_dispatch_queue); +} + +AWS_TEST_CASE(event_loop_all_types_creation, s_test_event_loop_all_types_creation) + /* Test that subscribe/unubscribe work at all */ static int s_test_event_loop_subscribe_unsubscribe(struct aws_allocator *allocator, void *ctx) { (void)ctx; diff --git a/tests/socket_test.c b/tests/socket_test.c index e01834a75..4d35efa55 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -389,6 +389,46 @@ static int s_test_socket_ex( return 0; } +static int s_test_socket_creation(struct aws_allocator *alloc, enum aws_socket_impl_type type, int expected_result) { + struct aws_socket socket; + + struct aws_socket_options options = { + .type = AWS_SOCKET_STREAM, + .domain = AWS_SOCKET_IPV4, + .keep_alive_interval_sec = 0, + .keep_alive_timeout_sec = 0, + .connect_timeout_ms = 0, + .keepalive = 0, + .impl_type = type, + }; + + int err = aws_socket_init(&socket, alloc, &options); + if (err == AWS_OP_SUCCESS) { + aws_socket_clean_up(&socket); + ASSERT_INT_EQUALS(err, expected_result); + } else { // socket init failed, validate the last error + ASSERT_INT_EQUALS(aws_last_error(), expected_result); + } + return AWS_OP_SUCCESS; +} + +static int s_test_socket_impl_types_creation(struct aws_allocator *allocator, void *ctx) { + int posix_expected_result = AWS_ERROR_PLATFORM_NOT_SUPPORTED; + int winsock_expected_result = AWS_ERROR_PLATFORM_NOT_SUPPORTED; +#if defined(AWS_ENABLE_KQUEUE) || defined(AWS_ENABLE_EPOLL) + posix_expected_result = AWS_OP_SUCCESS; +#endif +#ifdef AWS_ENABLE_IO_COMPLETION_PORTS + winsock_expected_result = AWS_OP_SUCCESS; +#endif + // TODO: Apple Network Framework is not implemented yet. Add the related socket test later. + + return s_test_socket_creation(allocator, AWS_SOCKET_IMPL_POSIX, posix_expected_result) || + s_test_socket_creation(allocator, AWS_SOCKET_IMPL_WINSOCK, winsock_expected_result); +} + +AWS_TEST_CASE(test_socket_impl_types_creation, s_test_socket_impl_types_creation) + static int s_test_socket( struct aws_allocator *allocator, struct aws_socket_options *options, From 48ad48c2b02d069497b72b1ec07a6e3942c804b4 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 21 Nov 2024 16:05:56 -0800 Subject: [PATCH 50/61] move to private socket header --- include/aws/io/private/socket_impl.h | 72 ++++++++++++++++++++++++++++ include/aws/io/socket.h | 59 ----------------------- source/posix/socket.c | 1 + source/socket.c | 1 + 4 files changed, 74 insertions(+), 59 deletions(-) create mode 100644 include/aws/io/private/socket_impl.h diff --git a/include/aws/io/private/socket_impl.h b/include/aws/io/private/socket_impl.h new file mode 100644 index 000000000..2cfcf7ff1 --- /dev/null +++ b/include/aws/io/private/socket_impl.h @@ -0,0 +1,72 @@ +#ifndef AWS_IO_SOCKET_IMPL_H +#define AWS_IO_SOCKET_IMPL_H + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include + +/* These are hacks for working around headers and functions we need for IO work but aren't directly includable or + linkable. these are purposely not exported. These functions only get called internally. The awkward aws_ prefixes are + just in case someone includes this header somewhere they were able to get these definitions included. */ +#ifdef _WIN32 +typedef void (*aws_ms_fn_ptr)(void); + +void aws_check_and_init_winsock(void); +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); + +struct aws_socket_vtable { + 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); +}; + +#endif // AWS_IO_SOCKET_IMPL_H diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index eddc259ab..3d3621fd7 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -140,40 +140,6 @@ struct aws_socket_endpoint { struct aws_socket; -struct aws_socket_vtable { - 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); -}; - struct aws_socket { struct aws_socket_vtable *vtable; struct aws_allocator *allocator; @@ -195,31 +161,6 @@ struct aws_socket { struct aws_byte_buf; struct aws_byte_cursor; -/* These are hacks for working around headers and functions we need for IO work but aren't directly includable or - linkable. these are purposely not exported. These functions only get called internally. The awkward aws_ prefixes are - just in case someone includes this header somewhere they were able to get these definitions included. */ -#ifdef _WIN32 -typedef void (*aws_ms_fn_ptr)(void); - -void aws_check_and_init_winsock(void); -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/posix/socket.c b/source/posix/socket.c index 91f54f0d3..266ad2de2 100644 --- a/source/posix/socket.c +++ b/source/posix/socket.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/source/socket.c b/source/socket.c index dfe89b0b5..93c807979 100644 --- a/source/socket.c +++ b/source/socket.c @@ -7,6 +7,7 @@ #include #include #include +#include void aws_socket_clean_up(struct aws_socket *socket) { AWS_PRECONDITION(socket->vtable && socket->vtable->socket_cleanup_fn); From 17b79a47daff8775ca9aa310b0f279d08e8de1a7 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 21 Nov 2024 16:11:35 -0800 Subject: [PATCH 51/61] move function definition --- source/event_loop.c | 91 +++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/source/event_loop.c b/source/event_loop.c index ad1e47f1d..ddfe90ca6 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -31,6 +31,47 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a return aws_event_loop_new(alloc, &options); } + + +#ifndef AWS_ENABLE_IO_COMPLETION_PORTS +struct aws_event_loop *aws_event_loop_new_with_iocp( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + (void)alloc; + (void)options; + + 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 + +#ifndef AWS_ENABLE_KQUEUE +struct aws_event_loop *aws_event_loop_new_with_kqueue( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + (void)alloc; + (void)options; + + 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 + +#ifndef AWS_ENABLE_EPOLL +struct aws_event_loop *aws_event_loop_new_with_epoll( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options) { + (void)alloc; + (void)options; + + AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Epoll is not supported on the platform"); + return NULL; +} +#endif // AWS_ENABLE_KQUEUE + + /** * 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. @@ -46,19 +87,17 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { */ #ifdef AWS_ENABLE_KQUEUE return AWS_EVENT_LOOP_KQUEUE; -#endif -#ifdef AWS_ENABLE_DISPATCH_QUEUE +#elif defined(AWS_ENABLE_DISPATCH_QUEUE) return AWS_EVENT_LOOP_DISPATCH_QUEUE; -#endif -#ifdef AWS_ENABLE_EPOLL +#elif defined(AWS_ENABLE_EPOLL) return AWS_EVENT_LOOP_EPOLL; -#endif -#ifdef AWS_OS_WINDOWS +#elif defined(AWS_OS_WINDOWS) return AWS_EVENT_LOOP_IOCP; -#endif +#else AWS_LOGF_ERROR( AWS_LS_IO_EVENT_LOOP, "Failed to get default event loop type. The library is not built correctly on the platform."); +#endif } static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type); @@ -660,41 +699,3 @@ struct aws_event_loop *aws_event_loop_new_with_dispatch_queue( aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); return NULL; } - -#ifndef AWS_ENABLE_IO_COMPLETION_PORTS -struct aws_event_loop *aws_event_loop_new_with_iocp( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options) { - (void)alloc; - (void)options; - - 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 - -#ifndef AWS_ENABLE_KQUEUE -struct aws_event_loop *aws_event_loop_new_with_kqueue( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options) { - (void)alloc; - (void)options; - - 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 - -#ifndef AWS_ENABLE_EPOLL -struct aws_event_loop *aws_event_loop_new_with_epoll( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options) { - (void)alloc; - (void)options; - - AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Epoll is not supported on the platform"); - return NULL; -} -#endif // AWS_ENABLE_KQUEUE From a32ee15ae152683c3efc7155dde696af2d96cfd6 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Thu, 21 Nov 2024 16:22:48 -0800 Subject: [PATCH 52/61] include private header & rename function --- include/aws/io/socket.h | 1 - source/event_loop.c | 3 --- source/linux/epoll_event_loop.c | 2 +- source/socket.c | 2 +- source/windows/iocp/socket.c | 1 + 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index 3d3621fd7..149d613a0 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -161,7 +161,6 @@ struct aws_socket { struct aws_byte_buf; struct aws_byte_cursor; - AWS_EXTERN_C_BEGIN /** diff --git a/source/event_loop.c b/source/event_loop.c index ddfe90ca6..946fcd9a8 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -31,8 +31,6 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a return aws_event_loop_new(alloc, &options); } - - #ifndef AWS_ENABLE_IO_COMPLETION_PORTS struct aws_event_loop *aws_event_loop_new_with_iocp( struct aws_allocator *alloc, @@ -71,7 +69,6 @@ struct aws_event_loop *aws_event_loop_new_with_epoll( } #endif // AWS_ENABLE_KQUEUE - /** * 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. diff --git a/source/linux/epoll_event_loop.c b/source/linux/epoll_event_loop.c index b0f6d7334..147b0001b 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_epoll_with_options( +struct aws_event_loop *aws_event_loop_new_with_epoll( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { AWS_PRECONDITION(options); diff --git a/source/socket.c b/source/socket.c index 93c807979..4eda7d002 100644 --- a/source/socket.c +++ b/source/socket.c @@ -6,8 +6,8 @@ #include #include #include -#include #include +#include void aws_socket_clean_up(struct aws_socket *socket) { AWS_PRECONDITION(socket->vtable && socket->vtable->socket_cleanup_fn); diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index 48f512859..b2d8ad16a 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -14,6 +14,7 @@ below, clang-format doesn't work (at least on my version) with the c-style comme #include // clang-format on +#include #include #include From c53b4adead880d51099e6c8d363401e052d02805 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 22 Nov 2024 09:53:12 -0800 Subject: [PATCH 53/61] include private socket header --- source/windows/winsock_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/windows/winsock_init.c b/source/windows/winsock_init.c index 669ae84b8..ba0b96aa3 100644 --- a/source/windows/winsock_init.c +++ b/source/windows/winsock_init.c @@ -15,6 +15,7 @@ below, clang-format doesn't work (at least on my version) with the c-style comme #include #include +#include #include From ad5152c76d2b9a35119b88c6db5b6ae843ed7e9c Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Fri, 22 Nov 2024 09:53:35 -0800 Subject: [PATCH 54/61] format --- source/windows/winsock_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/windows/winsock_init.c b/source/windows/winsock_init.c index ba0b96aa3..cba580e56 100644 --- a/source/windows/winsock_init.c +++ b/source/windows/winsock_init.c @@ -14,8 +14,8 @@ below, clang-format doesn't work (at least on my version) with the c-style comme // clang-format on #include -#include #include +#include #include From 1afb85949f2ec09cb7a47cdf13e7ca6051a196d0 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 25 Nov 2024 10:02:46 -0800 Subject: [PATCH 55/61] move windows related header to private --- source/windows/host_resolver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/windows/host_resolver.c b/source/windows/host_resolver.c index 59fbb858d..7bc10580e 100644 --- a/source/windows/host_resolver.c +++ b/source/windows/host_resolver.c @@ -10,6 +10,7 @@ #include #include #include +#include #include int aws_default_dns_resolve( From 182757fa941beb9f0a75dbb3e1bb6b67cf90734e Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 25 Nov 2024 10:20:49 -0800 Subject: [PATCH 56/61] fix unreferenced param --- tests/socket_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/socket_test.c b/tests/socket_test.c index 4d35efa55..f96b20e4f 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -413,6 +413,7 @@ static int s_test_socket_creation(struct aws_allocator *alloc, enum aws_socket_i } static int s_test_socket_impl_types_creation(struct aws_allocator *allocator, void *ctx) { + (void)ctx; int posix_expected_result = AWS_ERROR_PLATFORM_NOT_SUPPORTED; int winsock_expected_result = AWS_ERROR_PLATFORM_NOT_SUPPORTED; #if defined(AWS_ENABLE_KQUEUE) || defined(AWS_ENABLE_EPOLL) From 02afc29b00e66d4c83110ae69bec504d7503fc0a Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 25 Nov 2024 10:27:53 -0800 Subject: [PATCH 57/61] rename windows creation --- source/windows/iocp/iocp_event_loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/windows/iocp/iocp_event_loop.c b/source/windows/iocp/iocp_event_loop.c index 584ba0b1c..ff390670f 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_with_iocp_with_options( +struct aws_event_loop *aws_event_loop_new_with_iocp( struct aws_allocator *alloc, const struct aws_event_loop_options *options) { AWS_ASSERT(alloc); From 6610f79ef4189ac2098343dc0f1a2a90ba1e969e Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 25 Nov 2024 10:29:38 -0800 Subject: [PATCH 58/61] format --- include/aws/io/socket.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index 149d613a0..3506f7f1b 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -37,9 +37,9 @@ enum aws_socket_type { * * PLATFORM DEFAULT SOCKET IMPLEMENTATION TYPE * Linux | AWS_SOCKET_IMPL_POSIX - * Windows | AWS_SOCKET_IMPL_WINSOCK + * Windows | AWS_SOCKET_IMPL_WINSOCK * BSD Variants| AWS_SOCKET_IMPL_POSIX - * MacOS | AWS_SOCKET_IMPL_POSIX + * MacOS | AWS_SOCKET_IMPL_POSIX * iOS | AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK */ enum aws_socket_impl_type { From 53fc1fc2ed9f020438e611381c5d0715e5110a24 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 25 Nov 2024 10:36:08 -0800 Subject: [PATCH 59/61] add event loop creation test for windows --- tests/event_loop_test.c | 106 ++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index d8521d565..3cc319f96 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -862,59 +862,6 @@ static int s_state_wait_1sec(struct thread_tester *tester) { } } -/* Verify default event loop type */ -static int s_test_event_loop_creation( - struct aws_allocator *allocator, - enum aws_event_loop_type type, - bool expect_success) { - struct aws_event_loop_options event_loop_options = { - .thread_options = NULL, - .clock = aws_high_res_clock_get_ticks, - .type = type, - }; - - struct aws_event_loop *event_loop = aws_event_loop_new(allocator, &event_loop_options); - - if (expect_success) { - ASSERT_NOT_NULL(event_loop); - /* Clean up tester*/ - aws_event_loop_destroy(event_loop); - } else { - ASSERT_NULL(event_loop); - } - - return AWS_OP_SUCCESS; -} - -/* Verify default event loop type */ -static int s_test_event_loop_all_types_creation(struct aws_allocator *allocator, void *ctx) { - (void)ctx; - bool enable_kqueue = false; - bool enable_epoll = false; - bool enable_iocp = false; - bool enable_dispatch_queue = false; -# ifdef AWS_ENABLE_KQUEUE - enable_kqueue = true; -# endif -# ifdef AWS_ENABLE_EPOLL - enable_epoll = true; -# endif -# ifdef AWS_ENABLE_IO_COMPLETION_PORTS - enable_iocp = true; -# endif -# ifdef AWS_ENABLE_DISPATCH_QUEUE -// TODO: Dispatch queue support is not yet implemented. Uncomment the following line once the dispatch queue is ready. -// enable_dispatch_queue = true; -# endif - - return s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_EPOLL, enable_epoll) || - s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_IOCP, enable_iocp) || - s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_KQUEUE, enable_kqueue) || - s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_DISPATCH_QUEUE, enable_dispatch_queue); -} - -AWS_TEST_CASE(event_loop_all_types_creation, s_test_event_loop_all_types_creation) - /* Test that subscribe/unubscribe work at all */ static int s_test_event_loop_subscribe_unsubscribe(struct aws_allocator *allocator, void *ctx) { (void)ctx; @@ -1026,6 +973,59 @@ AWS_TEST_CASE(event_loop_readable_event_on_2nd_time_readable, s_test_event_loop_ #endif /* AWS_ENABLE_IO_COMPLETION_PORTS */ +/* Verify default event loop type */ +static int s_test_event_loop_creation( + struct aws_allocator *allocator, + enum aws_event_loop_type type, + bool expect_success) { + struct aws_event_loop_options event_loop_options = { + .thread_options = NULL, + .clock = aws_high_res_clock_get_ticks, + .type = type, + }; + + struct aws_event_loop *event_loop = aws_event_loop_new(allocator, &event_loop_options); + + if (expect_success) { + ASSERT_NOT_NULL(event_loop); + /* Clean up tester*/ + aws_event_loop_destroy(event_loop); + } else { + ASSERT_NULL(event_loop); + } + + return AWS_OP_SUCCESS; +} + +/* Verify default event loop type */ +static int s_test_event_loop_all_types_creation(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + bool enable_kqueue = false; + bool enable_epoll = false; + bool enable_iocp = false; + bool enable_dispatch_queue = false; +#ifdef AWS_ENABLE_KQUEUE + enable_kqueue = true; +#endif +#ifdef AWS_ENABLE_EPOLL + enable_epoll = true; +#endif +#ifdef AWS_ENABLE_IO_COMPLETION_PORTS + enable_iocp = true; +#endif +#ifdef AWS_ENABLE_DISPATCH_QUEUE +// TODO: Dispatch queue support is not yet implemented. Uncomment the following line once the dispatch queue is ready. +// enable_dispatch_queue = true; +#endif + + return s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_EPOLL, enable_epoll) || + s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_IOCP, enable_iocp) || + s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_KQUEUE, enable_kqueue) || + s_test_event_loop_creation(allocator, AWS_EVENT_LOOP_DISPATCH_QUEUE, enable_dispatch_queue); +} + +AWS_TEST_CASE(event_loop_all_types_creation, s_test_event_loop_all_types_creation) + static int s_event_loop_test_stop_then_restart(struct aws_allocator *allocator, void *ctx) { (void)ctx; struct aws_event_loop *event_loop = aws_event_loop_new_default(allocator, aws_high_res_clock_get_ticks); From 31a9a95b06d6403d6890bbeca67214dc570aaa11 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Wed, 4 Dec 2024 12:50:46 -0800 Subject: [PATCH 60/61] update cr --- include/aws/io/socket.h | 3 --- source/event_loop.c | 10 +++++----- source/socket.c | 19 +++++++++---------- source/windows/iocp/socket.c | 4 ++-- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index 3506f7f1b..d4e38afb8 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -6,7 +6,6 @@ */ #include -#include #include AWS_PUSH_SANE_WARNING_LEVEL @@ -138,8 +137,6 @@ struct aws_socket_endpoint { uint32_t port; }; -struct aws_socket; - struct aws_socket { struct aws_socket_vtable *vtable; struct aws_allocator *allocator; diff --git a/source/event_loop.c b/source/event_loop.c index 946fcd9a8..d10c5fe78 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -656,30 +656,30 @@ static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) switch (type) { 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."); + AWS_LOGF_ERROR(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_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."); + AWS_LOGF_ERROR(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_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."); + AWS_LOGF_ERROR(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_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."); + AWS_LOGF_ERROR(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); #endif // AWS_ENABLE_DISPATCH_QUEUE break; default: - AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type."); + AWS_LOGF_ERROR(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type."); return aws_raise_error(AWS_ERROR_UNSUPPORTED_OPERATION); break; } diff --git a/source/socket.c b/source/socket.c index 4eda7d002..88e085677 100644 --- a/source/socket.c +++ b/source/socket.c @@ -110,26 +110,25 @@ bool aws_socket_is_open(struct aws_socket *socket) { * 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_SOCKET_IMPL_PLATFORM_DEFAULT; // override default socket #ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK - type = AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; -#endif // AWS_USE_APPLE_NETWORK_FRAMEWORK - if (type != AWS_SOCKET_IMPL_PLATFORM_DEFAULT) { - return type; - } + return AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; +#else // ! AWS_USE_APPLE_NETWORK_FRAMEWORK /** * 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) +# if defined(AWS_ENABLE_KQUEUE) || defined(AWS_ENABLE_EPOLL) return AWS_SOCKET_IMPL_POSIX; -#elif AWS_ENABLE_DISPATCH_QUEUE +# elif defined(AWS_ENABLE_DISPATCH_QUEUE) return AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; -#elif AWS_ENABLE_IO_COMPLETION_PORTS +# elif defined(AWS_ENABLE_IO_COMPLETION_PORTS) return AWS_SOCKET_IMPL_WINSOCK; -#else +# else + AWS_FATAL_ASSERT( + true && "Invalid default socket impl type. Please check make sure the library is compiled the correct "); return AWS_SOCKET_IMPL_PLATFORM_DEFAULT; +# endif #endif } diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index b2d8ad16a..d672719c8 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -398,8 +398,8 @@ static int s_socket_init( struct aws_allocator *alloc, const struct aws_socket_options *options, bool create_underlying_socket) { - AWS_ASSERT(options->domain <= AWS_SOCKET_LOCAL); - AWS_ASSERT(options->type <= AWS_SOCKET_DGRAM); + AWS_FATAL_ASSERT(options->domain <= AWS_SOCKET_LOCAL); + AWS_FATAL_ASSERT(options->type <= AWS_SOCKET_DGRAM); AWS_ZERO_STRUCT(*socket); struct iocp_socket *impl = aws_mem_calloc(alloc, 1, sizeof(struct iocp_socket)); From e1d75132857c934600303cb4470af69c530b2f50 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 9 Dec 2024 15:09:53 -0800 Subject: [PATCH 61/61] remove apple network framewokr CI so that we dont block merge --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb86c2004..71726b8a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -215,7 +215,7 @@ jobs: strategy: fail-fast: false matrix: - eventloop: ["-DAWS_USE_APPLE_NETWORK_FRAMEWORK=ON", "-DAWS_USE_APPLE_NETWORK_FRAMEWORK=OFF"] + eventloop: ["-DAWS_USE_APPLE_NETWORK_FRAMEWORK=OFF"] # TODO: Add "-DAWS_USE_APPLE_NETWORK_FRAMEWORK=ON" when apple network framework is implemented. steps: - uses: aws-actions/configure-aws-credentials@v4 with: @@ -245,7 +245,7 @@ jobs: strategy: fail-fast: false matrix: - eventloop: ["-DAWS_USE_APPLE_NETWORK_FRAMEWORK=ON", "-DAWS_USE_APPLE_NETWORK_FRAMEWORK=OFF"] + eventloop: ["-DAWS_USE_APPLE_NETWORK_FRAMEWORK=OFF"] # TODO: Add "-DAWS_USE_APPLE_NETWORK_FRAMEWORK=ON" when apple network framework is implemented. steps: - uses: aws-actions/configure-aws-credentials@v4 with: