Skip to content

Commit 32f49a5

Browse files
authored
bootstrap-shutdown-cb: HTTP edition (#169)
1 parent 5d013de commit 32f49a5

File tree

6 files changed

+145
-24
lines changed

6 files changed

+145
-24
lines changed

bin/elasticurl/main.c

+27-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct elasticurl_ctx {
7272
const char *trace_file;
7373
enum aws_log_level log_level;
7474
bool exchange_completed;
75+
bool bootstrap_shutdown_completed;
7576
};
7677

7778
static void s_usage(int exit_code) {
@@ -525,6 +526,20 @@ static bool s_completion_predicate(void *arg) {
525526
return app_ctx->exchange_completed;
526527
}
527528

529+
static void s_bootstrap_on_shutdown(void *user_data) {
530+
struct elasticurl_ctx *app_ctx = user_data;
531+
532+
aws_mutex_lock(&app_ctx->mutex);
533+
app_ctx->bootstrap_shutdown_completed = true;
534+
aws_mutex_unlock(&app_ctx->mutex);
535+
aws_condition_variable_notify_all(&app_ctx->c_var);
536+
}
537+
538+
static bool s_bootstrap_shutdown_predicate(void *arg) {
539+
struct elasticurl_ctx *app_ctx = arg;
540+
return app_ctx->bootstrap_shutdown_completed;
541+
}
542+
528543
int main(int argc, char **argv) {
529544
struct aws_allocator *allocator = aws_default_allocator();
530545

@@ -664,7 +679,13 @@ int main(int argc, char **argv) {
664679
struct aws_host_resolver resolver;
665680
aws_host_resolver_init_default(&resolver, allocator, 8, &el_group);
666681

667-
struct aws_client_bootstrap *bootstrap = aws_client_bootstrap_new(allocator, &el_group, &resolver, NULL);
682+
struct aws_client_bootstrap_options bootstrap_options = {
683+
.event_loop_group = &el_group,
684+
.host_resolver = &resolver,
685+
.on_shutdown_complete = s_bootstrap_on_shutdown,
686+
.user_data = &app_ctx,
687+
};
688+
struct aws_client_bootstrap *bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
668689

669690
struct aws_socket_options socket_options = {
670691
.type = AWS_SOCKET_STREAM,
@@ -691,8 +712,13 @@ int main(int argc, char **argv) {
691712
aws_http_client_connect(&http_client_options);
692713
aws_mutex_lock(&app_ctx.mutex);
693714
aws_condition_variable_wait_pred(&app_ctx.c_var, &app_ctx.mutex, s_completion_predicate, &app_ctx);
715+
aws_mutex_unlock(&app_ctx.mutex);
694716

695717
aws_client_bootstrap_release(bootstrap);
718+
aws_mutex_lock(&app_ctx.mutex);
719+
aws_condition_variable_wait_pred(&app_ctx.c_var, &app_ctx.mutex, s_bootstrap_shutdown_predicate, &app_ctx);
720+
aws_mutex_unlock(&app_ctx.mutex);
721+
696722
aws_host_resolver_clean_up(&resolver);
697723
aws_event_loop_group_clean_up(&el_group);
698724

tests/proxy_test_helper.c

+23-2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,16 @@ void proxy_tester_on_client_connection_shutdown(
7272
aws_condition_variable_notify_one(&tester->wait_cvar);
7373
}
7474

75+
void proxy_tester_on_client_bootstrap_shutdown(void *user_data) {
76+
struct proxy_tester *tester = user_data;
77+
AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
78+
79+
tester->client_bootstrap_is_shutdown = true;
80+
81+
AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
82+
aws_condition_variable_notify_one(&tester->wait_cvar);
83+
}
84+
7585
int proxy_tester_wait(struct proxy_tester *tester, bool (*pred)(void *user_data)) {
7686
ASSERT_SUCCESS(aws_mutex_lock(&tester->wait_lock));
7787
ASSERT_SUCCESS(aws_condition_variable_wait_pred(&tester->wait_cvar, &tester->wait_lock, pred, tester));
@@ -95,6 +105,11 @@ bool proxy_tester_request_complete_pred_fn(void *user_data) {
95105
return tester->request_complete || tester->client_connection_is_shutdown;
96106
}
97107

108+
bool proxy_tester_client_bootstrap_shutdown_pred(void *user_data) {
109+
struct proxy_tester *tester = user_data;
110+
return tester->client_bootstrap_is_shutdown;
111+
}
112+
98113
int proxy_tester_init(struct proxy_tester *tester, const struct proxy_tester_options *options) {
99114
AWS_ZERO_STRUCT(*tester);
100115

@@ -131,8 +146,13 @@ int proxy_tester_init(struct proxy_tester *tester, const struct proxy_tester_opt
131146
(uint32_t)aws_timestamp_convert(TESTER_TIMEOUT_SEC, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL),
132147
};
133148

134-
tester->client_bootstrap =
135-
aws_client_bootstrap_new(tester->alloc, &tester->event_loop_group, &tester->host_resolver, NULL);
149+
struct aws_client_bootstrap_options bootstrap_options = {
150+
.event_loop_group = &tester->event_loop_group,
151+
.host_resolver = &tester->host_resolver,
152+
.on_shutdown_complete = proxy_tester_on_client_bootstrap_shutdown,
153+
.user_data = tester,
154+
};
155+
tester->client_bootstrap = aws_client_bootstrap_new(tester->alloc, &bootstrap_options);
136156
ASSERT_NOT_NULL(tester->client_bootstrap);
137157

138158
bool use_tls = options->test_mode == PTTM_HTTPS;
@@ -196,6 +216,7 @@ int proxy_tester_clean_up(struct proxy_tester *tester) {
196216
}
197217

198218
aws_client_bootstrap_release(tester->client_bootstrap);
219+
ASSERT_SUCCESS(proxy_tester_wait(tester, proxy_tester_client_bootstrap_shutdown_pred));
199220

200221
aws_host_resolver_clean_up(&tester->host_resolver);
201222
aws_event_loop_group_clean_up(&tester->event_loop_group);

tests/proxy_test_helper.h

+3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ struct proxy_tester {
7373
struct testing_channel *testing_channel;
7474

7575
bool client_connection_is_shutdown;
76+
bool client_bootstrap_is_shutdown;
7677

7778
/* If we need to wait for some async process*/
7879
struct aws_mutex wait_lock;
@@ -105,6 +106,8 @@ void proxy_tester_on_client_connection_shutdown(
105106
int error_code,
106107
void *user_data);
107108

109+
void proxy_tester_on_client_bootstrap_shutdown(void *user_data);
110+
108111
int proxy_tester_create_testing_channel_connection(struct proxy_tester *tester);
109112

110113
int proxy_tester_verify_connect_request(struct proxy_tester *tester);

tests/test_connection.c

+34-5
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct tester {
7474
int server_connection_is_shutdown;
7575
int wait_client_connection_is_shutdown;
7676
int wait_server_connection_is_shutdown;
77+
bool client_bootstrap_is_shutdown;
7778

7879
bool server_is_shutdown;
7980
struct aws_http_connection *new_client_connection;
@@ -186,6 +187,15 @@ static void s_tester_on_client_connection_shutdown(
186187
AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
187188
aws_condition_variable_notify_one(&tester->wait_cvar);
188189
}
190+
static void s_tester_on_client_bootstrap_shutdown(void *user_data) {
191+
struct tester *tester = user_data;
192+
AWS_FATAL_ASSERT(aws_mutex_lock(&tester->wait_lock) == AWS_OP_SUCCESS);
193+
194+
tester->client_bootstrap_is_shutdown = true;
195+
196+
AWS_FATAL_ASSERT(aws_mutex_unlock(&tester->wait_lock) == AWS_OP_SUCCESS);
197+
aws_condition_variable_notify_one(&tester->wait_cvar);
198+
}
189199

190200
static int s_tester_wait(struct tester *tester, bool (*pred)(void *user_data)) {
191201
int local_wait_result;
@@ -230,6 +240,11 @@ static bool s_tester_server_shutdown_pred(void *user_data) {
230240
return tester->server_is_shutdown;
231241
}
232242

243+
static bool s_tester_client_bootstrap_shutdown_pred(void *user_data) {
244+
struct tester *tester = user_data;
245+
return tester->client_bootstrap_is_shutdown;
246+
}
247+
233248
static int s_tester_init(struct tester *tester, const struct tester_options *options) {
234249
AWS_ZERO_STRUCT(*tester);
235250

@@ -289,8 +304,13 @@ static int s_tester_init(struct tester *tester, const struct tester_options *opt
289304
return AWS_OP_SUCCESS;
290305
}
291306

292-
tester->client_bootstrap =
293-
aws_client_bootstrap_new(tester->alloc, &tester->event_loop_group, &tester->host_resolver, NULL);
307+
struct aws_client_bootstrap_options bootstrap_options = {
308+
.event_loop_group = &tester->event_loop_group,
309+
.host_resolver = &tester->host_resolver,
310+
.on_shutdown_complete = s_tester_on_client_bootstrap_shutdown,
311+
.user_data = tester,
312+
};
313+
tester->client_bootstrap = aws_client_bootstrap_new(tester->alloc, &bootstrap_options);
294314
ASSERT_NOT_NULL(tester->client_bootstrap);
295315

296316
/* Connect */
@@ -377,6 +397,7 @@ static int s_test_connection_setup_shutdown(struct aws_allocator *allocator, voi
377397
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_connection_shutdown_pred));
378398

379399
aws_client_bootstrap_release(tester.client_bootstrap);
400+
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_client_bootstrap_shutdown_pred));
380401

381402
ASSERT_SUCCESS(s_tester_clean_up(&tester));
382403
return AWS_OP_SUCCESS;
@@ -403,6 +424,7 @@ static int s_test_connection_destroy_server_with_connection_existing(struct aws_
403424
release_all_client_connections(&tester);
404425
release_all_server_connections(&tester);
405426
aws_client_bootstrap_release(tester.client_bootstrap);
427+
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_client_bootstrap_shutdown_pred));
406428

407429
ASSERT_SUCCESS(s_tester_clean_up(&tester));
408430
return AWS_OP_SUCCESS;
@@ -445,7 +467,10 @@ static int s_test_connection_destroy_server_with_multiple_connections_existing(
445467
/* release memory */
446468
release_all_client_connections(&tester);
447469
release_all_server_connections(&tester);
470+
448471
aws_client_bootstrap_release(tester.client_bootstrap);
472+
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_client_bootstrap_shutdown_pred));
473+
449474
ASSERT_SUCCESS(s_tester_clean_up(&tester));
450475
return AWS_OP_SUCCESS;
451476
}
@@ -541,8 +566,11 @@ static int s_test_connection_server_shutting_down_new_connection_setup_fail(
541566
aws_task_init(server_block_task, s_block_task, &tester, "wait_a_bit");
542567
aws_event_loop_schedule_task_now(server_eventloop, server_block_task);
543568

544-
struct aws_client_bootstrap *bootstrap =
545-
aws_client_bootstrap_new(allocator, &event_loop_group, &tester.host_resolver, NULL);
569+
struct aws_client_bootstrap_options bootstrap_options = {
570+
.event_loop_group = &event_loop_group,
571+
.host_resolver = &tester.host_resolver,
572+
};
573+
struct aws_client_bootstrap *bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
546574
struct aws_http_client_connection_options client_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
547575
client_options.allocator = tester.alloc;
548576
client_options.bootstrap = bootstrap;
@@ -580,8 +608,9 @@ static int s_test_connection_server_shutting_down_new_connection_setup_fail(
580608
/* release memory */
581609
release_all_client_connections(&tester);
582610
release_all_server_connections(&tester);
583-
aws_client_bootstrap_release(tester.client_bootstrap);
584611
aws_client_bootstrap_release(bootstrap);
612+
aws_client_bootstrap_release(tester.client_bootstrap);
613+
ASSERT_SUCCESS(s_tester_wait(&tester, s_tester_client_bootstrap_shutdown_pred));
585614
aws_event_loop_group_clean_up(&event_loop_group);
586615
ASSERT_SUCCESS(s_tester_clean_up(&tester));
587616

tests/test_connection_manager.c

+52-13
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ struct cm_tester {
6969

7070
size_t wait_for_connection_count;
7171
bool is_shutdown_complete;
72+
bool is_client_bootstrap_shutdown_complete;
7273

7374
struct aws_http_connection_manager_system_vtable *mock_table;
7475

@@ -89,6 +90,17 @@ static void s_cm_tester_on_cm_shutdown_complete(void *user_data) {
8990
aws_condition_variable_notify_one(&tester->signal);
9091
}
9192

93+
static void s_cm_tester_on_client_bootstrap_shutdown_complete(void *user_data) {
94+
struct cm_tester *tester = user_data;
95+
AWS_FATAL_ASSERT(tester == &s_tester);
96+
aws_mutex_lock(&tester->lock);
97+
98+
tester->is_client_bootstrap_shutdown_complete = true;
99+
100+
aws_mutex_unlock(&tester->lock);
101+
aws_condition_variable_notify_one(&tester->signal);
102+
}
103+
92104
int s_cm_tester_init(struct cm_tester_options *options) {
93105
struct cm_tester *tester = &s_tester;
94106

@@ -115,8 +127,13 @@ int s_cm_tester_init(struct cm_tester_options *options) {
115127
ASSERT_SUCCESS(aws_event_loop_group_default_init(&tester->event_loop_group, tester->allocator, 1));
116128
ASSERT_SUCCESS(
117129
aws_host_resolver_init_default(&tester->host_resolver, tester->allocator, 8, &tester->event_loop_group));
118-
tester->client_bootstrap =
119-
aws_client_bootstrap_new(tester->allocator, &tester->event_loop_group, &tester->host_resolver, NULL);
130+
struct aws_client_bootstrap_options bootstrap_options = {
131+
.event_loop_group = &tester->event_loop_group,
132+
.host_resolver = &tester->host_resolver,
133+
.on_shutdown_complete = s_cm_tester_on_client_bootstrap_shutdown_complete,
134+
.user_data = tester,
135+
};
136+
tester->client_bootstrap = aws_client_bootstrap_new(tester->allocator, &bootstrap_options);
120137
ASSERT_NOT_NULL(tester->client_bootstrap);
121138

122139
struct aws_socket_options socket_options = {
@@ -134,17 +151,18 @@ int s_cm_tester_init(struct cm_tester_options *options) {
134151

135152
tester->proxy_options = options->proxy_options;
136153

137-
struct aws_http_connection_manager_options cm_options = {.bootstrap = tester->client_bootstrap,
138-
.initial_window_size = SIZE_MAX,
139-
.socket_options = &socket_options,
140-
.tls_connection_options = NULL,
141-
.proxy_options = tester->proxy_options,
142-
.host = aws_byte_cursor_from_c_str("www.google.com"),
143-
.port = 80,
144-
.max_connections = options->max_connections,
145-
.shutdown_complete_user_data = tester,
146-
.shutdown_complete_callback =
147-
s_cm_tester_on_cm_shutdown_complete};
154+
struct aws_http_connection_manager_options cm_options = {
155+
.bootstrap = tester->client_bootstrap,
156+
.initial_window_size = SIZE_MAX,
157+
.socket_options = &socket_options,
158+
.tls_connection_options = NULL,
159+
.proxy_options = tester->proxy_options,
160+
.host = aws_byte_cursor_from_c_str("www.google.com"),
161+
.port = 80,
162+
.max_connections = options->max_connections,
163+
.shutdown_complete_user_data = tester,
164+
.shutdown_complete_callback = s_cm_tester_on_cm_shutdown_complete,
165+
};
148166

149167
tester->connection_manager = aws_http_connection_manager_new(tester->allocator, &cm_options);
150168
ASSERT_NOT_NULL(tester->connection_manager);
@@ -314,6 +332,26 @@ static int s_wait_on_shutdown_complete(void) {
314332
return signal_error;
315333
}
316334

335+
static bool s_is_client_bootstrap_shutdown_complete(void *context) {
336+
(void)context;
337+
338+
struct cm_tester *tester = &s_tester;
339+
340+
return tester->is_client_bootstrap_shutdown_complete;
341+
}
342+
343+
static int s_wait_on_client_bootstrap_shutdown_complete(void) {
344+
struct cm_tester *tester = &s_tester;
345+
346+
ASSERT_SUCCESS(aws_mutex_lock(&tester->lock));
347+
348+
int signal_error = aws_condition_variable_wait_pred(
349+
&tester->signal, &tester->lock, s_is_client_bootstrap_shutdown_complete, tester);
350+
351+
ASSERT_SUCCESS(aws_mutex_unlock(&tester->lock));
352+
return signal_error;
353+
}
354+
317355
int s_cm_tester_clean_up(void) {
318356
struct cm_tester *tester = &s_tester;
319357

@@ -337,6 +375,7 @@ int s_cm_tester_clean_up(void) {
337375
s_wait_on_shutdown_complete();
338376

339377
aws_client_bootstrap_release(tester->client_bootstrap);
378+
ASSERT_SUCCESS(s_wait_on_client_bootstrap_shutdown_complete());
340379

341380
aws_host_resolver_clean_up(&tester->host_resolver);
342381
aws_event_loop_group_clean_up(&tester->event_loop_group);

tests/test_tls.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,12 @@ static int s_test_tls_download_medium_file(struct aws_allocator *allocator, void
140140

141141
ASSERT_SUCCESS(aws_event_loop_group_default_init(&test.event_loop_group, test.alloc, 1));
142142
ASSERT_SUCCESS(aws_host_resolver_init_default(&test.host_resolver, test.alloc, 1, &test.event_loop_group));
143-
ASSERT_NOT_NULL(
144-
test.client_bootstrap =
145-
aws_client_bootstrap_new(test.alloc, &test.event_loop_group, &test.host_resolver, NULL));
143+
144+
struct aws_client_bootstrap_options bootstrap_options = {
145+
.event_loop_group = &test.event_loop_group,
146+
.host_resolver = &test.host_resolver,
147+
};
148+
ASSERT_NOT_NULL(test.client_bootstrap = aws_client_bootstrap_new(test.alloc, &bootstrap_options));
146149
struct aws_tls_ctx_options tls_ctx_options;
147150
aws_tls_ctx_options_init_default_client(&tls_ctx_options, allocator);
148151
ASSERT_NOT_NULL(test.tls_ctx = aws_tls_client_ctx_new(allocator, &tls_ctx_options));

0 commit comments

Comments
 (0)