Skip to content

Commit 7ed71e3

Browse files
authored
bootstrap-shutdown-cb (#215)
Invoke callback when aws_client_bootstrap finishes shutting down. This is necessary because we need to keep the aws_host_resolver alive at least as long as the bootstrap.
1 parent bc6037e commit 7ed71e3

File tree

5 files changed

+95
-32
lines changed

5 files changed

+95
-32
lines changed

include/aws/io/channel_bootstrap.h

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ struct aws_tls_connection_options;
6868

6969
struct aws_event_loop_group;
7070

71+
/**
72+
* Called after client bootstrap has been completely cleaned up, after its last refcount is released.
73+
*/
74+
typedef void aws_client_bootstrap_shutdown_complete_fn(void *user_data);
75+
7176
/**
7277
* aws_client_bootstrap handles creation and setup of channels that communicate via socket with a specific endpoint.
7378
*/
@@ -78,6 +83,31 @@ struct aws_client_bootstrap {
7883
struct aws_host_resolution_config host_resolver_config;
7984
aws_channel_on_protocol_negotiated_fn *on_protocol_negotiated;
8085
struct aws_atomic_var ref_count;
86+
aws_client_bootstrap_shutdown_complete_fn *on_shutdown_complete;
87+
void *user_data;
88+
};
89+
90+
/**
91+
* aws_client_bootstrap creation options.
92+
*/
93+
struct aws_client_bootstrap_options {
94+
95+
/* Required. Must outlive the client bootstrap. */
96+
struct aws_event_loop_group *event_loop_group;
97+
98+
/* Required. Must outlive the client bootstrap. */
99+
struct aws_host_resolver *host_resolver;
100+
101+
/* Optional. If none is provided then default settings are used.
102+
* This object is deep-copied by bootstrap.
103+
* */
104+
struct aws_host_resolution_config *host_resolution_config;
105+
106+
/* Optional. If provided, callback is invoked when client bootstrap has completely shut down. */
107+
aws_client_bootstrap_shutdown_complete_fn *on_shutdown_complete;
108+
109+
/* Optional. Passed to callbacks */
110+
void *user_data;
81111
};
82112

83113
struct aws_server_bootstrap;
@@ -140,15 +170,11 @@ struct aws_server_bootstrap {
140170
AWS_EXTERN_C_BEGIN
141171

142172
/**
143-
* Initializes the client bootstrap with `allocator` and `el_group`. This object manages client connections and
144-
* channels. host_resolver will be used for resolving host names.
145-
* If host_resolution_config is NULL, the default will be used, host_resolution_config will be copied.
173+
* Create the client bootstrap.
146174
*/
147175
AWS_IO_API struct aws_client_bootstrap *aws_client_bootstrap_new(
148176
struct aws_allocator *allocator,
149-
struct aws_event_loop_group *el_group,
150-
struct aws_host_resolver *host_resolver,
151-
struct aws_host_resolution_config *host_resolution_config);
177+
const struct aws_client_bootstrap_options *options);
152178

153179
/**
154180
* Cleans up the bootstrap's resources. Does not clean up any of your channels. You must shutdown your channels before

source/channel_bootstrap.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@
3939
void s_client_bootstrap_destroy_impl(struct aws_client_bootstrap *bootstrap) {
4040
AWS_ASSERT(bootstrap);
4141
AWS_LOGF_DEBUG(AWS_LS_IO_CHANNEL_BOOTSTRAP, "id=%p: destroying", (void *)bootstrap);
42+
aws_client_bootstrap_shutdown_complete_fn *on_shutdown_complete = bootstrap->on_shutdown_complete;
43+
void *user_data = bootstrap->user_data;
4244
aws_mem_release(bootstrap->allocator, bootstrap);
45+
46+
if (on_shutdown_complete) {
47+
on_shutdown_complete(user_data);
48+
}
4349
}
4450

4551
void s_client_bootstrap_acquire(struct aws_client_bootstrap *bootstrap) {
@@ -54,12 +60,11 @@ void s_client_bootstrap_release(struct aws_client_bootstrap *bootstrap) {
5460

5561
struct aws_client_bootstrap *aws_client_bootstrap_new(
5662
struct aws_allocator *allocator,
57-
struct aws_event_loop_group *el_group,
58-
struct aws_host_resolver *host_resolver,
59-
struct aws_host_resolution_config *host_resolution_config) {
63+
const struct aws_client_bootstrap_options *options) {
6064
AWS_ASSERT(allocator);
61-
AWS_ASSERT(el_group);
62-
AWS_ASSERT(host_resolver);
65+
AWS_ASSERT(options);
66+
AWS_ASSERT(options->event_loop_group);
67+
AWS_ASSERT(options->host_resolver);
6368

6469
struct aws_client_bootstrap *bootstrap = aws_mem_calloc(allocator, 1, sizeof(struct aws_client_bootstrap));
6570
if (!bootstrap) {
@@ -70,16 +75,18 @@ struct aws_client_bootstrap *aws_client_bootstrap_new(
7075
AWS_LS_IO_CHANNEL_BOOTSTRAP,
7176
"id=%p: Initializing client bootstrap with event-loop group %p",
7277
(void *)bootstrap,
73-
(void *)el_group);
78+
(void *)options->event_loop_group);
7479

7580
bootstrap->allocator = allocator;
76-
bootstrap->event_loop_group = el_group;
81+
bootstrap->event_loop_group = options->event_loop_group;
7782
bootstrap->on_protocol_negotiated = NULL;
7883
aws_atomic_init_int(&bootstrap->ref_count, 1);
79-
bootstrap->host_resolver = host_resolver;
84+
bootstrap->host_resolver = options->host_resolver;
85+
bootstrap->on_shutdown_complete = options->on_shutdown_complete;
86+
bootstrap->user_data = options->user_data;
8087

81-
if (host_resolution_config) {
82-
bootstrap->host_resolver_config = *host_resolution_config;
88+
if (options->host_resolution_config) {
89+
bootstrap->host_resolver_config = *options->host_resolution_config;
8390
} else {
8491
bootstrap->host_resolver_config = (struct aws_host_resolution_config){
8592
.impl = aws_default_dns_resolve,
@@ -102,6 +109,10 @@ int aws_client_bootstrap_set_alpn_callback(
102109
}
103110

104111
void aws_client_bootstrap_release(struct aws_client_bootstrap *bootstrap) {
112+
if (!bootstrap) {
113+
return;
114+
}
115+
105116
AWS_LOGF_DEBUG(AWS_LS_IO_CHANNEL_BOOTSTRAP, "id=%p: releasing bootstrap reference", (void *)bootstrap);
106117
s_client_bootstrap_release(bootstrap);
107118
}

tests/channel_test.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -914,8 +914,13 @@ static int s_test_channel_connect_some_hosts_timeout(struct aws_allocator *alloc
914914
struct aws_host_resolver resolver;
915915
ASSERT_SUCCESS(aws_host_resolver_init_default(&resolver, allocator, 8, &event_loop_group));
916916

917-
struct aws_client_bootstrap *bootstrap =
918-
aws_client_bootstrap_new(allocator, &event_loop_group, &resolver, &mock_resolver_config);
917+
struct aws_client_bootstrap_options bootstrap_options = {
918+
.event_loop_group = &event_loop_group,
919+
.host_resolver = &resolver,
920+
.host_resolution_config = &mock_resolver_config,
921+
};
922+
923+
struct aws_client_bootstrap *bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
919924
ASSERT_NOT_NULL(bootstrap);
920925

921926
struct aws_socket_options options;

tests/socket_handler_test.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,11 @@ static int s_socket_echo_and_backpressure_test(struct aws_allocator *allocator,
361361
/* this should never get used for this case. */
362362
struct aws_host_resolver dummy_resolver;
363363
AWS_ZERO_STRUCT(dummy_resolver);
364-
struct aws_client_bootstrap *client_bootstrap =
365-
aws_client_bootstrap_new(allocator, &c_tester.el_group, &dummy_resolver, NULL);
364+
struct aws_client_bootstrap_options bootstrap_options = {
365+
.event_loop_group = &c_tester.el_group,
366+
.host_resolver = &dummy_resolver,
367+
};
368+
struct aws_client_bootstrap *client_bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
366369
ASSERT_NOT_NULL(client_bootstrap);
367370

368371
ASSERT_SUCCESS(aws_mutex_lock(&c_tester.mutex));
@@ -480,8 +483,11 @@ static int s_socket_close_test(struct aws_allocator *allocator, void *ctx) {
480483
/* this should not get used for a unix domain socket. */
481484
struct aws_host_resolver dummy_resolver;
482485
AWS_ZERO_STRUCT(dummy_resolver);
483-
struct aws_client_bootstrap *client_bootstrap =
484-
aws_client_bootstrap_new(allocator, &c_tester.el_group, &dummy_resolver, NULL);
486+
struct aws_client_bootstrap_options bootstrap_options = {
487+
.event_loop_group = &c_tester.el_group,
488+
.host_resolver = &dummy_resolver,
489+
};
490+
struct aws_client_bootstrap *client_bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
485491
ASSERT_NOT_NULL(client_bootstrap);
486492

487493
ASSERT_SUCCESS(aws_mutex_lock(&c_tester.mutex));

tests/tls_handler_test.c

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,11 @@ static int s_tls_channel_echo_and_backpressure_test_fn(struct aws_allocator *all
443443
aws_tls_connection_options_set_callbacks(
444444
&client_tls_opt_tester.opt, s_tls_on_negotiated, NULL, NULL, &outgoing_args);
445445

446-
struct aws_client_bootstrap *client_bootstrap =
447-
aws_client_bootstrap_new(allocator, &c_tester.el_group, &c_tester.resolver, NULL);
446+
struct aws_client_bootstrap_options bootstrap_options = {
447+
.event_loop_group = &c_tester.el_group,
448+
.host_resolver = &c_tester.resolver,
449+
};
450+
struct aws_client_bootstrap *client_bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
448451

449452
ASSERT_SUCCESS(aws_mutex_lock(&c_tester.mutex));
450453

@@ -604,8 +607,11 @@ static int s_verify_negotiation_fails(struct aws_allocator *allocator, const str
604607

605608
aws_mutex_lock(&c_tester.mutex);
606609

607-
struct aws_client_bootstrap *client_bootstrap =
608-
aws_client_bootstrap_new(allocator, &c_tester.el_group, &c_tester.resolver, NULL);
610+
struct aws_client_bootstrap_options bootstrap_options = {
611+
.event_loop_group = &c_tester.el_group,
612+
.host_resolver = &c_tester.resolver,
613+
};
614+
struct aws_client_bootstrap *client_bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
609615
ASSERT_NOT_NULL(client_bootstrap);
610616

611617
ASSERT_SUCCESS(aws_client_bootstrap_new_tls_socket_channel(
@@ -745,8 +751,11 @@ static int s_tls_client_channel_negotiation_error_socket_closed_fn(struct aws_al
745751

746752
aws_mutex_lock(&c_tester.mutex);
747753

748-
struct aws_client_bootstrap *client_bootstrap =
749-
aws_client_bootstrap_new(allocator, &c_tester.el_group, &c_tester.resolver, NULL);
754+
struct aws_client_bootstrap_options bootstrap_options = {
755+
.event_loop_group = &c_tester.el_group,
756+
.host_resolver = &c_tester.resolver,
757+
};
758+
struct aws_client_bootstrap *client_bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
750759
ASSERT_NOT_NULL(client_bootstrap);
751760

752761
ASSERT_SUCCESS(aws_client_bootstrap_new_tls_socket_channel(
@@ -824,8 +833,11 @@ static int s_verify_good_host(struct aws_allocator *allocator, const struct aws_
824833

825834
aws_mutex_lock(&c_tester.mutex);
826835

827-
struct aws_client_bootstrap *client_bootstrap =
828-
aws_client_bootstrap_new(allocator, &c_tester.el_group, &c_tester.resolver, NULL);
836+
struct aws_client_bootstrap_options bootstrap_options = {
837+
.event_loop_group = &c_tester.el_group,
838+
.host_resolver = &c_tester.resolver,
839+
};
840+
struct aws_client_bootstrap *client_bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
829841
ASSERT_NOT_NULL(client_bootstrap);
830842

831843
ASSERT_SUCCESS(aws_client_bootstrap_new_tls_socket_channel(
@@ -918,8 +930,11 @@ static int s_tls_server_multiple_connections_fn(struct aws_allocator *allocator,
918930
aws_tls_connection_options_set_callbacks(
919931
&client_tls_opt_tester.opt, s_tls_on_negotiated, NULL, NULL, &outgoing_args);
920932

921-
struct aws_client_bootstrap *client_bootstrap =
922-
aws_client_bootstrap_new(allocator, &c_tester.el_group, &c_tester.resolver, NULL);
933+
struct aws_client_bootstrap_options bootstrap_options = {
934+
.event_loop_group = &c_tester.el_group,
935+
.host_resolver = &c_tester.resolver,
936+
};
937+
struct aws_client_bootstrap *client_bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
923938

924939
ASSERT_SUCCESS(aws_mutex_lock(&c_tester.mutex));
925940

0 commit comments

Comments
 (0)