#ifndef AWS_IO_EVENT_LOOP_H #define AWS_IO_EVENT_LOOP_H /** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ #include 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; /** * @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 (*start_destroy)(struct aws_event_loop *event_loop); void (*complete_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_now_serialized)(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_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_EVENT_LOOP_PLATFORM_DEFAULT = 0, AWS_EVENT_LOOP_EPOLL, AWS_EVENT_LOOP_IOCP, AWS_EVENT_LOOP_KQUEUE, AWS_EVENT_LOOP_DISPATCH_QUEUE, }; /** * Event loop group configuration options */ struct aws_event_loop_group_options { /** * How many event loops that event loop group should contain. For most group types, this implies * the creation and management of an analagous amount of managed threads */ uint16_t loop_count; /** * 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; /** * Optional callback to invoke when the event loop group finishes destruction. */ const struct aws_shutdown_callback_options *shutdown_options; /** * Optional configuration to control how the event loop group's threads bind to CPU groups */ const uint16_t *cpu_group; /** * Override for the clock function that event loops should use. Defaults to the system's high resolution * timer. * * Do not bind this value to managed code; it is only used in timing-sensitive tests. */ aws_io_clock_fn *clock_override; }; AWS_EXTERN_C_BEGIN /** * The event loop will schedule the task and run it on the event loop thread as soon as possible. * Note that cancelled tasks may execute outside the event loop thread. * This function may be called from outside or inside the event loop thread. * * The task should not be cleaned up or modified until its function is executed. */ AWS_IO_API void aws_event_loop_schedule_task_now(struct aws_event_loop *event_loop, struct aws_task *task); /** * Variant of aws_event_loop_schedule_task_now that forces all tasks to go through the cross thread task queue, * guaranteeing that order-of-submission is order-of-execution. If you need this guarantee, you must use this * function; the base function contains short-circuiting logic that breaks ordering invariants. Beyond that, all * properties of aws_event_loop_schedule_task_now apply to this function as well. * * Serialization guarantee does not apply to task cancellation (which can occur out-of-order or even out-of-thread in * certain cases). */ AWS_IO_API void aws_event_loop_schedule_task_now_serialized(struct aws_event_loop *event_loop, struct aws_task *task); /** * The event loop will schedule the task and run it at the specified time. * Use aws_event_loop_current_clock_time() to query the current time in nanoseconds. * Note that cancelled tasks may execute outside the event loop thread. * This function may be called from outside or inside the event loop thread. * * The task should not be cleaned up or modified until its function is executed. */ AWS_IO_API void aws_event_loop_schedule_task_future( struct aws_event_loop *event_loop, struct aws_task *task, uint64_t run_at_nanos); /** * Cancels task. * This function must be called from the event loop's thread, and is only guaranteed * to work properly on tasks scheduled from within the event loop's thread. * The task will be executed with the AWS_TASK_STATUS_CANCELED status inside this call. */ AWS_IO_API void aws_event_loop_cancel_task(struct aws_event_loop *event_loop, struct aws_task *task); /** * Returns true if the event loop's thread is the same thread that called this function, otherwise false. */ AWS_IO_API 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(const struct aws_event_loop *event_loop, uint64_t *time_nanos); /** * Creation function for event loop groups. */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new( struct aws_allocator *allocator, const struct aws_event_loop_group_options *options); /** * Increments the reference count on the event loop group, allowing the caller to take a reference to it. * * Returns the same event loop group passed in. */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_group *el_group); /** * 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 void aws_event_loop_group_release(struct aws_event_loop_group *el_group); /** * Increments the reference count on the event loop group from event loop, allowing the caller to take a reference to * it. * * Returns the base event loop group of the event loop, or null if the event loop does not belong to a group. */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_acquire_from_event_loop(struct aws_event_loop *event_loop); /** * Decrements the ref count of the event loop's base event loop group. When the ref count drops to zero, the event loop * group will be destroyed. */ AWS_IO_API void aws_event_loop_group_release_from_event_loop(struct aws_event_loop *event_loop); /** * Returns the event loop at a particular index. If the index is out of bounds, null is returned. */ AWS_IO_API struct aws_event_loop *aws_event_loop_group_get_loop_at(struct aws_event_loop_group *el_group, size_t index); /** * Gets the number of event loops managed by an event loop group. */ AWS_IO_API size_t aws_event_loop_group_get_loop_count(const struct aws_event_loop_group *el_group); /** * Gets the event loop type used by an event loop group. */ AWS_IO_API enum aws_event_loop_type aws_event_loop_group_get_type(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 * 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 *aws_event_loop_group_get_next_loop(struct aws_event_loop_group *el_group); /** * @deprecated - use aws_event_loop_group_new() instead */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new_default( struct aws_allocator *alloc, uint16_t max_threads, const struct aws_shutdown_callback_options *shutdown_options); /** * @deprecated - use aws_event_loop_group_new() instead */ AWS_IO_API struct aws_event_loop_group *aws_event_loop_group_new_default_pinned_to_cpu_group( struct aws_allocator *alloc, uint16_t max_threads, uint16_t cpu_group, const struct aws_shutdown_callback_options *shutdown_options); /** * @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. * * Destroys an 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 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. * * Internally, this calls aws_event_loop_start_destroy() followed by aws_event_loop_complete_destroy() */ AWS_IO_API void aws_event_loop_destroy(struct aws_event_loop *event_loop); /** * @internal * * Signals an event loop to begin its destruction process. If an event loop's implementation of this API does anything, * it must be quick and non-blocking. Most event loop implementations have an empty implementation for this function. */ AWS_IO_API void aws_event_loop_start_destroy(struct aws_event_loop *event_loop); /** * @internal * * Waits for an event loop to complete its destruction process. aws_event_loop_start_destroy() must have been called * previously for this function to not deadlock. */ AWS_IO_API void aws_event_loop_complete_destroy(struct aws_event_loop *event_loop); AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL #endif /* AWS_IO_EVENT_LOOP_H */