Skip to content

Commit

Permalink
fix the bug and use a state instead of two bool
Browse files Browse the repository at this point in the history
  • Loading branch information
TingDaoK committed Aug 7, 2024
1 parent 28246c9 commit c9cfa04
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 23 deletions.
9 changes: 7 additions & 2 deletions include/aws/http/private/h1_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
# pragma warning(disable : 4214) /* nonstandard extension used: bit field types other than int */
#endif

enum aws_h1_connection_read_state {
AWS_CONNECTION_READ_OPEN,
AWS_CONNECTION_READ_SHUTTING_DOWN,
AWS_CONNECTION_READ_SHUT_DOWN_COMPLETE,
};

struct aws_h1_connection {
struct aws_http_connection base;

Expand Down Expand Up @@ -97,10 +103,9 @@ struct aws_h1_connection {
uint64_t incoming_stream_timestamp_ns;

int pending_shutdown_error_code;
bool is_reading_shutdown_pending : 1;
enum aws_h1_connection_read_state read_state;

/* True when read and/or writing has stopped, whether due to errors or normal channel shutdown. */
bool is_reading_stopped : 1;
bool is_writing_stopped : 1;

/* If true, the connection has upgraded to another protocol.
Expand Down
46 changes: 25 additions & 21 deletions source/h1_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,17 @@ static void s_stop(
AWS_ASSERT(stop_reading || stop_writing || schedule_shutdown); /* You are required to stop at least 1 thing */

if (stop_reading) {
connection->thread_data.is_reading_stopped = true;
if (connection->thread_data.read_state == AWS_CONNECTION_READ_OPEN) {
connection->thread_data.read_state = AWS_CONNECTION_READ_SHUT_DOWN_COMPLETE;
} else if (connection->thread_data.read_state == AWS_CONNECTION_READ_SHUTTING_DOWN) {
/* Shutdown after pending */
if (connection->thread_data.pending_shutdown_error_code != 0) {
error_code = connection->thread_data.pending_shutdown_error_code;
}
connection->thread_data.read_state = AWS_CONNECTION_READ_SHUT_DOWN_COMPLETE;
aws_channel_slot_on_handler_shutdown_complete(
connection->base.channel_slot, AWS_CHANNEL_DIR_READ, error_code, false);
}
}

if (stop_writing) {
Expand All @@ -165,16 +175,9 @@ static void s_stop(
(void *)&connection->base,
error_code,
aws_error_name(error_code));
if (connection->thread_data.is_reading_shutdown_pending) {
/* Shutdown after pending */
if (connection->thread_data.pending_shutdown_error_code != 0) {
error_code = connection->thread_data.pending_shutdown_error_code;
}
aws_channel_slot_on_handler_shutdown_complete(
connection->base.channel_slot, AWS_CHANNEL_DIR_READ, error_code, false);
} else {
aws_channel_shutdown(connection->base.channel_slot->channel, error_code);
}

aws_channel_shutdown(connection->base.channel_slot->channel, error_code);

if (stop_reading) {
/* Increase the window size after shutdown starts, to prevent deadlock when data still pending in the TLS
* handler. */
Expand Down Expand Up @@ -332,7 +335,7 @@ static size_t s_calculate_stream_mode_desired_connection_window(struct aws_h1_co
static int s_update_connection_window(struct aws_h1_connection *connection) {
AWS_ASSERT(aws_channel_thread_is_callers_thread(connection->base.channel_slot->channel));

if (connection->thread_data.is_reading_stopped) {
if (connection->thread_data.read_state == AWS_CONNECTION_READ_SHUT_DOWN_COMPLETE) {
return AWS_OP_SUCCESS;
}

Expand Down Expand Up @@ -786,7 +789,7 @@ static void s_set_incoming_stream_ptr(
static void s_client_update_incoming_stream_ptr(struct aws_h1_connection *connection) {
struct aws_linked_list *list = &connection->thread_data.stream_list;
struct aws_h1_stream *desired;
if (connection->thread_data.is_reading_stopped) {
if (connection->thread_data.read_state == AWS_CONNECTION_READ_SHUT_DOWN_COMPLETE) {
desired = NULL;
} else if (aws_linked_list_empty(list)) {
desired = NULL;
Expand Down Expand Up @@ -1671,7 +1674,7 @@ static void s_handler_installed(struct aws_channel_handler *handler, struct aws_
static int s_try_process_next_midchannel_read_message(struct aws_h1_connection *connection, bool *out_stop_processing) {
AWS_ASSERT(aws_channel_thread_is_callers_thread(connection->base.channel_slot->channel));
AWS_ASSERT(connection->thread_data.has_switched_protocols);
AWS_ASSERT(!connection->thread_data.is_reading_stopped);
AWS_ASSERT(connection->thread_data.read_state != AWS_CONNECTION_READ_SHUT_DOWN_COMPLETE);
AWS_ASSERT(!aws_linked_list_empty(&connection->thread_data.read_buffer.messages));

*out_stop_processing = false;
Expand Down Expand Up @@ -1847,7 +1850,7 @@ static int s_handler_process_read_message(

AWS_LOGF_TRACE(
AWS_LS_HTTP_CONNECTION, "id=%p: Incoming message of size %zu.", (void *)&connection->base, message_size);
if (connection->thread_data.is_reading_stopped) {
if (connection->thread_data.read_state == AWS_CONNECTION_READ_SHUT_DOWN_COMPLETE) {
/* Read has stopped, ignore the data, shutdown the channel incase it has not started yet. */
aws_mem_release(message->allocator, message); /* Release the message as we return success. */
s_shutdown_due_to_error(connection, AWS_ERROR_HTTP_CONNECTION_CLOSED);
Expand Down Expand Up @@ -1885,7 +1888,7 @@ void aws_h1_connection_try_process_read_messages(struct aws_h1_connection *conne

/* Process queued messages */
while (!aws_linked_list_empty(&connection->thread_data.read_buffer.messages)) {
if (connection->thread_data.is_reading_stopped) {
if (connection->thread_data.read_state == AWS_CONNECTION_READ_SHUT_DOWN_COMPLETE) {
AWS_LOGF_ERROR(
AWS_LS_HTTP_CONNECTION,
"id=%p: Cannot process message because connection is shutting down.",
Expand Down Expand Up @@ -1916,7 +1919,8 @@ void aws_h1_connection_try_process_read_messages(struct aws_h1_connection *conne
}
}

if (connection->thread_data.is_reading_shutdown_pending && connection->thread_data.read_buffer.pending_bytes == 0) {
if (connection->thread_data.read_state == AWS_CONNECTION_READ_SHUTTING_DOWN &&
connection->thread_data.read_buffer.pending_bytes == 0) {
/* Done processing the pending buffer. */
aws_raise_error(connection->thread_data.pending_shutdown_error_code);
goto shutdown;
Expand All @@ -1932,7 +1936,7 @@ void aws_h1_connection_try_process_read_messages(struct aws_h1_connection *conne

shutdown:
error_code = aws_last_error();
if (connection->thread_data.is_reading_shutdown_pending &&
if (connection->thread_data.read_state == AWS_CONNECTION_READ_SHUTTING_DOWN &&
connection->thread_data.pending_shutdown_error_code != 0) {
error_code = connection->thread_data.pending_shutdown_error_code;
}
Expand All @@ -1949,7 +1953,7 @@ void aws_h1_connection_try_process_read_messages(struct aws_h1_connection *conne
static int s_try_process_next_stream_read_message(struct aws_h1_connection *connection, bool *out_stop_processing) {
AWS_ASSERT(aws_channel_thread_is_callers_thread(connection->base.channel_slot->channel));
AWS_ASSERT(!connection->thread_data.has_switched_protocols);
AWS_ASSERT(!connection->thread_data.is_reading_stopped);
AWS_ASSERT(connection->thread_data.read_state != AWS_CONNECTION_READ_SHUT_DOWN_COMPLETE);
AWS_ASSERT(!aws_linked_list_empty(&connection->thread_data.read_buffer.messages));

*out_stop_processing = false;
Expand Down Expand Up @@ -2165,7 +2169,7 @@ static void s_initialize_read_delay_shutdown(struct aws_h1_connection *connectio
connection->thread_data.read_buffer.capacity);

/* Still have data buffered in connection, wait for it to be processed */
connection->thread_data.is_reading_shutdown_pending = true;
connection->thread_data.read_state = AWS_CONNECTION_READ_SHUTTING_DOWN;
connection->thread_data.pending_shutdown_error_code = error_code;
/* Try to process messages in queue */
aws_h1_connection_try_process_read_messages(connection);
Expand All @@ -2191,7 +2195,7 @@ static int s_handler_shutdown(

if (dir == AWS_CHANNEL_DIR_READ) {
/* This call ensures that no further streams will be created or worked on. */
if (!free_scarce_resources_immediately && !connection->thread_data.is_reading_stopped &&
if (!free_scarce_resources_immediately && connection->thread_data.read_state == AWS_CONNECTION_READ_OPEN &&
connection->thread_data.read_buffer.pending_bytes > 0) {
s_initialize_read_delay_shutdown(connection, error_code);
/* Return success, and wait for the buffered data to be processed to propagate the shutdown. */
Expand Down

0 comments on commit c9cfa04

Please sign in to comment.