Skip to content

Commit 3d164ff

Browse files
authored
Acquire/Release Event Loop (#725)
1 parent 7c00720 commit 3d164ff

File tree

14 files changed

+179
-77
lines changed

14 files changed

+179
-77
lines changed

.github/workflows/proof-alarm.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Check
1717
run: |
1818
TMPFILE=$(mktemp)
19-
echo "64a05aa7dfecba86bf4296a08b4cdf3a source/linux/epoll_event_loop.c" > $TMPFILE
19+
echo "5109c3b2748a98621ebdc05756fdfa51 source/linux/epoll_event_loop.c" > $TMPFILE
2020
md5sum --check $TMPFILE
2121
2222
# No further steps if successful

include/aws/io/event_loop.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ struct aws_event_loop_vtable {
4646
void *user_data);
4747
int (*unsubscribe_from_io_events)(struct aws_event_loop *event_loop, struct aws_io_handle *handle);
4848
void (*free_io_event_resources)(void *user_data);
49-
void *(*get_base_event_loop_group)(struct aws_event_loop *event_loop);
5049
bool (*is_on_callers_thread)(struct aws_event_loop *event_loop);
5150
};
5251

@@ -175,6 +174,22 @@ struct aws_event_loop_group *aws_event_loop_group_acquire(struct aws_event_loop_
175174
AWS_IO_API
176175
void aws_event_loop_group_release(struct aws_event_loop_group *el_group);
177176

177+
/**
178+
* Increments the reference count on the event loop group from event loop, allowing the caller to take a reference to
179+
* it.
180+
*
181+
* Returns the base event loop group of the event loop, or null if the event loop does not belong to a group.
182+
*/
183+
AWS_IO_API
184+
struct aws_event_loop_group *aws_event_loop_group_acquire_from_event_loop(struct aws_event_loop *event_loop);
185+
186+
/**
187+
* Decrements the ref count of the event loop's base event loop group. When the ref count drops to zero, the event loop
188+
* group will be destroyed.
189+
*/
190+
AWS_IO_API
191+
void aws_event_loop_group_release_from_event_loop(struct aws_event_loop *event_loop);
192+
178193
/**
179194
* Returns the event loop at a particular index. If the index is out of bounds, null is returned.
180195
*/

include/aws/io/private/event_loop_impl.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct aws_event_loop {
7575
uint64_t latest_tick_start;
7676
size_t current_tick_latency_sum;
7777
struct aws_atomic_var next_flush_time;
78+
struct aws_event_loop_group *base_elg;
7879
void *impl_data;
7980
};
8081

@@ -321,14 +322,6 @@ int aws_event_loop_unsubscribe_from_io_events(struct aws_event_loop *event_loop,
321322
AWS_IO_API
322323
void aws_event_loop_free_io_event_resources(struct aws_event_loop *event_loop, struct aws_io_handle *handle);
323324

324-
/**
325-
* Retrieves the aws_event_loop_group that is the parent of the aws_event_loop. This is only supported when using a
326-
* dispatch queue event loop as they are async and their sockets need to retain a refcount on the elg to keep it alive
327-
* and insure it has not been asyncronously destroyed before anything that needs it.
328-
*/
329-
AWS_IO_API
330-
void *get_base_event_loop_group(struct aws_event_loop *event_loop);
331-
332325
AWS_IO_API
333326
struct aws_event_loop_group *aws_event_loop_group_new_internal(
334327
struct aws_allocator *allocator,

source/bsd/kqueue_event_loop.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,7 @@ static int s_subscribe_to_io_events(
4949
void *user_data);
5050
static int s_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struct aws_io_handle *handle);
5151
static void s_free_io_event_resources(void *user_data);
52-
static void *s_get_base_event_loop_group(struct aws_event_loop *event_loop) {
53-
(void)event_loop;
54-
AWS_LOGF_ERROR(
55-
AWS_LS_IO_EVENT_LOOP,
56-
"id=%p: get_base_event_loop_group() is not supported using KQueue Event Loops",
57-
(void *)event_loop);
58-
aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED);
59-
return NULL;
60-
}
52+
6153
static bool s_is_event_thread(struct aws_event_loop *event_loop);
6254

6355
static void aws_event_loop_thread(void *user_data);
@@ -148,7 +140,6 @@ struct aws_event_loop_vtable s_kqueue_vtable = {
148140
.subscribe_to_io_events = s_subscribe_to_io_events,
149141
.unsubscribe_from_io_events = s_unsubscribe_from_io_events,
150142
.free_io_event_resources = s_free_io_event_resources,
151-
.get_base_event_loop_group = s_get_base_event_loop_group,
152143
.is_on_callers_thread = s_is_event_thread,
153144
};
154145

@@ -275,6 +266,8 @@ struct aws_event_loop *aws_event_loop_new_with_kqueue(
275266

276267
event_loop->vtable = &s_kqueue_vtable;
277268

269+
event_loop->base_elg = options->parent_elg;
270+
278271
/* success */
279272
return event_loop;
280273

source/channel.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@ struct aws_channel *aws_channel_new(struct aws_allocator *alloc, const struct aw
257257
setup_args->on_setup_completed = creation_args->on_setup_completed;
258258
setup_args->user_data = creation_args->setup_user_data;
259259

260+
/* keep loop alive until channel is destroyed */
261+
channel->loop = creation_args->event_loop;
262+
aws_event_loop_group_acquire_from_event_loop(channel->loop);
263+
260264
aws_task_init(&setup_args->task, s_on_channel_setup_complete, setup_args, "on_channel_setup_complete");
261265
aws_event_loop_schedule_task_now(creation_args->event_loop, &setup_args->task);
262266

@@ -308,6 +312,8 @@ static void s_final_channel_deletion_task(struct aws_task *task, void *arg, enum
308312

309313
aws_channel_set_statistics_handler(channel, NULL);
310314

315+
aws_event_loop_group_release_from_event_loop(channel->loop);
316+
311317
aws_mem_release(channel->alloc, channel);
312318
}
313319

source/darwin/dispatch_queue_event_loop.c

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ static void s_free_io_event_resources(void *user_data) {
6464
/* No io event resources to free */
6565
(void)user_data;
6666
}
67-
static void *s_get_base_event_loop_group(struct aws_event_loop *event_loop);
6867
static bool s_is_on_callers_thread(struct aws_event_loop *event_loop);
6968

7069
static struct aws_event_loop_vtable s_vtable = {
@@ -80,7 +79,6 @@ static struct aws_event_loop_vtable s_vtable = {
8079
.subscribe_to_io_events = s_subscribe_to_io_events,
8180
.unsubscribe_from_io_events = s_unsubscribe_from_io_events,
8281
.free_io_event_resources = s_free_io_event_resources,
83-
.get_base_event_loop_group = s_get_base_event_loop_group,
8482
.is_on_callers_thread = s_is_on_callers_thread,
8583
};
8684

@@ -249,12 +247,12 @@ struct aws_event_loop *aws_event_loop_new_with_dispatch_queue(
249247
}
250248

251249
loop->vtable = &s_vtable;
250+
loop->base_elg = options->parent_elg;
252251

253252
dispatch_loop = aws_mem_calloc(alloc, 1, sizeof(struct aws_dispatch_loop));
254253
dispatch_loop->allocator = alloc;
255254
loop->impl_data = dispatch_loop;
256255
dispatch_loop->base_loop = loop;
257-
dispatch_loop->base_elg = options->parent_elg;
258256
dispatch_loop->synced_data.execution_state = AWS_DLES_SUSPENDED;
259257
aws_ref_count_init(&dispatch_loop->ref_count, dispatch_loop, s_dispatch_event_loop_on_zero_ref_count);
260258

@@ -740,17 +738,6 @@ static int s_connect_to_io_completion_port(struct aws_event_loop *event_loop, st
740738
return AWS_OP_SUCCESS;
741739
}
742740

743-
/*
744-
* Because dispatch queue is async we may need to acquire a refcount of the parent event loop group to prevent
745-
* the event loop or dispatch loop from being cleaned out from underneath something that needs it. We expose the
746-
* base elg so anything that needs to insure the event loops and dispatch loops don't get prematurely cleaned can
747-
* hold a refcount.
748-
*/
749-
static void *s_get_base_event_loop_group(struct aws_event_loop *event_loop) {
750-
struct aws_dispatch_loop *dispatch_loop = event_loop->impl_data;
751-
return dispatch_loop->base_elg;
752-
}
753-
754741
/*
755742
* We use aws_thread_id_equal with syched_data.current_thread_id and synced_data.is_executing to determine
756743
* if operation is being executed on the same dispatch queue thread.

source/darwin/dispatch_queue_event_loop_private.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ struct aws_dispatch_loop {
3535
dispatch_queue_t dispatch_queue;
3636
struct aws_task_scheduler scheduler;
3737
struct aws_event_loop *base_loop;
38-
struct aws_event_loop_group *base_elg;
3938

4039
struct aws_ref_count ref_count;
4140

source/darwin/nw_socket.c

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -412,19 +412,28 @@ static bool s_validate_event_loop(struct aws_event_loop *event_loop) {
412412
return event_loop && event_loop->vtable && event_loop->impl_data;
413413
}
414414

415-
static void s_set_event_loop(struct aws_socket *aws_socket, struct aws_event_loop *event_loop) {
415+
static int s_set_event_loop(struct aws_socket *aws_socket, struct aws_event_loop *event_loop) {
416416
aws_socket->event_loop = event_loop;
417417
struct nw_socket *nw_socket = aws_socket->impl;
418418
// Never re-assign an event loop
419419
AWS_FATAL_ASSERT(nw_socket->event_loop == NULL);
420-
nw_socket->event_loop = event_loop;
421420

421+
// Acquire the event loop group from the event loop. The event loop group will be released when the socket is
422+
// destroyed.
423+
if (!aws_event_loop_group_acquire_from_event_loop(event_loop)) {
424+
AWS_LOGF_ERROR(
425+
AWS_LS_IO_SOCKET,
426+
"id=%p nw_socket=%p: failed to acquire event loop group.",
427+
(void *)aws_socket,
428+
(void *)nw_socket);
429+
return AWS_OP_ERR;
430+
}
431+
432+
nw_socket->event_loop = event_loop;
422433
AWS_LOGF_DEBUG(
423-
AWS_LS_IO_SOCKET,
424-
"id=%p nw_socket=%p: s_set_event_loop: socket acquire event loop group.",
425-
(void *)aws_socket,
426-
(void *)nw_socket);
427-
aws_event_loop_group_acquire(get_base_event_loop_group(event_loop));
434+
AWS_LS_IO_SOCKET, "id=%p nw_socket=%p: nw_socket set event loop.", (void *)aws_socket, (void *)nw_socket);
435+
436+
return AWS_OP_SUCCESS;
428437
}
429438

430439
static void s_release_event_loop(struct nw_socket *nw_socket) {
@@ -433,7 +442,7 @@ static void s_release_event_loop(struct nw_socket *nw_socket) {
433442
AWS_LS_IO_SOCKET, "nw_socket=%p: s_release_event_loop: socket has not event loop.", (void *)nw_socket);
434443
return;
435444
}
436-
aws_event_loop_group_release(get_base_event_loop_group(nw_socket->event_loop));
445+
aws_event_loop_group_release_from_event_loop(nw_socket->event_loop);
437446
AWS_LOGF_DEBUG(
438447
AWS_LS_IO_SOCKET, "nw_socket=%p: s_release_event_loop: socket release event loop group.", (void *)nw_socket);
439448
nw_socket->event_loop = NULL;
@@ -1798,7 +1807,10 @@ static int s_socket_connect_fn(struct aws_socket *socket, struct aws_socket_conn
17981807
}
17991808

18001809
/* event_loop must be set prior to setup of socket parameters. */
1801-
s_set_event_loop(socket, event_loop);
1810+
if (s_set_event_loop(socket, event_loop)) {
1811+
goto error;
1812+
}
1813+
18021814
if (s_setup_socket_params(nw_socket, &socket->options)) {
18031815
goto error;
18041816
}
@@ -2316,15 +2328,25 @@ static int s_socket_start_accept_fn(
23162328
return aws_raise_error(AWS_IO_EVENT_LOOP_ALREADY_ASSIGNED);
23172329
}
23182330

2331+
if (s_set_event_loop(socket, accept_loop)) {
2332+
AWS_LOGF_ERROR(
2333+
AWS_LS_IO_SOCKET,
2334+
"id=%p handle=%p: failed to set event loop %p, invalid event loop. It is most likely the event loop does "
2335+
"not has a parent event loop group.",
2336+
(void *)socket,
2337+
socket->io_handle.data.handle,
2338+
(void *)accept_loop);
2339+
s_unlock_socket_synced_data(nw_socket);
2340+
return aws_raise_error(AWS_IO_SOCKET_INVALID_OPTIONS);
2341+
}
2342+
23192343
aws_event_loop_connect_handle_to_io_completion_port(accept_loop, &socket->io_handle);
23202344
socket->accept_result_fn = options.on_accept_result;
23212345
socket->connect_accept_user_data = options.on_accept_result_user_data;
23222346

23232347
nw_socket->on_accept_started_fn = options.on_accept_start;
23242348
nw_socket->listen_accept_started_user_data = options.on_accept_start_user_data;
23252349

2326-
s_set_event_loop(socket, accept_loop);
2327-
23282350
nw_listener_set_state_changed_handler(
23292351
socket->io_handle.data.handle, ^(nw_listener_state_t state, nw_error_t error) {
23302352
s_handle_listener_state_changed_fn(nw_socket, state, error);
@@ -2433,9 +2455,20 @@ static int s_socket_assign_to_event_loop_fn(struct aws_socket *socket, struct aw
24332455
socket->io_handle.data.handle,
24342456
(void *)event_loop);
24352457

2436-
if (aws_event_loop_connect_handle_to_io_completion_port(event_loop, &socket->io_handle)) {
2458+
if (s_set_event_loop(socket, event_loop)) {
2459+
AWS_LOGF_ERROR(
2460+
AWS_LS_IO_SOCKET,
2461+
"id=%p handle=%p: assigning event loop %p failed. Invalid event loop. It is likely the event loop "
2462+
"does not has a parent event loop group.",
2463+
(void *)socket,
2464+
socket->io_handle.data.handle,
2465+
(void *)event_loop);
2466+
aws_raise_error(AWS_IO_SOCKET_INVALID_OPTIONS);
2467+
return AWS_IO_SOCKET_INVALID_OPTIONS;
2468+
}
24372469

2438-
AWS_LOGF_DEBUG(
2470+
if (aws_event_loop_connect_handle_to_io_completion_port(event_loop, &socket->io_handle)) {
2471+
AWS_LOGF_ERROR(
24392472
AWS_LS_IO_SOCKET,
24402473
"id=%p handle=%p: assigning event loop %p failed",
24412474
(void *)socket,
@@ -2444,7 +2477,6 @@ static int s_socket_assign_to_event_loop_fn(struct aws_socket *socket, struct aw
24442477
return AWS_OP_ERR;
24452478
}
24462479

2447-
s_set_event_loop(socket, event_loop);
24482480
nw_connection_start(socket->io_handle.data.handle);
24492481
return AWS_OP_SUCCESS;
24502482
}

source/event_loop.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,19 @@ void aws_event_loop_group_release(struct aws_event_loop_group *el_group) {
380380
}
381381
}
382382

383+
struct aws_event_loop_group *aws_event_loop_group_acquire_from_event_loop(struct aws_event_loop *event_loop) {
384+
if (event_loop != NULL) {
385+
return aws_event_loop_group_acquire(event_loop->base_elg);
386+
}
387+
return NULL;
388+
}
389+
390+
void aws_event_loop_group_release_from_event_loop(struct aws_event_loop *event_loop) {
391+
if (event_loop != NULL) {
392+
aws_event_loop_group_release(event_loop->base_elg);
393+
}
394+
}
395+
383396
size_t aws_event_loop_group_get_loop_count(const struct aws_event_loop_group *el_group) {
384397
return aws_array_list_length(&el_group->event_loops);
385398
}
@@ -655,11 +668,6 @@ void aws_event_loop_free_io_event_resources(struct aws_event_loop *event_loop, s
655668
event_loop->vtable->free_io_event_resources(handle->additional_data);
656669
}
657670

658-
void *get_base_event_loop_group(struct aws_event_loop *event_loop) {
659-
AWS_ASSERT(event_loop && event_loop->vtable->get_base_event_loop_group);
660-
return event_loop->vtable->get_base_event_loop_group(event_loop);
661-
}
662-
663671
bool aws_event_loop_thread_is_callers_thread(struct aws_event_loop *event_loop) {
664672
AWS_ASSERT(event_loop->vtable && event_loop->vtable->is_on_callers_thread);
665673
return event_loop->vtable->is_on_callers_thread(event_loop);

source/linux/epoll_event_loop.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,6 @@ static int s_subscribe_to_io_events(
6868
void *user_data);
6969
static int s_unsubscribe_from_io_events(struct aws_event_loop *event_loop, struct aws_io_handle *handle);
7070
static void s_free_io_event_resources(void *user_data);
71-
static void *s_get_base_event_loop_group(struct aws_event_loop *event_loop) {
72-
(void)event_loop;
73-
AWS_LOGF_ERROR(
74-
AWS_LS_IO_EVENT_LOOP,
75-
"id=%p: get_base_event_loop_group() is not supported using Epoll Event Loops",
76-
(void *)event_loop);
77-
aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED);
78-
return NULL;
79-
}
8071
static bool s_is_on_callers_thread(struct aws_event_loop *event_loop);
8172

8273
static void aws_event_loop_thread(void *args);
@@ -94,7 +85,6 @@ static struct aws_event_loop_vtable s_vtable = {
9485
.subscribe_to_io_events = s_subscribe_to_io_events,
9586
.unsubscribe_from_io_events = s_unsubscribe_from_io_events,
9687
.free_io_event_resources = s_free_io_event_resources,
97-
.get_base_event_loop_group = s_get_base_event_loop_group,
9888
.is_on_callers_thread = s_is_on_callers_thread,
9989
};
10090

@@ -218,6 +208,7 @@ struct aws_event_loop *aws_event_loop_new_with_epoll(
218208

219209
loop->impl_data = epoll_loop;
220210
loop->vtable = &s_vtable;
211+
loop->base_elg = options->parent_elg;
221212

222213
return loop;
223214

0 commit comments

Comments
 (0)