317 lines
11 KiB
C
317 lines
11 KiB
C
#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/io/io.h>
|
||
|
||
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 */
|