Skip to content

Commit

Permalink
Merge branch 'EventLoopPublicApi' of github.com:awslabs/aws-c-io into…
Browse files Browse the repository at this point in the history
… runtime_select_event_loop
  • Loading branch information
xiazhvera committed Nov 11, 2024
2 parents 3999196 + d68acdb commit 6f1984c
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 66 deletions.
68 changes: 68 additions & 0 deletions include/aws/io/event_loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 Type. If set to `AWS_ELT_PLATFORM_DEFAULT`, the event loop will automatically use the platform’s default.
*
Expand Down Expand Up @@ -190,6 +216,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);

/**
* 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,
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.
*
* @internal - Don't use outside of testing.
*/
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.
*
* @internal - Don't use outside of testing.
*/
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
52 changes: 1 addition & 51 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 Down Expand Up @@ -225,38 +200,13 @@ 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);

/**
* 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.
Expand Down
28 changes: 13 additions & 15 deletions include/aws/testing/io_testing_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
#include <aws/io/channel.h>
#include <aws/io/event_loop.h>
#include <aws/io/logging.h>
#include <aws/io/private/event_loop_impl.h>
// #include <aws/io/private/event_loop_impl.h>
#include <aws/io/statistics.h>
#include <aws/testing/aws_test_harness.h>

struct testing_loop {
struct aws_allocator *allocator;
struct aws_task_scheduler scheduler;
bool mock_on_callers_thread;
};
Expand All @@ -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);
}

Expand All @@ -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 = {
Expand All @@ -77,16 +79,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));
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;
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)(
Expand Down Expand Up @@ -394,7 +392,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,
Expand Down
17 changes: 17 additions & 0 deletions source/event_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,3 +694,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;
}

0 comments on commit 6f1984c

Please sign in to comment.