From 9323cc38734f61cebf4695d7977116b696bd8823 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Thu, 7 Nov 2024 14:16:19 -0800 Subject: [PATCH 01/18] 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 02/18] 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 fcb3d9a87cfe72600272d7e708e07519a882c180 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 8 Nov 2024 08:34:44 -0800 Subject: [PATCH 03/18] 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 04/18] 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 d68acdb80838ee024538d7ebec9ba6ce0c81fa8e Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Mon, 11 Nov 2024 07:26:43 -0800 Subject: [PATCH 05/18] Doc comments --- include/aws/io/event_loop.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 093e632f5..f5815e583 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -192,9 +192,20 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou uint16_t cpu_group, const struct aws_shutdown_callback_options *shutdown_options); +/** + * Returns the opaque internal user data of an event loop. Can be cast into a specific implementation by + * privileged consumers. + * + * @internal - Don't use outside of testing. + */ AWS_IO_API void *aws_event_loop_get_impl(struct aws_event_loop *event_loop); +/** + * Initializes the base structure used by all event loop implementations with test-oriented overrides. + * + * @internal - Don't use outside of testing. + */ AWS_IO_API struct aws_event_loop *aws_event_loop_new_base( struct aws_allocator *allocator, @@ -205,6 +216,8 @@ struct aws_event_loop *aws_event_loop_new_base( /** * Common cleanup code for all implementations. * This is only called from the *destroy() function of event loop implementations. + * + * @internal - Don't use outside of testing. */ AWS_IO_API void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); @@ -215,6 +228,8 @@ void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); * If you do not want this function to block, call aws_event_loop_stop() manually first. * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads * must ensure their API calls to the event loop happen-before the call to destroy. + * + * @internal - Don't use outside of testing. */ AWS_IO_API void aws_event_loop_destroy(struct aws_event_loop *event_loop); From b28743ce88b2d0906685c44474d5cab682ac8369 Mon Sep 17 00:00:00 2001 From: subdiox Date: Tue, 12 Nov 2024 01:51:50 +0900 Subject: [PATCH 06/18] Add cxx support (#689) --- include/aws/testing/io_testing_channel.h | 50 +++++++++++++----------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/include/aws/testing/io_testing_channel.h b/include/aws/testing/io_testing_channel.h index d2f1c13a5..192a269b0 100644 --- a/include/aws/testing/io_testing_channel.h +++ b/include/aws/testing/io_testing_channel.h @@ -33,7 +33,7 @@ static int s_testing_loop_wait_for_stop_completion(struct aws_event_loop *event_ } static void s_testing_loop_schedule_task_now(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; aws_task_scheduler_schedule_now(&testing_loop->scheduler, task); } @@ -42,22 +42,22 @@ static void s_testing_loop_schedule_task_future( struct aws_task *task, uint64_t run_at_nanos) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; aws_task_scheduler_schedule_future(&testing_loop->scheduler, task, run_at_nanos); } static void s_testing_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; aws_task_scheduler_cancel_task(&testing_loop->scheduler, task); } static bool s_testing_loop_is_on_callers_thread(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; return testing_loop->mock_on_callers_thread; } static void s_testing_loop_destroy(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; aws_task_scheduler_clean_up(&testing_loop->scheduler); aws_mem_release(event_loop->alloc, testing_loop); aws_event_loop_clean_up_base(event_loop); @@ -76,10 +76,12 @@ static struct aws_event_loop_vtable s_testing_loop_vtable = { }; static struct aws_event_loop *s_testing_loop_new(struct aws_allocator *allocator, aws_io_clock_fn clock) { - struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); + struct aws_event_loop *event_loop = + (struct aws_event_loop *)aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); aws_event_loop_init_base(event_loop, allocator, clock); - struct testing_loop *testing_loop = aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); + struct testing_loop *testing_loop = + (struct testing_loop *)aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); aws_task_scheduler_init(&testing_loop->scheduler, allocator); testing_loop->mock_on_callers_thread = true; event_loop->impl_data = testing_loop; @@ -113,7 +115,7 @@ static int s_testing_channel_handler_process_read_message( (void)slot; (void)message; - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; aws_linked_list_push_back(&testing_handler->messages, &message->queueing_handle); return AWS_OP_SUCCESS; } @@ -124,7 +126,7 @@ static int s_testing_channel_handler_process_write_message( struct aws_io_message *message) { (void)slot; - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; aws_linked_list_push_back(&testing_handler->messages, &message->queueing_handle); /* Invoke completion callback if this is the left-most handler */ @@ -142,7 +144,7 @@ static int s_testing_channel_handler_increment_read_window( size_t size) { (void)slot; - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; testing_handler->latest_window_update = size; return AWS_OP_SUCCESS; } @@ -154,7 +156,7 @@ static int s_testing_channel_handler_shutdown( int error_code, bool free_scarce_resources_immediately) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; /* If user has registered a callback, invoke it */ if (testing_handler->on_shutdown) { @@ -183,7 +185,7 @@ static int s_testing_channel_handler_shutdown( } static size_t s_testing_channel_handler_initial_window_size(struct aws_channel_handler *handler) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; return testing_handler->initial_window; } @@ -193,7 +195,7 @@ static size_t s_testing_channel_handler_message_overhead(struct aws_channel_hand } static void s_testing_channel_handler_destroy(struct aws_channel_handler *handler) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; while (!aws_linked_list_empty(&testing_handler->messages)) { struct aws_linked_list_node *node = aws_linked_list_pop_front(&testing_handler->messages); @@ -206,7 +208,7 @@ static void s_testing_channel_handler_destroy(struct aws_channel_handler *handle } static void s_testing_channel_handler_reset_statistics(struct aws_channel_handler *handler) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; aws_crt_statistics_socket_reset(&testing_handler->stats); } @@ -214,7 +216,7 @@ static void s_testing_channel_handler_reset_statistics(struct aws_channel_handle static void s_testing_channel_handler_gather_statistics( struct aws_channel_handler *handler, struct aws_array_list *stats) { - struct testing_channel_handler *testing_handler = handler->impl; + struct testing_channel_handler *testing_handler = (struct testing_channel_handler *)handler->impl; void *stats_base = &testing_handler->stats; aws_array_list_push_back(stats, &stats_base); @@ -235,9 +237,10 @@ static struct aws_channel_handler_vtable s_testing_channel_handler_vtable = { static struct aws_channel_handler *s_new_testing_channel_handler( struct aws_allocator *allocator, size_t initial_window) { - struct aws_channel_handler *handler = aws_mem_calloc(allocator, 1, sizeof(struct aws_channel_handler)); + struct aws_channel_handler *handler = + (struct aws_channel_handler *)aws_mem_calloc(allocator, 1, sizeof(struct aws_channel_handler)); struct testing_channel_handler *testing_handler = - aws_mem_calloc(allocator, 1, sizeof(struct testing_channel_handler)); + (struct testing_channel_handler *)aws_mem_calloc(allocator, 1, sizeof(struct testing_channel_handler)); aws_linked_list_init(&testing_handler->messages); testing_handler->initial_window = initial_window; testing_handler->latest_window_update = 0; @@ -270,14 +273,14 @@ struct testing_channel { static void s_testing_channel_on_setup_completed(struct aws_channel *channel, int error_code, void *user_data) { (void)channel; (void)error_code; - struct testing_channel *testing = user_data; + struct testing_channel *testing = (struct testing_channel *)user_data; testing->channel_setup_completed = true; } static void s_testing_channel_on_shutdown_completed(struct aws_channel *channel, int error_code, void *user_data) { (void)channel; (void)error_code; - struct testing_channel *testing = user_data; + struct testing_channel *testing = (struct testing_channel *)user_data; testing->channel_shutdown_completed = true; testing->channel_shutdown_error_code = error_code; @@ -393,7 +396,7 @@ static inline int testing_channel_init( AWS_ZERO_STRUCT(*testing); testing->loop = s_testing_loop_new(allocator, options->clock_fn); - testing->loop_impl = testing->loop->impl_data; + testing->loop_impl = (struct testing_loop *)testing->loop->impl_data; struct aws_channel_options args = { .on_setup_completed = s_testing_channel_on_setup_completed, @@ -411,8 +414,9 @@ static inline int testing_channel_init( ASSERT_TRUE(testing->channel_setup_completed); testing->left_handler_slot = aws_channel_slot_new(testing->channel); - struct aws_channel_handler *handler = s_new_testing_channel_handler(allocator, 16 * 1024); - testing->left_handler_impl = handler->impl; + struct aws_channel_handler *handler = + (struct aws_channel_handler *)s_new_testing_channel_handler(allocator, 16 * 1024); + testing->left_handler_impl = (struct testing_channel_handler *)handler->impl; ASSERT_SUCCESS(aws_channel_slot_set_handler(testing->left_handler_slot, handler)); return AWS_OP_SUCCESS; @@ -445,7 +449,7 @@ static inline int testing_channel_install_downstream_handler(struct testing_chan struct aws_channel_handler *handler = s_new_testing_channel_handler(testing->left_handler_slot->alloc, initial_window); ASSERT_NOT_NULL(handler); - testing->right_handler_impl = handler->impl; + testing->right_handler_impl = (struct testing_channel_handler *)handler->impl; ASSERT_SUCCESS(aws_channel_slot_set_handler(testing->right_handler_slot, handler)); return AWS_OP_SUCCESS; From 39991969a2a5b9f7657e37aa8e7477f993b73541 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Mon, 11 Nov 2024 13:14:41 -0800 Subject: [PATCH 07/18] 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 08/18] 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 09/18] update cr changes --- CMakeLists.txt | 1 - include/aws/io/event_loop.h | 9 +++++++++ include/aws/io/private/event_loop_impl.h | 4 ---- include/aws/io/socket.h | 9 +++++---- source/event_loop.c | 12 ++++++++---- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5589f394d..1a128c7e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,6 @@ elseif (APPLE) message(FATAL_ERROR "Network framework not found") endif () - #No choice on TLS for apple, darwinssl will always be used. list(APPEND PLATFORM_LIBS "-framework Security -framework Network") list(APPEND EVENT_LOOP_DEFINES "DISPATCH_QUEUE") diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 09da591c0..f44c431a2 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -12,6 +12,7 @@ AWS_PUSH_SANE_WARNING_LEVEL struct aws_event_loop; struct aws_event_loop_group; +struct aws_event_loop_options; struct aws_shutdown_callback_options; struct aws_task; @@ -246,6 +247,14 @@ struct aws_event_loop *aws_event_loop_new_base( AWS_IO_API void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); +/** + * Creates an instance of the event loop implementation from the options. + */ +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); + /** * Invokes the destroy() fn for the event loop implementation. * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 365d51f80..2e1992eed 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -98,19 +98,15 @@ struct aws_event_loop_options { enum aws_event_loop_type type; }; -AWS_IO_API struct aws_event_loop *aws_event_loop_new_iocp_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -AWS_IO_API struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -AWS_IO_API struct aws_event_loop *aws_event_loop_new_kqueue_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); -AWS_IO_API struct aws_event_loop *aws_event_loop_new_epoll_with_options( struct aws_allocator *alloc, const struct aws_event_loop_options *options); diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index ab295b576..8ce623d84 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -116,7 +116,8 @@ typedef void(aws_socket_on_accept_result_fn)( * Callback for when the data passed to a call to aws_socket_write() has either completed or failed. * On success, error_code will be AWS_ERROR_SUCCESS. * - * socket is possible to be a NULL pointer in the callback. + * `socket` may be NULL in the callback if the socket is released and cleaned up before a callback is triggered. + * by the system I/O handler, */ typedef void( aws_socket_on_write_completed_fn)(struct aws_socket *socket, int error_code, size_t bytes_written, void *user_data); @@ -206,19 +207,19 @@ aws_ms_fn_ptr aws_winsock_get_acceptex_fn(void); #endif -AWS_IO_API int aws_socket_init_posix( +int aws_socket_init_posix( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options); -AWS_IO_API int aws_socket_init_winsock( +int aws_socket_init_winsock( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options); -AWS_IO_API int aws_socket_init_apple_nw_socket( +int aws_socket_init_apple_nw_socket( struct aws_socket *socket, struct aws_allocator *alloc, const struct aws_socket_options *options); diff --git a/source/event_loop.c b/source/event_loop.c index 867eb7591..e1d728f2d 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -14,7 +14,11 @@ #include #include -static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; +#ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK + static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_DISPATCH_QUEUE; +#else + static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; +#endif struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock) { struct aws_event_loop_options options = { @@ -559,9 +563,6 @@ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_ * If `aws_event_loop_override_default_type` has been called, return the override default type. */ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { -#ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK - aws_event_loop_override_default_type(AWS_ELT_DISPATCH_QUEUE); -#endif // AWS_USE_APPLE_NETWORK_FRAMEWORK if (s_default_event_loop_type_override != AWS_ELT_PLATFORM_DEFAULT) { return s_default_event_loop_type_override; } @@ -625,6 +626,7 @@ struct aws_event_loop *aws_event_loop_new_dispatch_queue_with_options( AWS_ASSERT(0); AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Dispatch Queue is not supported on the platform"); + aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); return NULL; } @@ -637,6 +639,7 @@ struct aws_event_loop *aws_event_loop_new_iocp_with_options( AWS_ASSERT(0); AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "IOCP is not supported on the platform"); + aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); return NULL; } #endif // AWS_ENABLE_IO_COMPLETION_PORTS @@ -650,6 +653,7 @@ struct aws_event_loop *aws_event_loop_new_kqueue_with_options( AWS_ASSERT(0); AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Kqueue is not supported on the platform"); + aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); return NULL; } #endif // AWS_ENABLE_EPOLL From b6bff6f557ecf8b92131471d5668e7b90a196fab Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 12 Nov 2024 09:45:08 -0800 Subject: [PATCH 10/18] Event loop public api (#691) Co-authored-by: Bret Ambrose --- include/aws/io/event_loop.h | 411 ++++---------------- include/aws/io/private/event_loop_impl.h | 299 ++++++++++++++ include/aws/testing/io_testing_channel.h | 29 +- source/bsd/kqueue_event_loop.c | 4 +- source/channel.c | 1 + source/event_loop.c | 164 ++++---- source/exponential_backoff_retry_strategy.c | 5 +- source/linux/epoll_event_loop.c | 7 +- source/posix/pipe.c | 1 + source/posix/socket.c | 1 + source/s2n/s2n_tls_channel_handler.c | 11 +- source/windows/iocp/iocp_event_loop.c | 1 + source/windows/iocp/pipe.c | 1 + source/windows/iocp/socket.c | 1 + tests/alpn_handler_test.c | 1 + tests/byo_crypto_test.c | 6 +- tests/channel_test.c | 6 +- tests/default_host_resolver_test.c | 60 ++- tests/event_loop_test.c | 31 +- tests/exponential_backoff_retry_test.c | 25 +- tests/future_test.c | 1 + tests/pipe_test.c | 1 + tests/pkcs11_test.c | 6 +- tests/socket_handler_test.c | 15 +- tests/socket_test.c | 16 +- tests/standard_retry_test.c | 8 +- tests/tls_handler_test.c | 19 +- 27 files changed, 655 insertions(+), 476 deletions(-) create mode 100644 include/aws/io/private/event_loop_impl.h diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 58041a4c7..098e9428e 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -6,80 +6,27 @@ * SPDX-License-Identifier: Apache-2.0. */ -#include -#include -#include - #include AWS_PUSH_SANE_WARNING_LEVEL -enum aws_io_event_type { - AWS_IO_EVENT_TYPE_READABLE = 1, - AWS_IO_EVENT_TYPE_WRITABLE = 2, - AWS_IO_EVENT_TYPE_REMOTE_HANG_UP = 4, - AWS_IO_EVENT_TYPE_CLOSED = 8, - AWS_IO_EVENT_TYPE_ERROR = 16, -}; - struct aws_event_loop; +struct aws_event_loop_group; +struct aws_shutdown_callback_options; struct aws_task; -struct aws_thread_options; - -#if AWS_USE_IO_COMPLETION_PORTS - -struct aws_overlapped; - -typedef void(aws_event_loop_on_completion_fn)( - struct aws_event_loop *event_loop, - struct aws_overlapped *overlapped, - int status_code, - size_t num_bytes_transferred); - -/** - * The aws_win32_OVERLAPPED struct is layout-compatible with OVERLAPPED as defined in . It is used - * here to avoid pulling in a dependency on which would also bring along a lot of bad macros, such - * as redefinitions of GetMessage and GetObject. Note that the OVERLAPPED struct layout in the Windows SDK can - * never be altered without breaking binary compatibility for every existing third-party executable, so there - * is no need to worry about keeping this definition in sync. - */ -struct aws_win32_OVERLAPPED { - uintptr_t Internal; - uintptr_t InternalHigh; - union { - struct { - uint32_t Offset; - uint32_t OffsetHigh; - } s; - void *Pointer; - } u; - void *hEvent; -}; /** - * Use aws_overlapped when a handle connected to the event loop needs an OVERLAPPED struct. - * OVERLAPPED structs are needed to make OS-level async I/O calls. - * When the I/O completes, the assigned aws_event_loop_on_completion_fn is called from the event_loop's thread. - * While the I/O is pending, it is not safe to modify or delete aws_overlapped. - * Call aws_overlapped_init() before first use. If the aws_overlapped will be used multiple times, call - * aws_overlapped_reset() or aws_overlapped_init() between uses. + * @internal */ -struct aws_overlapped { - struct aws_win32_OVERLAPPED overlapped; - aws_event_loop_on_completion_fn *on_completion; - void *user_data; -}; - -#else /* !AWS_USE_IO_COMPLETION_PORTS */ - typedef void(aws_event_loop_on_event_fn)( struct aws_event_loop *event_loop, struct aws_io_handle *handle, int events, void *user_data); -#endif /* AWS_USE_IO_COMPLETION_PORTS */ - +/** + * @internal + */ struct aws_event_loop_vtable { void (*destroy)(struct aws_event_loop *event_loop); int (*run)(struct aws_event_loop *event_loop); @@ -88,203 +35,49 @@ struct aws_event_loop_vtable { void (*schedule_task_now)(struct aws_event_loop *event_loop, struct aws_task *task); void (*schedule_task_future)(struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); void (*cancel_task)(struct aws_event_loop *event_loop, struct aws_task *task); -#if AWS_USE_IO_COMPLETION_PORTS int (*connect_to_io_completion_port)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); -#else int (*subscribe_to_io_events)( struct aws_event_loop *event_loop, struct aws_io_handle *handle, int events, aws_event_loop_on_event_fn *on_event, void *user_data); -#endif int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle); void (*free_io_event_resources)(void *user_data); bool (*is_on_callers_thread)(struct aws_event_loop *event_loop); }; -struct aws_event_loop { - struct aws_event_loop_vtable *vtable; - struct aws_allocator *alloc; - aws_io_clock_fn *clock; - struct aws_hash_table local_data; - struct aws_atomic_var current_load_factor; - uint64_t latest_tick_start; - size_t current_tick_latency_sum; - struct aws_atomic_var next_flush_time; - void *impl_data; -}; - -struct aws_event_loop_local_object; -typedef void(aws_event_loop_on_local_object_removed_fn)(struct aws_event_loop_local_object *); - -struct aws_event_loop_local_object { - const void *key; - void *object; - aws_event_loop_on_local_object_removed_fn *on_object_removed; -}; - -struct aws_event_loop_options { - aws_io_clock_fn *clock; - struct aws_thread_options *thread_options; -}; - -typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, - const struct aws_event_loop_options *options, - void *new_loop_user_data); - -struct aws_event_loop_group { - struct aws_allocator *allocator; - struct aws_array_list event_loops; - struct aws_ref_count ref_count; - struct aws_shutdown_callback_options shutdown_options; -}; - -AWS_EXTERN_C_BEGIN - -#ifdef AWS_USE_IO_COMPLETION_PORTS -/** - * Prepares aws_overlapped for use, and sets a function to call when the overlapped operation completes. - */ -AWS_IO_API -void aws_overlapped_init( - struct aws_overlapped *overlapped, - aws_event_loop_on_completion_fn *on_completion, - void *user_data); - /** - * Prepares aws_overlapped for re-use without changing the assigned aws_event_loop_on_completion_fn. - * Call aws_overlapped_init(), instead of aws_overlapped_reset(), to change the aws_event_loop_on_completion_fn. + * Event loop group configuration options */ -AWS_IO_API -void aws_overlapped_reset(struct aws_overlapped *overlapped); +struct aws_event_loop_group_options { -/** - * Casts an aws_overlapped pointer for use as a LPOVERLAPPED parameter to Windows API functions - */ -AWS_IO_API -struct _OVERLAPPED *aws_overlapped_to_windows_overlapped(struct aws_overlapped *overlapped); -#endif /* AWS_USE_IO_COMPLETION_PORTS */ + /** + * How many event loops that event loop group should contain. For most group types, this implies + * the creation and management of an analagous amount of managed threads + */ + uint16_t loop_count; -/** - * Creates an instance of the default event loop implementation for the current architecture and operating system. - */ -AWS_IO_API -struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock); + /** + * Optional callback to invoke when the event loop group finishes destruction. + */ + const struct aws_shutdown_callback_options *shutdown_options; -/** - * Creates an instance of the default event loop implementation for the current architecture and operating system using - * extendable options. - */ -AWS_IO_API -struct aws_event_loop *aws_event_loop_new_default_with_options( - struct aws_allocator *alloc, - const struct aws_event_loop_options *options); - -/** - * Invokes the destroy() fn for the event loop implementation. - * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. - * If you do not want this function to block, call aws_event_loop_stop() manually first. - * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads - * must ensure their API calls to the event loop happen-before the call to destroy. - */ -AWS_IO_API -void aws_event_loop_destroy(struct aws_event_loop *event_loop); - -/** - * Initializes common event-loop data structures. - * This is only called from the *new() function of event loop implementations. - */ -AWS_IO_API -int aws_event_loop_init_base(struct aws_event_loop *event_loop, struct aws_allocator *alloc, aws_io_clock_fn *clock); - -/** - * Common cleanup code for all implementations. - * This is only called from the *destroy() function of event loop implementations. - */ -AWS_IO_API -void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); - -/** - * Fetches an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to - * by key. This function is not thread safe and should be called inside the event-loop's thread. - */ -AWS_IO_API -int aws_event_loop_fetch_local_object( - struct aws_event_loop *event_loop, - void *key, - struct aws_event_loop_local_object *obj); - -/** - * Puts an item object the event-loop's data store. Key will be taken as the memory address of the memory pointed to by - * key. The lifetime of item must live until remove or a put item overrides it. This function is not thread safe and - * should be called inside the event-loop's thread. - */ -AWS_IO_API -int aws_event_loop_put_local_object(struct aws_event_loop *event_loop, struct aws_event_loop_local_object *obj); - -/** - * Removes an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to - * by key. If removed_item is not null, the removed item will be moved to it if it exists. Otherwise, the default - * deallocation strategy will be used. This function is not thread safe and should be called inside the event-loop's - * thread. - */ -AWS_IO_API -int aws_event_loop_remove_local_object( - struct aws_event_loop *event_loop, - void *key, - struct aws_event_loop_local_object *removed_obj); - -/** - * Triggers the running of the event loop. This function must not block. The event loop is not active until this - * function is invoked. This function can be called again on an event loop after calling aws_event_loop_stop() and - * aws_event_loop_wait_for_stop_completion(). - */ -AWS_IO_API -int aws_event_loop_run(struct aws_event_loop *event_loop); - -/** - * Triggers the event loop to stop, but does not wait for the loop to stop completely. - * This function may be called from outside or inside the event loop thread. It is safe to call multiple times. - * This function is called from destroy(). - * - * If you do not call destroy(), an event loop can be run again by calling stop(), wait_for_stop_completion(), run(). - */ -AWS_IO_API -int aws_event_loop_stop(struct aws_event_loop *event_loop); + /** + * Optional configuration to control how the event loop group's threads bind to CPU groups + */ + const uint16_t *cpu_group; -/** - * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the - * event-loop load balancer to take into account load when vending another event-loop to a caller. - * - * Call this function at the beginning of your event-loop tick: after wake-up, but before processing any IO or tasks. - */ -AWS_IO_API -void aws_event_loop_register_tick_start(struct aws_event_loop *event_loop); - -/** - * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the - * event-loop load balancer to take into account load when vending another event-loop to a caller. - * - * Call this function at the end of your event-loop tick: after processing IO and tasks. - */ -AWS_IO_API -void aws_event_loop_register_tick_end(struct aws_event_loop *event_loop); - -/** - * Returns the current load factor (however that may be calculated). If the event-loop is not invoking - * aws_event_loop_register_tick_start() and aws_event_loop_register_tick_end(), this value will always be 0. - */ -AWS_IO_API -size_t aws_event_loop_get_load_factor(struct aws_event_loop *event_loop); + /** + * Override for the clock function that event loops should use. Defaults to the system's high resolution + * timer. + * + * Do not bind this value to managed code; it is only used in timing-sensitive tests. + */ + aws_io_clock_fn *clock_override; +}; -/** - * Blocks until the event loop stops completely. - * If you want to call aws_event_loop_run() again, you must call this after aws_event_loop_stop(). - * It is not safe to call this function from inside the event loop thread. - */ -AWS_IO_API -int aws_event_loop_wait_for_stop_completion(struct aws_event_loop *event_loop); +AWS_EXTERN_C_BEGIN /** * The event loop will schedule the task and run it on the event loop thread as soon as possible. @@ -319,105 +112,63 @@ void aws_event_loop_schedule_task_future( AWS_IO_API void aws_event_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task); -#if AWS_USE_IO_COMPLETION_PORTS - /** - * Associates an aws_io_handle with the event loop's I/O Completion Port. - * - * The handle must use aws_overlapped for all async operations requiring an OVERLAPPED struct. - * When the operation completes, the aws_overlapped's completion function will run on the event loop thread. - * Note that completion functions will not be invoked while the event loop is stopped. Users should wait for all async - * operations on connected handles to complete before cleaning up or destroying the event loop. - * - * A handle may only be connected to one event loop in its lifetime. + * Returns true if the event loop's thread is the same thread that called this function, otherwise false. */ AWS_IO_API -int aws_event_loop_connect_handle_to_io_completion_port( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle); - -#else /* !AWS_USE_IO_COMPLETION_PORTS */ +bool aws_event_loop_thread_is_callers_thread(struct aws_event_loop *event_loop); /** - * Subscribes on_event to events on the event-loop for handle. events is a bitwise concatenation of the events that were - * received. The definition for these values can be found in aws_io_event_type. Currently, only - * AWS_IO_EVENT_TYPE_READABLE and AWS_IO_EVENT_TYPE_WRITABLE are honored. You always are registered for error conditions - * and closure. This function may be called from outside or inside the event loop thread. However, the unsubscribe - * function must be called inside the event-loop's thread. + * Gets the current timestamp for the event loop's clock, in nanoseconds. This function is thread-safe. */ AWS_IO_API -int aws_event_loop_subscribe_to_io_events( - struct aws_event_loop *event_loop, - struct aws_io_handle *handle, - int events, - aws_event_loop_on_event_fn *on_event, - void *user_data); - -#endif /* AWS_USE_IO_COMPLETION_PORTS */ +int aws_event_loop_current_clock_time(const struct aws_event_loop *event_loop, uint64_t *time_nanos); /** - * Unsubscribes handle from event-loop notifications. - * This function is not thread safe and should be called inside the event-loop's thread. - * - * NOTE: if you are using io completion ports, this is a risky call. We use it in places, but only when we're certain - * there's no pending events. If you want to use it, it's your job to make sure you don't have pending events before - * calling it. + * Creation function for event loop groups. */ AWS_IO_API -int aws_event_loop_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struct aws_io_handle *handle); +struct aws_event_loop_group *aws_event_loop_group_new( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options); /** - * Cleans up resources (user_data) associated with the I/O eventing subsystem for a given handle. This should only - * ever be necessary in the case where you are cleaning up an event loop during shutdown and its thread has already - * been joined. + * Increments the reference count on the event loop group, allowing the caller to take a reference to it. + * + * Returns the same event loop group passed in. */ AWS_IO_API -void aws_event_loop_free_io_event_resources(struct aws_event_loop *event_loop, struct aws_io_handle *handle); +struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group); /** - * Returns true if the event loop's thread is the same thread that called this function, otherwise false. + * Decrements an event loop group's ref count. When the ref count drops to zero, the event loop group will be + * destroyed. */ AWS_IO_API -bool aws_event_loop_thread_is_callers_thread(struct aws_event_loop *event_loop); +void aws_event_loop_group_release(struct aws_event_loop_group *el_group); /** - * Gets the current timestamp for the event loop's clock, in nanoseconds. This function is thread-safe. + * Returns the event loop at a particular index. If the index is out of bounds, null is returned. */ AWS_IO_API -int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_t *time_nanos); +struct aws_event_loop *aws_event_loop_group_get_loop_at(struct aws_event_loop_group *el_group, size_t index); /** - * Creates an event loop group, with clock, number of loops to manage, and the function to call for creating a new - * event loop. + * Gets the number of event loops managed by an event loop group. */ AWS_IO_API -struct aws_event_loop_group *aws_event_loop_group_new( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options); +size_t aws_event_loop_group_get_loop_count(const struct aws_event_loop_group *el_group); -/** Creates an event loop group, with clock, number of loops to manage, the function to call for creating a new - * event loop, and also pins all loops to hw threads on the same cpu_group (e.g. NUMA nodes). Note: - * If el_count exceeds the number of hw threads in the cpu_group it will be ignored on the assumption that if you - * care about NUMA, you don't want hyper-threads doing your IO and you especially don't want IO on a different node. +/** + * Fetches the next loop for use. The purpose is to enable load balancing across loops. You should not depend on how + * this load balancing is done as it is subject to change in the future. Currently it uses the "best-of-two" algorithm + * based on the load factor of each loop. */ AWS_IO_API -struct aws_event_loop_group *aws_event_loop_group_new_pinned_to_cpu_group( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - uint16_t cpu_group, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options); +struct aws_event_loop *aws_event_loop_group_get_next_loop(struct aws_event_loop_group *el_group); /** - * Initializes an event loop group with platform defaults. If max_threads == 0, then the - * loop count will be the number of available processors on the machine / 2 (to exclude hyper-threads). - * Otherwise, max_threads will be the number of event loops in the group. + * @deprecated - use aws_event_loop_group_new() instead */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new_default( @@ -425,14 +176,8 @@ struct aws_event_loop_group *aws_event_loop_group_new_default( uint16_t max_threads, const struct aws_shutdown_callback_options *shutdown_options); -/** Creates an event loop group, with clock, number of loops to manage, the function to call for creating a new - * event loop, and also pins all loops to hw threads on the same cpu_group (e.g. NUMA nodes). Note: - * If el_count exceeds the number of hw threads in the cpu_group it will be clamped to the number of hw threads - * on the assumption that if you care about NUMA, you don't want hyper-threads doing your IO and you especially - * don't want IO on a different node. - * - * If max_threads == 0, then the - * loop count will be the number of available processors in the cpu_group / 2 (to exclude hyper-threads) +/** + * @deprecated - use aws_event_loop_group_new() instead */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( @@ -442,35 +187,49 @@ struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_grou const struct aws_shutdown_callback_options *shutdown_options); /** - * Increments the reference count on the event loop group, allowing the caller to take a reference to it. + * @internal - Don't use outside of testing. * - * Returns the same event loop group passed in. + * Returns the opaque internal user data of an event loop. Can be cast into a specific implementation by + * privileged consumers. */ AWS_IO_API -struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group); +void *aws_event_loop_get_impl(struct aws_event_loop *event_loop); /** - * Decrements an event loop group's ref count. When the ref count drops to zero, the event loop group will be - * destroyed. + * @internal - Don't use outside of testing. + * + * Initializes the base structure used by all event loop implementations with test-oriented overrides. */ AWS_IO_API -void aws_event_loop_group_release(struct aws_event_loop_group *el_group); - -AWS_IO_API -struct aws_event_loop *aws_event_loop_group_get_loop_at(struct aws_event_loop_group *el_group, size_t index); +struct aws_event_loop *aws_event_loop_new_base( + struct aws_allocator *allocator, + aws_io_clock_fn *clock, + struct aws_event_loop_vtable *vtable, + void *impl); +/** + * @internal - Don't use outside of testing. + * + * Common cleanup code for all implementations. + * This is only called from the *destroy() function of event loop implementations. + */ AWS_IO_API -size_t aws_event_loop_group_get_loop_count(struct aws_event_loop_group *el_group); +void aws_event_loop_clean_up_base(struct aws_event_loop *event_loop); /** - * Fetches the next loop for use. The purpose is to enable load balancing across loops. You should not depend on how - * this load balancing is done as it is subject to change in the future. Currently it uses the "best-of-two" algorithm - * based on the load factor of each loop. + * @internal - Don't use outside of testing. + * + * Invokes the destroy() fn for the event loop implementation. + * If the event loop is still in a running state, this function will block waiting on the event loop to shutdown. + * If you do not want this function to block, call aws_event_loop_stop() manually first. + * If the event loop is shared by multiple threads then destroy must be called by exactly one thread. All other threads + * must ensure their API calls to the event loop happen-before the call to destroy. */ AWS_IO_API -struct aws_event_loop *aws_event_loop_group_get_next_loop(struct aws_event_loop_group *el_group); +void aws_event_loop_destroy(struct aws_event_loop *event_loop); AWS_EXTERN_C_END + AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_IO_EVENT_LOOP_H */ diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h new file mode 100644 index 000000000..4eb2f6230 --- /dev/null +++ b/include/aws/io/private/event_loop_impl.h @@ -0,0 +1,299 @@ +#ifndef AWS_IO_EVENT_LOOP_IMPL_H +#define AWS_IO_EVENT_LOOP_IMPL_H + +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include + +#include +#include +#include +#include + +AWS_PUSH_SANE_WARNING_LEVEL + +struct aws_event_loop; +struct aws_overlapped; + +typedef void(aws_event_loop_on_completion_fn)( + struct aws_event_loop *event_loop, + struct aws_overlapped *overlapped, + int status_code, + size_t num_bytes_transferred); + +/** + * The aws_win32_OVERLAPPED struct is layout-compatible with OVERLAPPED as defined in . It is used + * here to avoid pulling in a dependency on which would also bring along a lot of bad macros, such + * as redefinitions of GetMessage and GetObject. Note that the OVERLAPPED struct layout in the Windows SDK can + * never be altered without breaking binary compatibility for every existing third-party executable, so there + * is no need to worry about keeping this definition in sync. + */ +struct aws_win32_OVERLAPPED { + uintptr_t Internal; + uintptr_t InternalHigh; + union { + struct { + uint32_t Offset; + uint32_t OffsetHigh; + } s; + void *Pointer; + } u; + void *hEvent; +}; + +/** + * Use aws_overlapped when a handle connected to the event loop needs an OVERLAPPED struct. + * OVERLAPPED structs are needed to make OS-level async I/O calls. + * When the I/O completes, the assigned aws_event_loop_on_completion_fn is called from the event_loop's thread. + * While the I/O is pending, it is not safe to modify or delete aws_overlapped. + * Call aws_overlapped_init() before first use. If the aws_overlapped will be used multiple times, call + * aws_overlapped_reset() or aws_overlapped_init() between uses. + */ +struct aws_overlapped { + struct aws_win32_OVERLAPPED overlapped; + aws_event_loop_on_completion_fn *on_completion; + void *user_data; +}; + +enum aws_io_event_type { + AWS_IO_EVENT_TYPE_READABLE = 1, + AWS_IO_EVENT_TYPE_WRITABLE = 2, + AWS_IO_EVENT_TYPE_REMOTE_HANG_UP = 4, + AWS_IO_EVENT_TYPE_CLOSED = 8, + AWS_IO_EVENT_TYPE_ERROR = 16, +}; + +struct aws_event_loop { + struct aws_event_loop_vtable *vtable; + struct aws_allocator *alloc; + aws_io_clock_fn *clock; + struct aws_hash_table local_data; + struct aws_atomic_var current_load_factor; + uint64_t latest_tick_start; + size_t current_tick_latency_sum; + struct aws_atomic_var next_flush_time; + void *impl_data; +}; + +struct aws_event_loop_local_object; +typedef void(aws_event_loop_on_local_object_removed_fn)(struct aws_event_loop_local_object *); + +struct aws_event_loop_local_object { + const void *key; + void *object; + aws_event_loop_on_local_object_removed_fn *on_object_removed; +}; + +struct aws_event_loop_options { + aws_io_clock_fn *clock; + struct aws_thread_options *thread_options; +}; + +typedef struct aws_event_loop *(aws_new_event_loop_fn)(struct aws_allocator *alloc, + const struct aws_event_loop_options *options, + void *new_loop_user_data); + +struct aws_event_loop_group { + struct aws_allocator *allocator; + struct aws_array_list event_loops; + struct aws_ref_count ref_count; + struct aws_shutdown_callback_options shutdown_options; +}; + +AWS_EXTERN_C_BEGIN + +#ifdef AWS_USE_IO_COMPLETION_PORTS + +/** + * Prepares aws_overlapped for use, and sets a function to call when the overlapped operation completes. + */ +AWS_IO_API +void aws_overlapped_init( + struct aws_overlapped *overlapped, + aws_event_loop_on_completion_fn *on_completion, + void *user_data); + +/** + * Prepares aws_overlapped for re-use without changing the assigned aws_event_loop_on_completion_fn. + * Call aws_overlapped_init(), instead of aws_overlapped_reset(), to change the aws_event_loop_on_completion_fn. + */ +AWS_IO_API +void aws_overlapped_reset(struct aws_overlapped *overlapped); + +/** + * Casts an aws_overlapped pointer for use as a LPOVERLAPPED parameter to Windows API functions + */ +AWS_IO_API +struct _OVERLAPPED *aws_overlapped_to_windows_overlapped(struct aws_overlapped *overlapped); + +/** + * Associates an aws_io_handle with the event loop's I/O Completion Port. + * + * The handle must use aws_overlapped for all async operations requiring an OVERLAPPED struct. + * When the operation completes, the aws_overlapped's completion function will run on the event loop thread. + * Note that completion functions will not be invoked while the event loop is stopped. Users should wait for all async + * operations on connected handles to complete before cleaning up or destroying the event loop. + * + * A handle may only be connected to one event loop in its lifetime. + */ +AWS_IO_API +int aws_event_loop_connect_handle_to_io_completion_port( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle); + +#else + +/** + * Subscribes on_event to events on the event-loop for handle. events is a bitwise concatenation of the events that were + * received. The definition for these values can be found in aws_io_event_type. Currently, only + * AWS_IO_EVENT_TYPE_READABLE and AWS_IO_EVENT_TYPE_WRITABLE are honored. You always are registered for error conditions + * and closure. This function may be called from outside or inside the event loop thread. However, the unsubscribe + * function must be called inside the event-loop's thread. + */ +AWS_IO_API +int aws_event_loop_subscribe_to_io_events( + struct aws_event_loop *event_loop, + struct aws_io_handle *handle, + int events, + aws_event_loop_on_event_fn *on_event, + void *user_data); + +#endif /* AWS_USE_IO_COMPLETION_PORTS */ + +/** + * Creates an instance of the default event loop implementation for the current architecture and operating system. + */ +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock); + +/** + * Creates an instance of the default event loop implementation for the current architecture and operating system using + * extendable options. + */ +AWS_IO_API +struct aws_event_loop *aws_event_loop_new_default_with_options( + struct aws_allocator *alloc, + const struct aws_event_loop_options *options); + +/** + * Initializes common event-loop data structures. + * This is only called from the *new() function of event loop implementations. + */ +AWS_IO_API +int aws_event_loop_init_base(struct aws_event_loop *event_loop, struct aws_allocator *alloc, aws_io_clock_fn *clock); + +/** + * Fetches an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to + * by key. This function is not thread safe and should be called inside the event-loop's thread. + */ +AWS_IO_API +int aws_event_loop_fetch_local_object( + struct aws_event_loop *event_loop, + void *key, + struct aws_event_loop_local_object *obj); + +/** + * Puts an item object the event-loop's data store. Key will be taken as the memory address of the memory pointed to by + * key. The lifetime of item must live until remove or a put item overrides it. This function is not thread safe and + * should be called inside the event-loop's thread. + */ +AWS_IO_API +int aws_event_loop_put_local_object(struct aws_event_loop *event_loop, struct aws_event_loop_local_object *obj); + +/** + * Removes an object from the event-loop's data store. Key will be taken as the memory address of the memory pointed to + * by key. If removed_item is not null, the removed item will be moved to it if it exists. Otherwise, the default + * deallocation strategy will be used. This function is not thread safe and should be called inside the event-loop's + * thread. + */ +AWS_IO_API +int aws_event_loop_remove_local_object( + struct aws_event_loop *event_loop, + void *key, + struct aws_event_loop_local_object *removed_obj); + +/** + * Triggers the running of the event loop. This function must not block. The event loop is not active until this + * function is invoked. This function can be called again on an event loop after calling aws_event_loop_stop() and + * aws_event_loop_wait_for_stop_completion(). + */ +AWS_IO_API +int aws_event_loop_run(struct aws_event_loop *event_loop); + +/** + * Triggers the event loop to stop, but does not wait for the loop to stop completely. + * This function may be called from outside or inside the event loop thread. It is safe to call multiple times. + * This function is called from destroy(). + * + * If you do not call destroy(), an event loop can be run again by calling stop(), wait_for_stop_completion(), run(). + */ +AWS_IO_API +int aws_event_loop_stop(struct aws_event_loop *event_loop); + +/** + * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the + * event-loop load balancer to take into account load when vending another event-loop to a caller. + * + * Call this function at the beginning of your event-loop tick: after wake-up, but before processing any IO or tasks. + */ +AWS_IO_API +void aws_event_loop_register_tick_start(struct aws_event_loop *event_loop); + +/** + * For event-loop implementations to use for providing metrics info to the base event-loop. This enables the + * event-loop load balancer to take into account load when vending another event-loop to a caller. + * + * Call this function at the end of your event-loop tick: after processing IO and tasks. + */ +AWS_IO_API +void aws_event_loop_register_tick_end(struct aws_event_loop *event_loop); + +/** + * Returns the current load factor (however that may be calculated). If the event-loop is not invoking + * aws_event_loop_register_tick_start() and aws_event_loop_register_tick_end(), this value will always be 0. + */ +AWS_IO_API +size_t aws_event_loop_get_load_factor(struct aws_event_loop *event_loop); + +/** + * Blocks until the event loop stops completely. + * If you want to call aws_event_loop_run() again, you must call this after aws_event_loop_stop(). + * It is not safe to call this function from inside the event loop thread. + */ +AWS_IO_API +int aws_event_loop_wait_for_stop_completion(struct aws_event_loop *event_loop); + +/** + * Unsubscribes handle from event-loop notifications. + * This function is not thread safe and should be called inside the event-loop's thread. + * + * NOTE: if you are using io completion ports, this is a risky call. We use it in places, but only when we're certain + * there's no pending events. If you want to use it, it's your job to make sure you don't have pending events before + * calling it. + */ +AWS_IO_API +int aws_event_loop_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + +/** + * Cleans up resources (user_data) associated with the I/O eventing subsystem for a given handle. This should only + * ever be necessary in the case where you are cleaning up an event loop during shutdown and its thread has already + * been joined. + */ +AWS_IO_API +void aws_event_loop_free_io_event_resources(struct aws_event_loop *event_loop, struct aws_io_handle *handle); + +AWS_IO_API +struct aws_event_loop_group *aws_event_loop_group_new_internal( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options, + aws_new_event_loop_fn *new_loop_fn, + void *new_loop_user_data); + +AWS_EXTERN_C_END + +AWS_POP_SANE_WARNING_LEVEL + +#endif /* AWS_IO_EVENT_LOOP_IMPL_H */ diff --git a/include/aws/testing/io_testing_channel.h b/include/aws/testing/io_testing_channel.h index 192a269b0..c202168cb 100644 --- a/include/aws/testing/io_testing_channel.h +++ b/include/aws/testing/io_testing_channel.h @@ -9,10 +9,12 @@ #include #include #include +// #include #include #include struct testing_loop { + struct aws_allocator *allocator; struct aws_task_scheduler scheduler; bool mock_on_callers_thread; }; @@ -33,7 +35,7 @@ static int s_testing_loop_wait_for_stop_completion(struct aws_event_loop *event_ } static void s_testing_loop_schedule_task_now(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); aws_task_scheduler_schedule_now(&testing_loop->scheduler, task); } @@ -42,26 +44,27 @@ static void s_testing_loop_schedule_task_future( struct aws_task *task, uint64_t run_at_nanos) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); aws_task_scheduler_schedule_future(&testing_loop->scheduler, task, run_at_nanos); } static void s_testing_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); aws_task_scheduler_cancel_task(&testing_loop->scheduler, task); } static bool s_testing_loop_is_on_callers_thread(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); return testing_loop->mock_on_callers_thread; } static void s_testing_loop_destroy(struct aws_event_loop *event_loop) { - struct testing_loop *testing_loop = (struct testing_loop *)event_loop->impl_data; + struct testing_loop *testing_loop = (struct testing_loop *)aws_event_loop_get_impl(event_loop); + struct aws_allocator *allocator = testing_loop->allocator; aws_task_scheduler_clean_up(&testing_loop->scheduler); - aws_mem_release(event_loop->alloc, testing_loop); + aws_mem_release(allocator, testing_loop); aws_event_loop_clean_up_base(event_loop); - aws_mem_release(event_loop->alloc, event_loop); + aws_mem_release(allocator, event_loop); } static struct aws_event_loop_vtable s_testing_loop_vtable = { @@ -76,18 +79,14 @@ static struct aws_event_loop_vtable s_testing_loop_vtable = { }; static struct aws_event_loop *s_testing_loop_new(struct aws_allocator *allocator, aws_io_clock_fn clock) { - struct aws_event_loop *event_loop = - (struct aws_event_loop *)aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); - aws_event_loop_init_base(event_loop, allocator, clock); - struct testing_loop *testing_loop = (struct testing_loop *)aws_mem_calloc(allocator, 1, sizeof(struct testing_loop)); + aws_task_scheduler_init(&testing_loop->scheduler, allocator); testing_loop->mock_on_callers_thread = true; - event_loop->impl_data = testing_loop; - event_loop->vtable = &s_testing_loop_vtable; + testing_loop->allocator = allocator; - return event_loop; + return aws_event_loop_new_base(allocator, clock, &s_testing_loop_vtable, testing_loop); } typedef void(testing_channel_handler_on_shutdown_fn)( @@ -396,7 +395,7 @@ static inline int testing_channel_init( AWS_ZERO_STRUCT(*testing); testing->loop = s_testing_loop_new(allocator, options->clock_fn); - testing->loop_impl = (struct testing_loop *)testing->loop->impl_data; + testing->loop_impl = (struct testing_loop *)aws_event_loop_get_impl(testing->loop); struct aws_channel_options args = { .on_setup_completed = s_testing_channel_on_setup_completed, diff --git a/source/bsd/kqueue_event_loop.c b/source/bsd/kqueue_event_loop.c index 33a517e7b..e0f8ed63b 100644 --- a/source/bsd/kqueue_event_loop.c +++ b/source/bsd/kqueue_event_loop.c @@ -5,14 +5,14 @@ #include -#include - #include #include #include #include #include #include +#include +#include #if defined(__FreeBSD__) || defined(__NetBSD__) # define __BSD_VISIBLE 1 diff --git a/source/channel.c b/source/channel.c index 55903fc1d..3e3d33932 100644 --- a/source/channel.c +++ b/source/channel.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #ifdef _MSC_VER diff --git a/source/event_loop.c b/source/event_loop.c index 1e7aef676..2e0861964 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -5,6 +5,9 @@ #include +#include +#include + #include #include #include @@ -72,30 +75,32 @@ static void s_aws_event_loop_group_shutdown_async(struct aws_event_loop_group *e aws_thread_launch(&cleanup_thread, s_event_loop_destroy_async_thread_fn, el_group, &thread_options); } -static struct aws_event_loop_group *s_event_loop_group_new( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - uint16_t cpu_group, - bool pin_threads, +struct aws_event_loop_group *aws_event_loop_group_new_internal( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options, aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options) { - AWS_ASSERT(new_loop_fn); + void *new_loop_user_data) { + AWS_FATAL_ASSERT(new_loop_fn); + + aws_io_clock_fn *clock = options->clock_override; + if (!clock) { + clock = aws_high_res_clock_get_ticks; + } size_t group_cpu_count = 0; struct aws_cpu_info *usable_cpus = NULL; + bool pin_threads = options->cpu_group != NULL; if (pin_threads) { + uint16_t cpu_group = *options->cpu_group; group_cpu_count = aws_get_cpu_count_for_group(cpu_group); - if (!group_cpu_count) { + // LOG THIS aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); return NULL; } - usable_cpus = aws_mem_calloc(alloc, group_cpu_count, sizeof(struct aws_cpu_info)); - + usable_cpus = aws_mem_calloc(allocator, group_cpu_count, sizeof(struct aws_cpu_info)); if (usable_cpus == NULL) { return NULL; } @@ -103,16 +108,23 @@ static struct aws_event_loop_group *s_event_loop_group_new( aws_get_cpu_ids_for_group(cpu_group, usable_cpus, group_cpu_count); } - struct aws_event_loop_group *el_group = aws_mem_calloc(alloc, 1, sizeof(struct aws_event_loop_group)); + struct aws_event_loop_group *el_group = aws_mem_calloc(allocator, 1, sizeof(struct aws_event_loop_group)); if (el_group == NULL) { return NULL; } - el_group->allocator = alloc; + el_group->allocator = allocator; aws_ref_count_init( &el_group->ref_count, el_group, (aws_simple_completion_callback *)s_aws_event_loop_group_shutdown_async); - if (aws_array_list_init_dynamic(&el_group->event_loops, alloc, el_count, sizeof(struct aws_event_loop *))) { + uint16_t el_count = options->loop_count; + if (el_count == 0) { + uint16_t processor_count = (uint16_t)aws_system_info_processor_count(); + /* cut them in half to avoid using hyper threads for the IO work. */ + el_count = processor_count > 1 ? processor_count / 2 : processor_count; + } + + if (aws_array_list_init_dynamic(&el_group->event_loops, allocator, el_count, sizeof(struct aws_event_loop *))) { goto on_error; } @@ -121,7 +133,7 @@ static struct aws_event_loop_group *s_event_loop_group_new( if (!pin_threads || (i < group_cpu_count && !usable_cpus[i].suspected_hyper_thread)) { struct aws_thread_options thread_options = *aws_default_thread_options(); - struct aws_event_loop_options options = { + struct aws_event_loop_options el_options = { .clock = clock, .thread_options = &thread_options, }; @@ -138,8 +150,7 @@ static struct aws_event_loop_group *s_event_loop_group_new( } thread_options.name = aws_byte_cursor_from_c_str(thread_name); - struct aws_event_loop *loop = new_loop_fn(alloc, &options, new_loop_user_data); - + struct aws_event_loop *loop = new_loop_fn(allocator, &el_options, new_loop_user_data); if (!loop) { goto on_error; } @@ -155,12 +166,12 @@ static struct aws_event_loop_group *s_event_loop_group_new( } } - if (shutdown_options != NULL) { - el_group->shutdown_options = *shutdown_options; + if (options->shutdown_options != NULL) { + el_group->shutdown_options = *options->shutdown_options; } if (pin_threads) { - aws_mem_release(alloc, usable_cpus); + aws_mem_release(allocator, usable_cpus); } return el_group; @@ -169,7 +180,7 @@ on_error:; /* cache the error code to prevent any potential side effects */ int cached_error_code = aws_last_error(); - aws_mem_release(alloc, usable_cpus); + aws_mem_release(allocator, usable_cpus); s_aws_event_loop_group_shutdown_sync(el_group); s_event_loop_group_thread_exit(el_group); @@ -178,20 +189,6 @@ on_error:; return NULL; } -struct aws_event_loop_group *aws_event_loop_group_new( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options) { - - AWS_ASSERT(new_loop_fn); - AWS_ASSERT(el_count); - - return s_event_loop_group_new(alloc, clock, el_count, 0, false, new_loop_fn, new_loop_user_data, shutdown_options); -} - static struct aws_event_loop *s_default_new_event_loop( struct aws_allocator *allocator, const struct aws_event_loop_options *options, @@ -201,49 +198,11 @@ static struct aws_event_loop *s_default_new_event_loop( return aws_event_loop_new_default_with_options(allocator, options); } -struct aws_event_loop_group *aws_event_loop_group_new_default( - struct aws_allocator *alloc, - uint16_t max_threads, - const struct aws_shutdown_callback_options *shutdown_options) { - if (!max_threads) { - uint16_t processor_count = (uint16_t)aws_system_info_processor_count(); - /* cut them in half to avoid using hyper threads for the IO work. */ - max_threads = processor_count > 1 ? processor_count / 2 : processor_count; - } - - return aws_event_loop_group_new( - alloc, aws_high_res_clock_get_ticks, max_threads, s_default_new_event_loop, NULL, shutdown_options); -} - -struct aws_event_loop_group *aws_event_loop_group_new_pinned_to_cpu_group( - struct aws_allocator *alloc, - aws_io_clock_fn *clock, - uint16_t el_count, - uint16_t cpu_group, - aws_new_event_loop_fn *new_loop_fn, - void *new_loop_user_data, - const struct aws_shutdown_callback_options *shutdown_options) { - AWS_ASSERT(new_loop_fn); - AWS_ASSERT(el_count); - - return s_event_loop_group_new( - alloc, clock, el_count, cpu_group, true, new_loop_fn, new_loop_user_data, shutdown_options); -} - -struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( - struct aws_allocator *alloc, - uint16_t max_threads, - uint16_t cpu_group, - const struct aws_shutdown_callback_options *shutdown_options) { - - if (!max_threads) { - uint16_t processor_count = (uint16_t)aws_system_info_processor_count(); - /* cut them in half to avoid using hyper threads for the IO work. */ - max_threads = processor_count > 1 ? processor_count / 2 : processor_count; - } +struct aws_event_loop_group *aws_event_loop_group_new( + struct aws_allocator *allocator, + const struct aws_event_loop_group_options *options) { - return aws_event_loop_group_new_pinned_to_cpu_group( - alloc, aws_high_res_clock_get_ticks, max_threads, cpu_group, s_default_new_event_loop, NULL, shutdown_options); + return aws_event_loop_group_new_internal(allocator, options, s_default_new_event_loop, NULL); } struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group) { @@ -260,7 +219,7 @@ void aws_event_loop_group_release(struct aws_event_loop_group *el_group) { } } -size_t aws_event_loop_group_get_loop_count(struct aws_event_loop_group *el_group) { +size_t aws_event_loop_group_get_loop_count(const struct aws_event_loop_group *el_group) { return aws_array_list_length(&el_group->event_loops); } @@ -524,7 +483,52 @@ bool aws_event_loop_thread_is_callers_thread(struct aws_event_loop *event_loop) return event_loop->vtable->is_on_callers_thread(event_loop); } -int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_t *time_nanos) { +int aws_event_loop_current_clock_time(const struct aws_event_loop *event_loop, uint64_t *time_nanos) { AWS_ASSERT(event_loop->clock); return event_loop->clock(time_nanos); } + +struct aws_event_loop_group *aws_event_loop_group_new_default( + struct aws_allocator *alloc, + uint16_t max_threads, + const struct aws_shutdown_callback_options *shutdown_options) { + + struct aws_event_loop_group_options elg_options = { + .loop_count = max_threads, + .shutdown_options = shutdown_options, + }; + + return aws_event_loop_group_new(alloc, &elg_options); +} + +struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( + struct aws_allocator *alloc, + uint16_t max_threads, + uint16_t cpu_group, + const struct aws_shutdown_callback_options *shutdown_options) { + + struct aws_event_loop_group_options elg_options = { + .loop_count = max_threads, + .shutdown_options = shutdown_options, + .cpu_group = &cpu_group, + }; + + return aws_event_loop_group_new(alloc, &elg_options); +} + +void *aws_event_loop_get_impl(struct aws_event_loop *event_loop) { + return event_loop->impl_data; +} + +struct aws_event_loop *aws_event_loop_new_base( + struct aws_allocator *allocator, + aws_io_clock_fn *clock, + struct aws_event_loop_vtable *vtable, + void *impl) { + struct aws_event_loop *event_loop = aws_mem_acquire(allocator, sizeof(struct aws_event_loop)); + aws_event_loop_init_base(event_loop, allocator, clock); + event_loop->impl_data = impl; + event_loop->vtable = vtable; + + return event_loop; +} diff --git a/source/exponential_backoff_retry_strategy.c b/source/exponential_backoff_retry_strategy.c index cf2472269..2110cbd46 100644 --- a/source/exponential_backoff_retry_strategy.c +++ b/source/exponential_backoff_retry_strategy.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,7 @@ static void s_exponential_retry_destroy(struct aws_retry_strategy *retry_strateg if (completion_callback != NULL) { completion_callback(completion_user_data); } - aws_ref_count_release(&el_group->ref_count); + aws_event_loop_group_release(el_group); } } @@ -361,7 +362,7 @@ struct aws_retry_strategy *aws_retry_strategy_new_exponential_backoff( aws_atomic_init_int(&exponential_backoff_strategy->base.ref_count, 1); exponential_backoff_strategy->config = *config; exponential_backoff_strategy->config.el_group = - aws_ref_count_acquire(&exponential_backoff_strategy->config.el_group->ref_count); + aws_event_loop_group_acquire(exponential_backoff_strategy->config.el_group); if (!exponential_backoff_strategy->config.generate_random && !exponential_backoff_strategy->config.generate_random_impl) { diff --git a/source/linux/epoll_event_loop.c b/source/linux/epoll_event_loop.c index 094a7836a..a99d5a8cf 100644 --- a/source/linux/epoll_event_loop.c +++ b/source/linux/epoll_event_loop.c @@ -3,17 +3,16 @@ * SPDX-License-Identifier: Apache-2.0. */ -#include - #include #include #include #include #include #include -#include - +#include #include +#include +#include #include diff --git a/source/posix/pipe.c b/source/posix/pipe.c index f727b021c..449ab1318 100644 --- a/source/posix/pipe.c +++ b/source/posix/pipe.c @@ -6,6 +6,7 @@ #include #include +#include #ifdef __GLIBC__ # define __USE_GNU diff --git a/source/posix/socket.c b/source/posix/socket.c index cdd69d2d0..49e18f47e 100644 --- a/source/posix/socket.c +++ b/source/posix/socket.c @@ -13,6 +13,7 @@ #include #include +#include #include #include diff --git a/source/s2n/s2n_tls_channel_handler.c b/source/s2n/s2n_tls_channel_handler.c index e9560608e..8326543e8 100644 --- a/source/s2n/s2n_tls_channel_handler.c +++ b/source/s2n/s2n_tls_channel_handler.c @@ -5,21 +5,20 @@ #include #include +#include #include - +#include +#include +#include #include #include #include #include +#include #include #include #include -#include -#include -#include -#include - #include #ifdef AWS_S2N_INSOURCE_PATH # include diff --git a/source/windows/iocp/iocp_event_loop.c b/source/windows/iocp/iocp_event_loop.c index 313344ab9..1d0801e4b 100644 --- a/source/windows/iocp/iocp_event_loop.c +++ b/source/windows/iocp/iocp_event_loop.c @@ -11,6 +11,7 @@ #include #include +#include #include diff --git a/source/windows/iocp/pipe.c b/source/windows/iocp/pipe.c index 04145c679..a9e2185e5 100644 --- a/source/windows/iocp/pipe.c +++ b/source/windows/iocp/pipe.c @@ -7,6 +7,7 @@ #include #include +#include #include #include diff --git a/source/windows/iocp/socket.c b/source/windows/iocp/socket.c index 755950f0c..7286bd6ba 100644 --- a/source/windows/iocp/socket.c +++ b/source/windows/iocp/socket.c @@ -26,6 +26,7 @@ below, clang-format doesn't work (at least on my version) with the c-style comme #include #include #include +#include #include #include diff --git a/tests/alpn_handler_test.c b/tests/alpn_handler_test.c index 5d83bad4e..fa6d88e27 100644 --- a/tests/alpn_handler_test.c +++ b/tests/alpn_handler_test.c @@ -5,6 +5,7 @@ #include #include +#include #include #include diff --git a/tests/byo_crypto_test.c b/tests/byo_crypto_test.c index 878889646..1414f8652 100644 --- a/tests/byo_crypto_test.c +++ b/tests/byo_crypto_test.c @@ -54,7 +54,11 @@ static struct byo_crypto_common_tester c_tester; static int s_byo_crypto_common_tester_init(struct aws_allocator *allocator, struct byo_crypto_common_tester *tester) { AWS_ZERO_STRUCT(*tester); aws_io_library_init(allocator); - tester->el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; tester->mutex = mutex; diff --git a/tests/channel_test.c b/tests/channel_test.c index 9a730a351..8fc530f99 100644 --- a/tests/channel_test.c +++ b/tests/channel_test.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -684,7 +685,10 @@ static int s_test_channel_connect_some_hosts_timeout(struct aws_allocator *alloc .shutdown = false, }; - struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); /* resolve our s3 test bucket and an EC2 host with an ACL that blackholes the connection */ const struct aws_string *addr1_ipv4 = NULL; diff --git a/tests/default_host_resolver_test.c b/tests/default_host_resolver_test.c index 2d0178a73..f47b346bf 100644 --- a/tests/default_host_resolver_test.c +++ b/tests/default_host_resolver_test.c @@ -96,7 +96,10 @@ static int s_test_default_with_ipv6_lookup_fn(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -189,7 +192,10 @@ static int s_test_default_host_resolver_ipv6_address_variations_fn(struct aws_al }; - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -263,7 +269,10 @@ static int s_test_default_with_ipv4_only_lookup_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -333,7 +342,10 @@ static int s_test_default_with_multiple_lookups_fn(struct aws_allocator *allocat aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -460,7 +472,10 @@ static int s_test_resolver_ttls_fn(struct aws_allocator *allocator, void *ctx) { s_set_time(0); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, .max_entries = 10, .system_clock_override_fn = s_clock_fn}; @@ -672,7 +687,10 @@ static int s_test_resolver_connect_failure_recording_fn(struct aws_allocator *al aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -864,7 +882,10 @@ static int s_test_resolver_ttl_refreshes_on_resolve_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1044,7 +1065,10 @@ static int s_test_resolver_ipv4_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1105,7 +1129,10 @@ static int s_test_resolver_purge_host_cache(struct aws_allocator *allocator, voi (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1220,7 +1247,10 @@ static int s_test_resolver_purge_cache(struct aws_allocator *allocator, void *ct (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1369,7 +1399,10 @@ static int s_test_resolver_ipv6_address_lookup_fn(struct aws_allocator *allocato aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, @@ -1431,7 +1464,10 @@ static int s_test_resolver_low_frequency_starvation_fn(struct aws_allocator *all aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = el_group, diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index e86448c8b..92b739156 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -8,9 +8,9 @@ #include #include #include -#include - #include +#include +#include #include struct task_args { @@ -1041,7 +1041,10 @@ static int test_event_loop_group_setup_and_shutdown(struct aws_allocator *alloca (void)ctx; aws_io_library_init(allocator); - struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new_default(allocator, 0, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); size_t cpu_count = aws_system_info_processor_count(); size_t el_count = aws_event_loop_group_get_loop_count(event_loop_group); @@ -1074,10 +1077,16 @@ static int test_numa_aware_event_loop_group_setup_and_shutdown(struct aws_alloca size_t cpus_for_group = aws_get_cpu_count_for_group(0); size_t el_count = 1; - /* pass UINT16_MAX here to check the boundary conditions on numa cpu detection. It should never create more threads - * than hw cpus available */ - struct aws_event_loop_group *event_loop_group = - aws_event_loop_group_new_default_pinned_to_cpu_group(allocator, UINT16_MAX, 0, NULL); + uint16_t cpu_group = 0; + struct aws_event_loop_group_options elg_options = { + /* + * pass UINT16_MAX here to check the boundary conditions on numa cpu detection. It should never create more + * threads than hw cpus available + */ + .loop_count = UINT16_MAX, + .cpu_group = &cpu_group, + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); el_count = aws_event_loop_group_get_loop_count(event_loop_group); @@ -1154,8 +1163,12 @@ static int test_event_loop_group_setup_and_shutdown_async(struct aws_allocator * async_shutdown_options.shutdown_callback_user_data = &task_args; async_shutdown_options.shutdown_callback_fn = s_async_shutdown_complete_callback; - struct aws_event_loop_group *event_loop_group = - aws_event_loop_group_new_default(allocator, 0, &async_shutdown_options); + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + .shutdown_options = &async_shutdown_options, + }; + + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(event_loop_group); diff --git a/tests/exponential_backoff_retry_test.c b/tests/exponential_backoff_retry_test.c index a3bf7bde0..779a4f50f 100644 --- a/tests/exponential_backoff_retry_test.c +++ b/tests/exponential_backoff_retry_test.c @@ -66,7 +66,10 @@ static int s_test_exponential_backoff_retry_too_many_retries_for_jitter_mode( aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, .jitter_mode = jitter_mode, @@ -157,7 +160,10 @@ static int s_test_exponential_backoff_retry_client_errors_do_not_count_fn(struct aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .el_group = el_group, .max_retries = 3, @@ -201,7 +207,10 @@ static int s_test_exponential_backoff_retry_no_jitter_time_taken_fn(struct aws_a aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, .jitter_mode = AWS_EXPONENTIAL_BACKOFF_JITTER_NONE, @@ -253,7 +262,10 @@ static int s_test_exponential_max_backoff_retry_no_jitter_fn(struct aws_allocato aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 3, .jitter_mode = AWS_EXPONENTIAL_BACKOFF_JITTER_NONE, @@ -310,7 +322,10 @@ static int s_test_exponential_backoff_retry_invalid_options_fn(struct aws_alloca aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_exponential_backoff_retry_options config = { .max_retries = 64, .el_group = el_group, diff --git a/tests/future_test.c b/tests/future_test.c index 1ac94b551..795d30bb5 100644 --- a/tests/future_test.c +++ b/tests/future_test.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "future_test.h" diff --git a/tests/pipe_test.c b/tests/pipe_test.c index 053c5aefd..f15f4da33 100644 --- a/tests/pipe_test.c +++ b/tests/pipe_test.c @@ -8,6 +8,7 @@ #include #include #include +#include #include enum pipe_loop_setup { diff --git a/tests/pkcs11_test.c b/tests/pkcs11_test.c index 792ed5fa4..4af9d0fb0 100644 --- a/tests/pkcs11_test.c +++ b/tests/pkcs11_test.c @@ -1653,8 +1653,10 @@ static int s_test_pkcs11_tls_negotiation_succeeds_common( ASSERT_SUCCESS(aws_mutex_init(&s_tls_tester.synced.mutex)); ASSERT_SUCCESS(aws_condition_variable_init(&s_tls_tester.synced.cvar)); - struct aws_event_loop_group *event_loop_group = - aws_event_loop_group_new_default(allocator, 1, NULL /*shutdown_opts*/); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new(allocator, &elg_options); ASSERT_NOT_NULL(event_loop_group); struct aws_host_resolver_default_options resolver_opts = { diff --git a/tests/socket_handler_test.c b/tests/socket_handler_test.c index 85c7c7c39..ee7290d4e 100644 --- a/tests/socket_handler_test.c +++ b/tests/socket_handler_test.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include #include @@ -59,7 +60,10 @@ static int s_socket_common_tester_init(struct aws_allocator *allocator, struct s AWS_ZERO_STRUCT(*tester); aws_io_library_init(allocator); - tester->el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, @@ -1006,8 +1010,13 @@ static int s_socket_common_tester_statistics_init( aws_io_library_init(allocator); AWS_ZERO_STRUCT(*tester); - tester->el_group = - aws_event_loop_group_new(allocator, s_statistic_test_clock_fn, 1, s_default_new_event_loop, NULL, NULL); + + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + .clock_override = s_statistic_test_clock_fn, + }; + tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_default_new_event_loop, NULL); + struct aws_mutex mutex = AWS_MUTEX_INIT; struct aws_condition_variable condition_variable = AWS_CONDITION_VARIABLE_INIT; tester->mutex = mutex; diff --git a/tests/socket_test.c b/tests/socket_test.c index 097d6ef66..e01834a75 100644 --- a/tests/socket_test.c +++ b/tests/socket_test.c @@ -12,6 +12,7 @@ #include #include +#include #include #ifdef _MSC_VER @@ -624,7 +625,10 @@ static int s_test_connect_timeout(struct aws_allocator *allocator, void *ctx) { aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -704,7 +708,10 @@ static int s_test_connect_timeout_cancelation(struct aws_allocator *allocator, v aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); @@ -1147,7 +1154,10 @@ static int s_cleanup_before_connect_or_timeout_doesnt_explode(struct aws_allocat aws_io_library_init(allocator); - struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + }; + struct aws_event_loop_group *el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(el_group); ASSERT_NOT_NULL(event_loop, "Event loop creation failed with error: %s", aws_error_debug_str(aws_last_error())); diff --git a/tests/standard_retry_test.c b/tests/standard_retry_test.c index bb62de691..11991a3e0 100644 --- a/tests/standard_retry_test.c +++ b/tests/standard_retry_test.c @@ -8,6 +8,7 @@ #include #include +#include #include @@ -49,7 +50,12 @@ static int s_fixture_setup(struct aws_allocator *allocator, void *ctx) { .shutdown_callback_user_data = ctx, }; - test_data->el_group = aws_event_loop_group_new_default(allocator, 1, &shutdown_options); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + .shutdown_options = &shutdown_options, + }; + test_data->el_group = aws_event_loop_group_new(allocator, &elg_options); + ASSERT_NOT_NULL(test_data->el_group); struct aws_standard_retry_options retry_options = { .initial_bucket_capacity = 15, diff --git a/tests/tls_handler_test.c b/tests/tls_handler_test.c index a55d26077..7b1a68c32 100644 --- a/tests/tls_handler_test.c +++ b/tests/tls_handler_test.c @@ -10,6 +10,7 @@ # include # include # include +# include # include # include @@ -177,7 +178,10 @@ static int s_tls_common_tester_init(struct aws_allocator *allocator, struct tls_ aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - tester->el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + tester->el_group = aws_event_loop_group_new(allocator, &elg_options); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, @@ -532,7 +536,11 @@ static int s_tls_channel_server_client_tester_init(struct aws_allocator *allocat AWS_ZERO_STRUCT(s_server_client_tester); ASSERT_SUCCESS(aws_mutex_init(&s_server_client_tester.server_mutex)); ASSERT_SUCCESS(aws_condition_variable_init(&s_server_client_tester.server_condition_variable)); - s_server_client_tester.client_el_group = aws_event_loop_group_new_default(allocator, 0, NULL); + + struct aws_event_loop_group_options elg_options = { + .loop_count = 0, + }; + s_server_client_tester.client_el_group = aws_event_loop_group_new(allocator, &elg_options); ASSERT_SUCCESS(s_tls_rw_args_init( &s_server_client_tester.server_rw_args, @@ -1904,8 +1912,11 @@ static int s_tls_common_tester_statistics_init(struct aws_allocator *allocator, aws_atomic_store_int(&tester->current_time_ns, 0); aws_atomic_store_ptr(&tester->stats_handler, NULL); - tester->el_group = - aws_event_loop_group_new(allocator, s_statistic_test_clock_fn, 1, s_default_new_event_loop, NULL, NULL); + struct aws_event_loop_group_options elg_options = { + .loop_count = 1, + .clock_override = s_statistic_test_clock_fn, + }; + tester->el_group = aws_event_loop_group_new_internal(allocator, &elg_options, s_default_new_event_loop, NULL); struct aws_host_resolver_default_options resolver_options = { .el_group = tester->el_group, From 405c988df9d0523939c2f8169740c1d384a9e7f7 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 09:50:54 -0800 Subject: [PATCH 11/18] rename enum --- include/aws/io/event_loop.h | 24 ++++++------- include/aws/io/private/event_loop_impl.h | 2 +- include/aws/io/socket.h | 20 +++++------ source/event_loop.c | 42 +++++++++++----------- source/socket.c | 44 +++++++++++------------- 5 files changed, 64 insertions(+), 68 deletions(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index f44c431a2..3900e8db9 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -43,21 +43,21 @@ struct aws_event_loop_vtable { }; /** - * Event Loop Type. If set to `AWS_ELT_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default. + * Event Loop Type. If set to `AWS_EVENT_LOOP_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default. * * Default Event Loop Type - * Linux | AWS_ELT_EPOLL - * Windows | AWS_ELT_IOCP - * BSD Variants| AWS_ELT_KQUEUE - * MacOS | AWS_ELT_KQUEUE - * iOS | AWS_ELT_DISPATCH_QUEUE + * Linux | AWS_EVENT_LOOP_EPOLL + * Windows | AWS_EVENT_LOOP_IOCP + * BSD Variants| AWS_EVENT_LOOP_KQUEUE + * MacOS | AWS_EVENT_LOOP_KQUEUE + * iOS | AWS_EVENT_LOOP_DISPATCH_QUEUE */ enum aws_event_loop_type { - AWS_ELT_PLATFORM_DEFAULT = 0, - AWS_ELT_EPOLL, - AWS_ELT_IOCP, - AWS_ELT_KQUEUE, - AWS_ELT_DISPATCH_QUEUE, + AWS_EVENT_LOOP_PLATFORM_DEFAULT = 0, + AWS_EVENT_LOOP_EPOLL, + AWS_EVENT_LOOP_IOCP, + AWS_EVENT_LOOP_KQUEUE, + AWS_EVENT_LOOP_DISPATCH_QUEUE, }; /** @@ -72,7 +72,7 @@ struct aws_event_loop_group_options { uint16_t loop_count; /** - * Event loop type. If the event loop type is set to AWS_ELT_PLATFORM_DEFAULT, the + * Event loop type. If the event loop type is set to AWS_EVENT_LOOP_PLATFORM_DEFAULT, the * creation function will automatically use the platform’s default event loop type. */ enum aws_event_loop_type type; diff --git a/include/aws/io/private/event_loop_impl.h b/include/aws/io/private/event_loop_impl.h index 2e1992eed..528c7514c 100644 --- a/include/aws/io/private/event_loop_impl.h +++ b/include/aws/io/private/event_loop_impl.h @@ -92,7 +92,7 @@ struct aws_event_loop_options { struct aws_thread_options *thread_options; /** - * Event loop type. If the event loop type is set to AWS_ELT_PLATFORM_DEFAULT, the + * Event loop type. If the event loop type is set to AWS_EVENT_LOOP_PLATFORM_DEFAULT, the * creation function will automatically use the platform’s default event loop type. */ enum aws_event_loop_type type; diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index e0aaf9f84..916f62171 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -32,21 +32,21 @@ enum aws_socket_type { }; /** - * Socket Implementation type. Decides which socket implementation is used. If set to `AWS_SIT_PLATFORM_DEFAULT`, it + * Socket Implementation type. Decides which socket implementation is used. If set to `AWS_SOCKET_IMPL_PLATFORM_DEFAULT`, it * will automatically use the platform’s default. * * PLATFORM DEFAULT SOCKET IMPLEMENTATION TYPE - * Linux | AWS_SIT_POSIX - * Windows | AWS_SIT_WINSOCK - * BSD Variants| AWS_SIT_POSIX - * MacOS | AWS_SIT_POSIX - * iOS | AWS_SIT_APPLE_NETWORK_FRAMEWORK + * Linux | AWS_SOCKET_IMPL_POSIX + * Windows | AWS_SOCKET_IMPL_WINSOCK + * BSD Variants| AWS_SOCKET_IMPL_POSIX + * MacOS | AWS_SOCKET_IMPL_POSIX + * iOS | AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK */ enum aws_socket_impl_type { - AWS_SIT_PLATFORM_DEFAULT = 0, - AWS_SIT_POSIX, - AWS_SIT_WINSOCK, - AWS_SIT_APPLE_NETWORK_FRAMEWORK, + AWS_SOCKET_IMPL_PLATFORM_DEFAULT = 0, + AWS_SOCKET_IMPL_POSIX, + AWS_SOCKET_IMPL_WINSOCK, + AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK, }; #define AWS_NETWORK_INTERFACE_NAME_MAX 16 diff --git a/source/event_loop.c b/source/event_loop.c index cd87c3ff0..e7b285339 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -15,16 +15,16 @@ #include #ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK - static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_DISPATCH_QUEUE; + static enum aws_event_loop_type s_default_event_loop_type_override = AWS_EVENT_LOOP_DISPATCH_QUEUE; #else - static enum aws_event_loop_type s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; + static enum aws_event_loop_type s_default_event_loop_type_override = AWS_EVENT_LOOP_PLATFORM_DEFAULT; #endif struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, aws_io_clock_fn *clock) { struct aws_event_loop_options options = { .thread_options = NULL, .clock = clock, - .type = AWS_ELT_PLATFORM_DEFAULT, + .type = AWS_EVENT_LOOP_PLATFORM_DEFAULT, }; return aws_event_loop_new_with_options(alloc, &options); @@ -36,7 +36,7 @@ struct aws_event_loop *aws_event_loop_new_default_with_options( struct aws_event_loop_options local_options = { .thread_options = options->thread_options, .clock = options->clock, - .type = AWS_ELT_PLATFORM_DEFAULT, + .type = AWS_EVENT_LOOP_PLATFORM_DEFAULT, }; return aws_event_loop_new_with_options(alloc, &local_options); @@ -49,7 +49,7 @@ struct aws_event_loop *aws_event_loop_new_with_options( const struct aws_event_loop_options *options) { enum aws_event_loop_type type = options->type; - if (type == AWS_ELT_PLATFORM_DEFAULT) { + if (type == AWS_EVENT_LOOP_PLATFORM_DEFAULT) { type = aws_event_loop_get_default_type(); } @@ -59,13 +59,13 @@ struct aws_event_loop *aws_event_loop_new_with_options( } switch (type) { - case AWS_ELT_EPOLL: + case AWS_EVENT_LOOP_EPOLL: return aws_event_loop_new_epoll_with_options(alloc, options); - case AWS_ELT_IOCP: + case AWS_EVENT_LOOP_IOCP: return aws_event_loop_new_iocp_with_options(alloc, options); - case AWS_ELT_KQUEUE: + case AWS_EVENT_LOOP_KQUEUE: return aws_event_loop_new_kqueue_with_options(alloc, options); - case AWS_ELT_DISPATCH_QUEUE: + case AWS_EVENT_LOOP_DISPATCH_QUEUE: return aws_event_loop_new_dispatch_queue_with_options(alloc, options); default: AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Invalid event loop type on the platform."); @@ -542,23 +542,23 @@ int aws_event_loop_current_clock_time(struct aws_event_loop *event_loop, uint64_ * Override default event loop type. Only used internally in tests. * * If the defined type is not supported on the current platform, the event loop type would reset to - * AWS_ELT_PLATFORM_DEFAULT. + * AWS_EVENT_LOOP_PLATFORM_DEFAULT. */ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_override) { if (aws_event_loop_type_validate_platform(default_type_override) == AWS_OP_SUCCESS) { s_default_event_loop_type_override = default_type_override; } else { - s_default_event_loop_type_override = AWS_ELT_PLATFORM_DEFAULT; + s_default_event_loop_type_override = AWS_EVENT_LOOP_PLATFORM_DEFAULT; } } /** - * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to + * Return the default event loop type. If the return value is `AWS_EVENT_LOOP_PLATFORM_DEFAULT`, the function failed to * retrieve the default type value. * If `aws_event_loop_override_default_type` has been called, return the override default type. */ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { - if (s_default_event_loop_type_override != AWS_ELT_PLATFORM_DEFAULT) { + if (s_default_event_loop_type_override != AWS_EVENT_LOOP_PLATFORM_DEFAULT) { return s_default_event_loop_type_override; } /** @@ -566,40 +566,40 @@ static enum aws_event_loop_type aws_event_loop_get_default_type(void) { * definition was declared in aws-c-common. We probably do not want to introduce extra dependency here. */ #ifdef AWS_ENABLE_KQUEUE - return AWS_ELT_KQUEUE; + return AWS_EVENT_LOOP_KQUEUE; #endif #ifdef AWS_ENABLE_DISPATCH_QUEUE - return AWS_ELT_DISPATCH_QUEUE; + return AWS_EVENT_LOOP_DISPATCH_QUEUE; #endif #ifdef AWS_ENABLE_EPOLL - return AWS_ELT_EPOLL; + return AWS_EVENT_LOOP_EPOLL; #endif #ifdef AWS_OS_WINDOWS - return AWS_ELT_IOCP; + return AWS_EVENT_LOOP_IOCP; #endif } static int aws_event_loop_type_validate_platform(enum aws_event_loop_type type) { switch (type) { - case AWS_ELT_EPOLL: + case AWS_EVENT_LOOP_EPOLL: #ifndef AWS_ENABLE_EPOLL AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type EPOLL is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_EPOLL break; - case AWS_ELT_IOCP: + case AWS_EVENT_LOOP_IOCP: #ifndef AWS_ENABLE_IO_COMPLETION_PORTS AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type IOCP is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_IO_COMPLETION_PORTS break; - case AWS_ELT_KQUEUE: + case AWS_EVENT_LOOP_KQUEUE: #ifndef AWS_ENABLE_KQUEUE AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type KQUEUE is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_KQUEUE break; - case AWS_ELT_DISPATCH_QUEUE: + case AWS_EVENT_LOOP_DISPATCH_QUEUE: #ifndef AWS_ENABLE_DISPATCH_QUEUE AWS_LOGF_DEBUG(AWS_LS_IO_EVENT_LOOP, "Event loop type Dispatch Queue is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); diff --git a/source/socket.c b/source/socket.c index f7eb77520..2fcdef0e8 100644 --- a/source/socket.c +++ b/source/socket.c @@ -110,7 +110,7 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons // 1. get socket type & validate type is avliable the platform enum aws_socket_impl_type type = options->impl_type; - if (type == AWS_SIT_PLATFORM_DEFAULT) { + if (type == AWS_SOCKET_IMPL_PLATFORM_DEFAULT) { type = aws_socket_get_default_impl_type(); } @@ -121,22 +121,18 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons // 2. setup vtable based on socket type switch (type) { - case AWS_SIT_POSIX: + case AWS_SOCKET_IMPL_POSIX: return aws_socket_init_posix(socket, alloc, options); - break; - case AWS_SIT_WINSOCK: + case AWS_SOCKET_IMPL_WINSOCK: return aws_socket_init_winsock(socket, alloc, options); - break; - - case AWS_SIT_APPLE_NETWORK_FRAMEWORK: + case AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK: + // Apple Network Framework is not implemented yet. We should not use it yet. AWS_ASSERT(false && "Invalid socket implementation on platform."); return aws_socket_init_apple_nw_socket(socket, alloc, options); - break; default: - break; + AWS_ASSERT(false && "Invalid socket implementation on platform."); + return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); } - AWS_ASSERT(false && "Invalid socket implementation on platform."); - return AWS_ERROR_PLATFORM_NOT_SUPPORTED; } int aws_socket_get_bound_address(const struct aws_socket *socket, struct aws_socket_endpoint *out_address) { @@ -172,16 +168,16 @@ void aws_socket_endpoint_init_local_address_for_test(struct aws_socket_endpoint } /** - * Return the default socket implementation type. If the return value is `AWS_SIT_PLATFORM_DEFAULT`, the function failed - * to retrieve the default type value. + * Return the default socket implementation type. If the return value is `AWS_SOCKET_IMPL_PLATFORM_DEFAULT`, the + * function failed to retrieve the default type value. */ static enum aws_socket_impl_type aws_socket_get_default_impl_type(void) { - enum aws_socket_impl_type type = AWS_SIT_PLATFORM_DEFAULT; + enum aws_socket_impl_type type = AWS_SOCKET_IMPL_PLATFORM_DEFAULT; // override default socket #ifdef AWS_USE_APPLE_NETWORK_FRAMEWORK - type = AWS_SIT_APPLE_NETWORK_FRAMEWORK; + type = AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; #endif // AWS_USE_APPLE_NETWORK_FRAMEWORK - if (type != AWS_SIT_PLATFORM_DEFAULT) { + if (type != AWS_SOCKET_IMPL_PLATFORM_DEFAULT) { return type; } /** @@ -189,33 +185,33 @@ static enum aws_socket_impl_type aws_socket_get_default_impl_type(void) { * definition was declared in aws-c-common. We probably do not want to introduce extra dependency here. */ #if defined(AWS_ENABLE_KQUEUE) || defined(AWS_ENABLE_EPOLL) - return AWS_SIT_POSIX; + return AWS_SOCKET_IMPL_POSIX; #endif #ifdef AWS_ENABLE_DISPATCH_QUEUE - return AWS_SIT_APPLE_NETWORK_FRAMEWORK; + return AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK; #endif #ifdef AWS_ENABLE_IO_COMPLETION_PORTS - return AWS_SIT_WINSOCK; + return AWS_SOCKET_IMPL_WINSOCK; #else - return AWS_SIT_PLATFORM_DEFAULT; + return AWS_SOCKET_IMPL_PLATFORM_DEFAULT; #endif } static int aws_socket_impl_type_validate_platform(enum aws_socket_impl_type type) { switch (type) { - case AWS_SIT_POSIX: + case AWS_SOCKET_IMPL_POSIX: #if !defined(AWS_ENABLE_EPOLL) && !defined(AWS_ENABLE_KQUEUE) AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Posix socket is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); -#endif // AWS_SIT_POSIX +#endif // AWS_SOCKET_IMPL_POSIX break; - case AWS_SIT_WINSOCK: + case AWS_SOCKET_IMPL_WINSOCK: #ifndef AWS_ENABLE_IO_COMPLETION_PORTS AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "WINSOCK is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); #endif // AWS_ENABLE_IO_COMPLETION_PORTS break; - case AWS_SIT_APPLE_NETWORK_FRAMEWORK: + case AWS_SOCKET_IMPL_APPLE_NETWORK_FRAMEWORK: #ifndef AWS_ENABLE_DISPATCH_QUEUE AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "Apple Network Framework is not supported on the platform."); return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED); From 11c9be9a03f1beb1c8cf76cd03ecd8c58bba556c Mon Sep 17 00:00:00 2001 From: Alex Weibel Date: Tue, 12 Nov 2024 10:30:58 -0800 Subject: [PATCH 12/18] Add ML-KEM Support (#693) --- include/aws/io/tls_channel_handler.h | 10 +++++----- source/s2n/s2n_tls_channel_handler.c | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/aws/io/tls_channel_handler.h b/include/aws/io/tls_channel_handler.h index f44335b12..087b333a3 100644 --- a/include/aws/io/tls_channel_handler.h +++ b/include/aws/io/tls_channel_handler.h @@ -34,14 +34,14 @@ enum aws_tls_cipher_pref { /* Deprecated */ AWS_IO_TLS_CIPHER_PREF_KMS_PQ_TLSv1_0_2020_02 = 3, /* Deprecated */ AWS_IO_TLS_CIPHER_PREF_KMS_PQ_SIKE_TLSv1_0_2020_02 = 4, /* Deprecated */ AWS_IO_TLS_CIPHER_PREF_KMS_PQ_TLSv1_0_2020_07 = 5, + /* Deprecated */ AWS_IO_TLS_CIPHER_PREF_PQ_TLSv1_0_2021_05 = 6, /* - * This TLS cipher preference list contains post-quantum key exchange algorithms that have been submitted to NIST - * for potential future standardization. Support for this preference list, or PQ algorithms present in it, may be - * removed at any time in the future. PQ algorithms in this preference list will be used in hybrid mode, and always - * combined with a classical ECDHE key exchange. + * This TLS cipher preference list contains post-quantum key exchange algorithms that have been standardized by + * NIST. PQ algorithms in this preference list will be used in hybrid mode, and always combined with a classical + * ECDHE key exchange. */ - AWS_IO_TLS_CIPHER_PREF_PQ_TLSv1_0_2021_05 = 6, + AWS_IO_TLS_CIPHER_PREF_PQ_TLSV1_2_2024_10 = 7, AWS_IO_TLS_CIPHER_PREF_END_RANGE = 0xFFFF }; diff --git a/source/s2n/s2n_tls_channel_handler.c b/source/s2n/s2n_tls_channel_handler.c index 8326543e8..af8fbd834 100644 --- a/source/s2n/s2n_tls_channel_handler.c +++ b/source/s2n/s2n_tls_channel_handler.c @@ -270,6 +270,8 @@ bool aws_tls_is_cipher_pref_supported(enum aws_tls_cipher_pref cipher_pref) { #ifndef ANDROID case AWS_IO_TLS_CIPHER_PREF_PQ_TLSv1_0_2021_05: return true; + case AWS_IO_TLS_CIPHER_PREF_PQ_TLSV1_2_2024_10: + return true; #endif default: @@ -1536,6 +1538,9 @@ static struct aws_tls_ctx *s_tls_ctx_new( case AWS_IO_TLS_CIPHER_PREF_PQ_TLSv1_0_2021_05: security_policy = "PQ-TLS-1-0-2021-05-26"; break; + case AWS_IO_TLS_CIPHER_PREF_PQ_TLSV1_2_2024_10: + security_policy = "AWS-CRT-SDK-TLSv1.2-2023-PQ"; + break; default: AWS_LOGF_ERROR(AWS_LS_IO_TLS, "Unrecognized TLS Cipher Preference: %d", options->cipher_pref); aws_raise_error(AWS_IO_TLS_CIPHER_PREF_UNSUPPORTED); From c15417b1f2d6bc3c1d9ee7aac1ed18ae052652c6 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 12 Nov 2024 10:57:13 -0800 Subject: [PATCH 13/18] Update checksum based on previous PR changes (#695) Co-authored-by: Bret Ambrose --- .github/workflows/proof-alarm.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/proof-alarm.yml b/.github/workflows/proof-alarm.yml index b6e34c10c..4e33d77f7 100644 --- a/.github/workflows/proof-alarm.yml +++ b/.github/workflows/proof-alarm.yml @@ -16,7 +16,7 @@ jobs: - name: Check run: | TMPFILE=$(mktemp) - echo "c624a28de5af7f851a240a1e65a26c01 source/linux/epoll_event_loop.c" > $TMPFILE + echo "1fdf8e7a914412cc7242b8d64732fa89 source/linux/epoll_event_loop.c" > $TMPFILE md5sum --check $TMPFILE # No further steps if successful From 51e2d5a5ad64e2666a5de50ab7e84442e34e2c05 Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 10:57:17 -0800 Subject: [PATCH 14/18] 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 15/18] 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 16/18] lint --- include/aws/io/event_loop.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index 4cc428def..bc3f4c03a 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -49,7 +49,8 @@ struct aws_event_loop_vtable { }; /** - * Event Loop Type. If set to `AWS_EVENT_LOOP_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default. + * Event Loop Type. If set to `AWS_EVENT_LOOP_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s + * default. * * Default Event Loop Type * Linux | AWS_EVENT_LOOP_EPOLL From c507d137e25fba8283674a7f89564d771f21930d Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 13:58:50 -0800 Subject: [PATCH 17/18] update comments --- include/aws/io/event_loop.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/aws/io/event_loop.h b/include/aws/io/event_loop.h index fc5af7544..7778edd7d 100644 --- a/include/aws/io/event_loop.h +++ b/include/aws/io/event_loop.h @@ -104,6 +104,8 @@ struct aws_event_loop_group_options { }; /** + * @internal - Don't use outside of testing. + * * Return the default event loop type. If the return value is `AWS_ELT_PLATFORM_DEFAULT`, the function failed to * retrieve the default type value. * If `aws_event_loop_override_default_type` has been called, return the override default type. From c54b99e5fe0c5e15b5144956d595a98847f080cd Mon Sep 17 00:00:00 2001 From: Vera Xia Date: Tue, 12 Nov 2024 14:08:42 -0800 Subject: [PATCH 18/18] rename enum --- source/event_loop.c | 2 +- tests/event_loop_test.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/event_loop.c b/source/event_loop.c index 8d1ba9802..e49515d73 100644 --- a/source/event_loop.c +++ b/source/event_loop.c @@ -588,7 +588,7 @@ void aws_event_loop_override_default_type(enum aws_event_loop_type default_type_ * retrieve the default type value. * If `aws_event_loop_override_default_type` has been called, return the override default type. */ -static enum aws_event_loop_type aws_event_loop_get_default_type(void) { +enum aws_event_loop_type aws_event_loop_get_default_type(void) { if (s_default_event_loop_type_override != AWS_EVENT_LOOP_PLATFORM_DEFAULT) { return s_default_event_loop_type_override; } diff --git a/tests/event_loop_test.c b/tests/event_loop_test.c index 3bd5829b9..6fa75ef02 100644 --- a/tests/event_loop_test.c +++ b/tests/event_loop_test.c @@ -80,7 +80,7 @@ static int s_test_event_loop_xthread_scheduled_tasks_execute(struct aws_allocato // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, // therefore we do not validate the thread id for dispatch queue. - if (aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE) { + if (aws_event_loop_get_default_type() != AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_FALSE(aws_thread_thread_id_equal(task_args.thread_id, aws_thread_current_thread_id())); } @@ -156,7 +156,7 @@ static int s_test_event_loop_canceled_tasks_run_in_el_thread(struct aws_allocato ASSERT_TRUE(task1_args.was_in_thread); // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, // therefore we do not validate the thread id for dispatch queue. - if (aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE) { + if (aws_event_loop_get_default_type() != AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_FALSE(aws_thread_thread_id_equal(task1_args.thread_id, aws_thread_current_thread_id())); } ASSERT_INT_EQUALS(AWS_TASK_STATUS_RUN_READY, task1_args.status); @@ -174,7 +174,7 @@ static int s_test_event_loop_canceled_tasks_run_in_el_thread(struct aws_allocato ASSERT_TRUE(task2_args.was_in_thread); // The dispatch queue will schedule tasks on thread pools, it is unpredicatable which thread we run the task on, // therefore we do not validate the thread id for dispatch queue. - if (aws_event_loop_get_default_type() != AWS_ELT_DISPATCH_QUEUE) { + if (aws_event_loop_get_default_type() != AWS_EVENT_LOOP_DISPATCH_QUEUE) { ASSERT_TRUE(aws_thread_thread_id_equal(task2_args.thread_id, aws_thread_current_thread_id())); } ASSERT_INT_EQUALS(AWS_TASK_STATUS_CANCELED, task2_args.status);