Skip to content

Commit

Permalink
Merge branch 'runtime_select_event_loop' of github.com:awslabs/aws-c-…
Browse files Browse the repository at this point in the history
…io into grand_dispatch_queue
  • Loading branch information
xiazhvera committed Nov 12, 2024
2 parents 6b92e59 + 8be6cd2 commit 94f95c1
Show file tree
Hide file tree
Showing 14 changed files with 268 additions and 257 deletions.
6 changes: 1 addition & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,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")

Expand Down Expand Up @@ -220,10 +219,7 @@ if (USE_VSOCK)
endif()

if (AWS_USE_APPLE_NETWORK_FRAMEWORK)
target_compile_definitions(${PROJECT_NAME} PRIVATE "-DAWS_USE_APPLE_NETWORK_FRAMEWORK")
option(AWS_USE_APPLE_NETWORK_FRAMEWORK
"Use apple network framework as default event loop and socket options."
ON)
target_compile_definitions(${PROJECT_NAME} PUBLIC "-DAWS_USE_APPLE_NETWORK_FRAMEWORK")
endif()

target_include_directories(${PROJECT_NAME} PUBLIC
Expand Down
119 changes: 91 additions & 28 deletions include/aws/io/event_loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,58 @@ 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;

/**
* Event Loop Type. If set to `AWS_ELT_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default.
* @internal
*/
typedef void(aws_event_loop_on_event_fn)(
struct aws_event_loop *event_loop,
struct aws_io_handle *handle,
int events,
void *user_data);

/**
* @internal
*/
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 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,
};

/**
Expand All @@ -45,7 +78,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;
Expand All @@ -58,7 +91,7 @@ struct aws_event_loop_group_options {
/**
* Optional configuration to control how the event loop group's threads bind to CPU groups
*/
uint16_t *cpu_group;
const uint16_t *cpu_group;

/**
* Override for the clock function that event loops should use. Defaults to the system's high resolution
Expand Down Expand Up @@ -122,7 +155,7 @@ bool aws_event_loop_thread_is_callers_thread(struct aws_event_loop *event_loop);
* Gets the current timestamp for the event loop's clock, in nanoseconds. This function is thread-safe.
*/
AWS_IO_API
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);

/**
* Creation function for event loop groups.
Expand Down Expand Up @@ -157,7 +190,7 @@ struct aws_event_loop *aws_event_loop_group_get_loop_at(struct aws_event_loop_gr
* Gets the number of event loops managed by an event loop group.
*/
AWS_IO_API
size_t aws_event_loop_group_get_loop_count(struct aws_event_loop_group *el_group);
size_t aws_event_loop_group_get_loop_count(const struct aws_event_loop_group *el_group);

/**
* Fetches the next loop for use. The purpose is to enable load balancing across loops. You should not depend on how
Expand All @@ -168,10 +201,6 @@ AWS_IO_API
struct aws_event_loop *aws_event_loop_group_get_next_loop(struct aws_event_loop_group *el_group);

/**
* Initializes an event loop group with platform defaults. If max_threads == 0, then the
* loop count will be the number of available processors on the machine / 2 (to exclude hyper-threads).
* Otherwise, max_threads will be the number of event loops in the group.
*
* @deprecated - use aws_event_loop_group_new() instead
*/
AWS_IO_API
Expand All @@ -180,15 +209,7 @@ 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
Expand All @@ -198,6 +219,48 @@ 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);

/**
* @internal - Don't use outside of testing.
*
* Returns the opaque internal user data of an event loop. Can be cast into a specific implementation by
* privileged consumers.
*/
AWS_IO_API
void *aws_event_loop_get_impl(struct aws_event_loop *event_loop);

/**
* @internal - Don't use outside of testing.
*
* Initializes the base structure used by all event loop implementations with test-oriented overrides.
*/
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);

/**
* @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
void aws_event_loop_clean_up_base(struct aws_event_loop *event_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
void aws_event_loop_destroy(struct aws_event_loop *event_loop);

AWS_EXTERN_C_END

AWS_POP_SANE_WARNING_LEVEL
Expand Down
64 changes: 3 additions & 61 deletions include/aws/io/private/event_loop_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <aws/common/atomics.h>
#include <aws/common/hash_table.h>
#include <aws/common/ref_count.h>
#include <aws/io/event_loop.h>

AWS_PUSH_SANE_WARNING_LEVEL

Expand Down Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -117,25 +92,21 @@ 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;
};

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);
Expand Down Expand Up @@ -217,31 +188,9 @@ struct aws_event_loop *aws_event_loop_new_default(struct aws_allocator *alloc, a
/**
* Creates an instance of the default event loop implementation for the current architecture and operating system using
* extendable options.
*
* Please note the event loop type defined in the options will be ignored.
*/
AWS_IO_API
struct aws_event_loop *aws_event_loop_new_default_with_options(
struct aws_allocator *alloc,
const struct aws_event_loop_options *options);

/**
* Creates an instance of the event loop implementation from the options.
*/
AWS_IO_API
struct aws_event_loop *aws_event_loop_new_with_options(
struct aws_allocator *alloc,
const struct aws_event_loop_options *options);

/**
* Invokes the destroy() fn for the event loop implementation.
* If the event loop is still in a running state, this function will block waiting on the event loop to shutdown.
* 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);
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.
Expand All @@ -250,13 +199,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.
Expand Down
33 changes: 17 additions & 16 deletions include/aws/io/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
* 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_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
Expand Down Expand Up @@ -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.
Expand All @@ -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);
Expand Down Expand Up @@ -205,17 +206,17 @@ aws_ms_fn_ptr aws_winsock_get_connectex_fn(void);
aws_ms_fn_ptr aws_winsock_get_acceptex_fn(void);
#endif

AWS_IO_API int aws_socket_init_posix(
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);
Expand Down
Loading

0 comments on commit 94f95c1

Please sign in to comment.