Skip to content

Commit 8f706b2

Browse files
authored
Ref (#284)
* rework ref-counting and async shutdown for a number of core types and their dependents
1 parent 98b3e49 commit 8f706b2

File tree

9 files changed

+80
-166
lines changed

9 files changed

+80
-166
lines changed

.tsan_suppressions.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# threads created here are not explicitly joined but they are part of a ref-count mechanism that
2+
# decrements (with a possible signal of a shutdown callback based on state and count) on thread
3+
# exit function. For now, there is no reasonable way to integrate thread join into the host resolver
4+
# logic, and so this is a false positive.
5+
thread:create_and_init_host_entry

bin/elasticurl/main.c

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ struct elasticurl_ctx {
6464
enum aws_log_level log_level;
6565
enum aws_http_version required_http_version;
6666
bool exchange_completed;
67-
bool bootstrap_shutdown_completed;
6867
};
6968

7069
static void s_usage(int exit_code) {
@@ -539,20 +538,6 @@ static bool s_completion_predicate(void *arg) {
539538
return app_ctx->exchange_completed;
540539
}
541540

542-
static void s_bootstrap_on_shutdown(void *user_data) {
543-
struct elasticurl_ctx *app_ctx = user_data;
544-
545-
aws_mutex_lock(&app_ctx->mutex);
546-
app_ctx->bootstrap_shutdown_completed = true;
547-
aws_mutex_unlock(&app_ctx->mutex);
548-
aws_condition_variable_notify_all(&app_ctx->c_var);
549-
}
550-
551-
static bool s_bootstrap_shutdown_predicate(void *arg) {
552-
struct elasticurl_ctx *app_ctx = arg;
553-
return app_ctx->bootstrap_shutdown_completed;
554-
}
555-
556541
int main(int argc, char **argv) {
557542
struct aws_allocator *allocator = aws_default_allocator();
558543

@@ -690,17 +675,12 @@ int main(int argc, char **argv) {
690675
}
691676
}
692677

693-
struct aws_event_loop_group el_group;
694-
aws_event_loop_group_default_init(&el_group, allocator, 1);
695-
696-
struct aws_host_resolver resolver;
697-
aws_host_resolver_init_default(&resolver, allocator, 8, &el_group);
678+
struct aws_event_loop_group *el_group = aws_event_loop_group_new_default(allocator, 1, NULL);
679+
struct aws_host_resolver *resolver = aws_host_resolver_new_default(allocator, 8, el_group, NULL);
698680

699681
struct aws_client_bootstrap_options bootstrap_options = {
700-
.event_loop_group = &el_group,
701-
.host_resolver = &resolver,
702-
.on_shutdown_complete = s_bootstrap_on_shutdown,
703-
.user_data = &app_ctx,
682+
.event_loop_group = el_group,
683+
.host_resolver = resolver,
704684
};
705685
struct aws_client_bootstrap *bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
706686

@@ -731,16 +711,17 @@ int main(int argc, char **argv) {
731711
aws_mutex_unlock(&app_ctx.mutex);
732712

733713
aws_client_bootstrap_release(bootstrap);
734-
aws_mutex_lock(&app_ctx.mutex);
735-
aws_condition_variable_wait_pred(&app_ctx.c_var, &app_ctx.mutex, s_bootstrap_shutdown_predicate, &app_ctx);
736-
aws_mutex_unlock(&app_ctx.mutex);
714+
aws_host_resolver_release(resolver);
715+
aws_event_loop_group_release(el_group);
737716

738-
aws_host_resolver_clean_up(&resolver);
739-
aws_event_loop_group_clean_up(&el_group);
717+
if (aws_global_thread_creator_shutdown_wait_for(5)) {
718+
fprintf(stderr, "Timeout waiting for thread shutdown!");
719+
exit(1);
720+
}
740721

741722
if (tls_ctx) {
742723
aws_tls_connection_options_clean_up(&tls_connection_options);
743-
aws_tls_ctx_destroy(tls_ctx);
724+
aws_tls_ctx_release(tls_ctx);
744725
aws_tls_ctx_options_clean_up(&tls_ctx_options);
745726
}
746727

source/connection.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,9 @@ static void s_http_server_clean_up(struct aws_http_server *server) {
506506
if (!server) {
507507
return;
508508
}
509+
510+
aws_server_bootstrap_release(server->bootstrap);
511+
509512
/* invoke the user callback */
510513
if (server->on_destroy_complete) {
511514
server->on_destroy_complete(server->user_data);
@@ -578,7 +581,7 @@ struct aws_http_server *aws_http_server_new(const struct aws_http_server_options
578581
}
579582

580583
server->alloc = options->allocator;
581-
server->bootstrap = options->bootstrap;
584+
server->bootstrap = aws_server_bootstrap_acquire(options->bootstrap);
582585
server->is_using_tls = options->tls_options != NULL;
583586
server->initial_window_size = options->initial_window_size;
584587
server->user_data = options->server_user_data;

source/connection_manager.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,8 @@ static void s_aws_http_connection_manager_finish_destroy(struct aws_http_connect
648648

649649
aws_mutex_clean_up(&manager->lock);
650650

651+
aws_client_bootstrap_release(manager->bootstrap);
652+
651653
if (manager->shutdown_complete_callback) {
652654
manager->shutdown_complete_callback(manager->shutdown_complete_user_data);
653655
}
@@ -815,7 +817,7 @@ struct aws_http_connection_manager *aws_http_connection_manager_new(
815817
manager->port = options->port;
816818
manager->max_connections = options->max_connections;
817819
manager->socket_options = *options->socket_options;
818-
manager->bootstrap = options->bootstrap;
820+
manager->bootstrap = aws_client_bootstrap_acquire(options->bootstrap);
819821
manager->system_vtable = g_aws_http_connection_manager_default_system_vtable_ptr;
820822
manager->external_ref_count = 1;
821823
manager->shutdown_complete_callback = options->shutdown_complete_callback;

tests/proxy_test_helper.c

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,6 @@ void proxy_tester_on_client_connection_shutdown(
6262
aws_condition_variable_notify_one(&tester->wait_cvar);
6363
}
6464

65-
void proxy_tester_on_client_bootstrap_shutdown(void *user_data) {
66-
struct proxy_tester *tester = user_data;
67-
AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
68-
69-
tester->client_bootstrap_is_shutdown = true;
70-
71-
AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
72-
aws_condition_variable_notify_one(&tester->wait_cvar);
73-
}
74-
7565
int proxy_tester_wait(struct proxy_tester *tester, bool (*pred)(void *user_data)) {
7666
ASSERT_SUCCESS(aws_mutex_lock(&tester->wait_lock));
7767
ASSERT_SUCCESS(aws_condition_variable_wait_pred(&tester->wait_cvar, &tester->wait_lock, pred, tester));
@@ -95,11 +85,6 @@ bool proxy_tester_request_complete_pred_fn(void *user_data) {
9585
return tester->request_complete || tester->client_connection_is_shutdown;
9686
}
9787

98-
bool proxy_tester_client_bootstrap_shutdown_pred(void *user_data) {
99-
struct proxy_tester *tester = user_data;
100-
return tester->client_bootstrap_is_shutdown;
101-
}
102-
10388
int proxy_tester_init(struct proxy_tester *tester, const struct proxy_tester_options *options) {
10489
AWS_ZERO_STRUCT(*tester);
10590

@@ -126,8 +111,8 @@ int proxy_tester_init(struct proxy_tester *tester, const struct proxy_tester_opt
126111
ASSERT_SUCCESS(aws_mutex_init(&tester->wait_lock));
127112
ASSERT_SUCCESS(aws_condition_variable_init(&tester->wait_cvar));
128113

129-
ASSERT_SUCCESS(aws_event_loop_group_default_init(&tester->event_loop_group, tester->alloc, 1));
130-
ASSERT_SUCCESS(aws_host_resolver_init_default(&tester->host_resolver, tester->alloc, 8, &tester->event_loop_group));
114+
tester->event_loop_group = aws_event_loop_group_new_default(tester->alloc, 1, NULL);
115+
tester->host_resolver = aws_host_resolver_new_default(tester->alloc, 8, tester->event_loop_group, NULL);
131116

132117
struct aws_socket_options socket_options = {
133118
.type = AWS_SOCKET_STREAM,
@@ -137,10 +122,8 @@ int proxy_tester_init(struct proxy_tester *tester, const struct proxy_tester_opt
137122
};
138123

139124
struct aws_client_bootstrap_options bootstrap_options = {
140-
.event_loop_group = &tester->event_loop_group,
141-
.host_resolver = &tester->host_resolver,
142-
.on_shutdown_complete = proxy_tester_on_client_bootstrap_shutdown,
143-
.user_data = tester,
125+
.event_loop_group = tester->event_loop_group,
126+
.host_resolver = tester->host_resolver,
144127
};
145128
tester->client_bootstrap = aws_client_bootstrap_new(tester->alloc, &bootstrap_options);
146129
ASSERT_NOT_NULL(tester->client_bootstrap);
@@ -206,14 +189,14 @@ int proxy_tester_clean_up(struct proxy_tester *tester) {
206189
}
207190

208191
aws_client_bootstrap_release(tester->client_bootstrap);
209-
ASSERT_SUCCESS(proxy_tester_wait(tester, proxy_tester_client_bootstrap_shutdown_pred));
210192

211-
aws_host_resolver_clean_up(&tester->host_resolver);
212-
aws_event_loop_group_clean_up(&tester->event_loop_group);
193+
aws_host_resolver_release(tester->host_resolver);
194+
aws_event_loop_group_release(tester->event_loop_group);
195+
ASSERT_SUCCESS(aws_global_thread_creator_shutdown_wait_for(10));
213196

214197
if (tester->tls_ctx) {
215198
aws_tls_connection_options_clean_up(&tester->tls_connection_options);
216-
aws_tls_ctx_destroy(tester->tls_ctx);
199+
aws_tls_ctx_release(tester->tls_ctx);
217200
aws_tls_ctx_options_clean_up(&tester->tls_ctx_options);
218201
}
219202

tests/proxy_test_helper.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ struct proxy_tester_options {
4343
struct proxy_tester {
4444
struct aws_allocator *alloc;
4545
struct aws_logger logger;
46-
struct aws_event_loop_group event_loop_group;
47-
struct aws_host_resolver host_resolver;
46+
struct aws_event_loop_group *event_loop_group;
47+
struct aws_host_resolver *host_resolver;
4848
struct aws_client_bootstrap *client_bootstrap;
4949

5050
struct aws_tls_ctx *tls_ctx;
@@ -63,7 +63,6 @@ struct proxy_tester {
6363
struct testing_channel *testing_channel;
6464

6565
bool client_connection_is_shutdown;
66-
bool client_bootstrap_is_shutdown;
6766

6867
/* If we need to wait for some async process*/
6968
struct aws_mutex wait_lock;

tests/test_connection.c

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ struct tester_options {
4343
struct tester {
4444
struct aws_allocator *alloc;
4545
struct aws_logger logger;
46-
struct aws_event_loop_group event_loop_group;
47-
struct aws_host_resolver host_resolver;
46+
struct aws_event_loop_group *event_loop_group;
47+
struct aws_host_resolver *host_resolver;
4848
struct aws_server_bootstrap *server_bootstrap;
4949
struct aws_http_server *server;
5050
struct aws_client_bootstrap *client_bootstrap;
@@ -64,7 +64,6 @@ struct tester {
6464
int server_connection_is_shutdown;
6565
int wait_client_connection_is_shutdown;
6666
int wait_server_connection_is_shutdown;
67-
bool client_bootstrap_is_shutdown;
6867

6968
bool server_is_shutdown;
7069
struct aws_http_connection *new_client_connection;
@@ -177,15 +176,6 @@ static void s_tester_on_client_connection_shutdown(
177176
AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
178177
aws_condition_variable_notify_one(&tester->wait_cvar);
179178
}
180-
static void s_tester_on_client_bootstrap_shutdown(void *user_data) {
181-
struct tester *tester = user_data;
182-
AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
183-
184-
tester->client_bootstrap_is_shutdown = true;
185-
186-
AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
187-
aws_condition_variable_notify_one(&tester->wait_cvar);
188-
}
189179

190180
static int s_tester_wait(struct tester *tester, bool (*pred)(void *user_data)) {
191181
int local_wait_result;
@@ -230,11 +220,6 @@ static bool s_tester_server_shutdown_pred(void *user_data) {
230220
return tester->server_is_shutdown;
231221
}
232222

233-
static bool s_tester_client_bootstrap_shutdown_pred(void *user_data) {
234-
struct tester *tester = user_data;
235-
return tester->client_bootstrap_is_shutdown;
236-
}
237-
238223
static int s_tester_init(struct tester *tester, const struct tester_options *options) {
239224
AWS_ZERO_STRUCT(*tester);
240225

@@ -253,9 +238,9 @@ static int s_tester_init(struct tester *tester, const struct tester_options *opt
253238
ASSERT_SUCCESS(aws_mutex_init(&tester->wait_lock));
254239
ASSERT_SUCCESS(aws_condition_variable_init(&tester->wait_cvar));
255240

256-
ASSERT_SUCCESS(aws_event_loop_group_default_init(&tester->event_loop_group, tester->alloc, 1));
257-
ASSERT_SUCCESS(aws_host_resolver_init_default(&tester->host_resolver, tester->alloc, 8, &tester->event_loop_group));
258-
tester->server_bootstrap = aws_server_bootstrap_new(tester->alloc, &tester->event_loop_group);
241+
tester->event_loop_group = aws_event_loop_group_new_default(tester->alloc, 1, NULL);
242+
tester->host_resolver = aws_host_resolver_new_default(tester->alloc, 8, tester->event_loop_group, NULL);
243+
tester->server_bootstrap = aws_server_bootstrap_new(tester->alloc, tester->event_loop_group);
259244
ASSERT_NOT_NULL(tester->server_bootstrap);
260245

261246
struct aws_socket_options socket_options = {
@@ -295,10 +280,8 @@ static int s_tester_init(struct tester *tester, const struct tester_options *opt
295280
}
296281

297282
struct aws_client_bootstrap_options bootstrap_options = {
298-
.event_loop_group = &tester->event_loop_group,
299-
.host_resolver = &tester->host_resolver,
300-
.on_shutdown_complete = s_tester_on_client_bootstrap_shutdown,
301-
.user_data = tester,
283+
.event_loop_group = tester->event_loop_group,
284+
.host_resolver = tester->host_resolver,
302285
};
303286
tester->client_bootstrap = aws_client_bootstrap_new(tester->alloc, &bootstrap_options);
304287
ASSERT_NOT_NULL(tester->client_bootstrap);
@@ -335,8 +318,11 @@ static int s_tester_clean_up(struct tester *tester) {
335318
ASSERT_SUCCESS(s_tester_wait(tester, s_tester_server_shutdown_pred));
336319
}
337320
aws_server_bootstrap_release(tester->server_bootstrap);
338-
aws_host_resolver_clean_up(&tester->host_resolver);
339-
aws_event_loop_group_clean_up(&tester->event_loop_group);
321+
aws_client_bootstrap_release(tester->client_bootstrap);
322+
aws_host_resolver_release(tester->host_resolver);
323+
aws_event_loop_group_release(tester->event_loop_group);
324+
ASSERT_SUCCESS(aws_global_thread_creator_shutdown_wait_for(10));
325+
340326
aws_http_library_clean_up();
341327
aws_logger_clean_up(&tester->logger);
342328
aws_mutex_clean_up(&tester->wait_lock);
@@ -386,9 +372,6 @@ static int s_test_connection_setup_shutdown(struct aws_allocator *allocator, voi
386372
release_all_server_connections(&tester);
387373
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
388374

389-
aws_client_bootstrap_release(tester.client_bootstrap);
390-
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_client_bootstrap_shutdown_pred));
391-
392375
ASSERT_SUCCESS(s_tester_clean_up(&tester));
393376
return AWS_OP_SUCCESS;
394377
}
@@ -413,8 +396,6 @@ static int s_test_connection_destroy_server_with_connection_existing(struct aws_
413396
/* release memory */
414397
release_all_client_connections(&tester);
415398
release_all_server_connections(&tester);
416-
aws_client_bootstrap_release(tester.client_bootstrap);
417-
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_client_bootstrap_shutdown_pred));
418399

419400
ASSERT_SUCCESS(s_tester_clean_up(&tester));
420401
return AWS_OP_SUCCESS;
@@ -458,9 +439,6 @@ static int s_test_connection_destroy_server_with_multiple_connections_existing(
458439
release_all_client_connections(&tester);
459440
release_all_server_connections(&tester);
460441

461-
aws_client_bootstrap_release(tester.client_bootstrap);
462-
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_client_bootstrap_shutdown_pred));
463-
464442
ASSERT_SUCCESS(s_tester_clean_up(&tester));
465443
return AWS_OP_SUCCESS;
466444
}
@@ -540,25 +518,24 @@ static int s_test_connection_server_shutting_down_new_connection_setup_fail(
540518
};
541519
/* create a new eventloop for the new connection and block the new connection. Waiting server to begin shutting
542520
* down. */
543-
struct aws_event_loop_group event_loop_group;
544-
ASSERT_SUCCESS(aws_event_loop_group_default_init(&event_loop_group, allocator, 1));
521+
struct aws_event_loop_group *event_loop_group = aws_event_loop_group_new_default(allocator, 1, NULL);
545522

546523
/* get the first eventloop, which will be the eventloop for client to connect */
547-
struct aws_event_loop *current_eventloop = aws_event_loop_group_get_loop_at(&event_loop_group, 0);
524+
struct aws_event_loop *current_eventloop = aws_event_loop_group_get_loop_at(event_loop_group, 0);
548525
struct aws_task *block_task = aws_mem_acquire(allocator, sizeof(struct aws_task));
549526
aws_task_init(block_task, s_block_task, &tester, "wait_a_bit");
550527
aws_event_loop_schedule_task_now(current_eventloop, block_task);
551528

552529
/* get the first eventloop of tester, which will be the eventloop for server listener socket, block the listener
553530
* socket */
554-
struct aws_event_loop *server_eventloop = aws_event_loop_group_get_loop_at(&tester.event_loop_group, 0);
531+
struct aws_event_loop *server_eventloop = aws_event_loop_group_get_loop_at(tester.event_loop_group, 0);
555532
struct aws_task *server_block_task = aws_mem_acquire(allocator, sizeof(struct aws_task));
556533
aws_task_init(server_block_task, s_block_task, &tester, "wait_a_bit");
557534
aws_event_loop_schedule_task_now(server_eventloop, server_block_task);
558535

559536
struct aws_client_bootstrap_options bootstrap_options = {
560-
.event_loop_group = &event_loop_group,
561-
.host_resolver = &tester.host_resolver,
537+
.event_loop_group = event_loop_group,
538+
.host_resolver = tester.host_resolver,
562539
};
563540
struct aws_client_bootstrap *bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
564541
struct aws_http_client_connection_options client_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
@@ -603,9 +580,7 @@ static int s_test_connection_server_shutting_down_new_connection_setup_fail(
603580
release_all_client_connections(&tester);
604581
release_all_server_connections(&tester);
605582
aws_client_bootstrap_release(bootstrap);
606-
aws_client_bootstrap_release(tester.client_bootstrap);
607-
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_client_bootstrap_shutdown_pred));
608-
aws_event_loop_group_clean_up(&event_loop_group);
583+
aws_event_loop_group_release(event_loop_group);
609584
ASSERT_SUCCESS(s_tester_clean_up(&tester));
610585

611586
return AWS_OP_SUCCESS;

0 commit comments

Comments
 (0)