|
|
|
@ -47,6 +47,7 @@ |
|
|
|
|
#include <grpc/support/alloc.h> |
|
|
|
|
#include <grpc/support/log.h> |
|
|
|
|
#include <grpc/support/slice_buffer.h> |
|
|
|
|
#include <grpc/support/string_util.h> |
|
|
|
|
#include <grpc/support/useful.h> |
|
|
|
|
|
|
|
|
|
/* #define REFCOUNTING_DEBUG */ |
|
|
|
@ -166,15 +167,19 @@ static void destruct_transport(grpc_chttp2_transport *t) { |
|
|
|
|
#ifdef REFCOUNTING_DEBUG |
|
|
|
|
#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__) |
|
|
|
|
#define UNREF_TRANSPORT(t, r) unref_transport(t, r, __FILE__, __LINE__) |
|
|
|
|
static void unref_transport(grpc_chttp2_transport *t, const char *reason, const char *file, int line) { |
|
|
|
|
gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count, t->refs.count-1, reason, file, line); |
|
|
|
|
static void unref_transport(grpc_chttp2_transport *t, const char *reason, |
|
|
|
|
const char *file, int line) { |
|
|
|
|
gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count, |
|
|
|
|
t->refs.count - 1, reason, file, line); |
|
|
|
|
if (!gpr_unref(&t->refs)) return; |
|
|
|
|
destruct_transport(t); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ref_transport(grpc_chttp2_transport *t, const char *reason, const char *file, int line) {
|
|
|
|
|
gpr_log(GPR_DEBUG, "chttp2: ref:%p %d->%d %s [%s:%d]", t, t->refs.count, t->refs.count+1, reason, file, line); |
|
|
|
|
gpr_ref(&t->refs);
|
|
|
|
|
static void ref_transport(grpc_chttp2_transport *t, const char *reason, |
|
|
|
|
const char *file, int line) { |
|
|
|
|
gpr_log(GPR_DEBUG, "chttp2: ref:%p %d->%d %s [%s:%d]", t, t->refs.count, |
|
|
|
|
t->refs.count + 1, reason, file, line); |
|
|
|
|
gpr_ref(&t->refs); |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
#define REF_TRANSPORT(t, r) ref_transport(t) |
|
|
|
@ -221,6 +226,7 @@ static void init_transport(grpc_chttp2_transport *t, |
|
|
|
|
t->parsing.str_grpc_timeout = |
|
|
|
|
grpc_mdstr_from_string(t->metadata_context, "grpc-timeout"); |
|
|
|
|
t->parsing.deframe_state = is_client ? DTS_FH_0 : DTS_CLIENT_PREFIX_0; |
|
|
|
|
t->writing.is_client = is_client; |
|
|
|
|
|
|
|
|
|
gpr_slice_buffer_init(&t->global.qbuf); |
|
|
|
|
|
|
|
|
@ -378,12 +384,11 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs, |
|
|
|
|
s->global.outgoing_window = |
|
|
|
|
t->global |
|
|
|
|
.settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; |
|
|
|
|
s->global.incoming_window = |
|
|
|
|
s->parsing.incoming_window = s->global.incoming_window = |
|
|
|
|
t->global |
|
|
|
|
.settings[SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; |
|
|
|
|
*t->accepting_stream = s; |
|
|
|
|
grpc_chttp2_list_add_incoming_window_updated(&t->global, &s->global); |
|
|
|
|
grpc_chttp2_stream_map_add(&t->new_stream_map, s->global.id, s); |
|
|
|
|
grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s); |
|
|
|
|
s->global.in_stream_map = 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -404,7 +409,8 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) { |
|
|
|
|
GPR_ASSERT(!s->global.in_stream_map); |
|
|
|
|
grpc_chttp2_unregister_stream(t, s); |
|
|
|
|
if (!t->parsing_active && s->global.id) { |
|
|
|
|
GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map, s->global.id) == NULL); |
|
|
|
|
GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map, |
|
|
|
|
s->global.id) == NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gpr_mu_unlock(&t->mu); |
|
|
|
@ -525,7 +531,8 @@ void grpc_chttp2_terminate_writing( |
|
|
|
|
if (t->ep && !t->endpoint_reading) { |
|
|
|
|
grpc_endpoint_destroy(t->ep); |
|
|
|
|
t->ep = NULL; |
|
|
|
|
UNREF_TRANSPORT(t, "disconnect"); /* safe because we'll still have the ref for write */ |
|
|
|
|
UNREF_TRANSPORT( |
|
|
|
|
t, "disconnect"); /* safe because we'll still have the ref for write */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unlock(t); |
|
|
|
@ -586,7 +593,8 @@ static void maybe_start_some_streams( |
|
|
|
|
stream_global->id, STREAM_FROM_GLOBAL(stream_global)); |
|
|
|
|
stream_global->in_stream_map = 1; |
|
|
|
|
transport_global->concurrent_stream_count++; |
|
|
|
|
grpc_chttp2_list_add_incoming_window_updated(transport_global, stream_global); |
|
|
|
|
grpc_chttp2_list_add_incoming_window_updated(transport_global, |
|
|
|
|
stream_global); |
|
|
|
|
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); |
|
|
|
|
} |
|
|
|
|
/* cancel out streams that will never be started */ |
|
|
|
@ -699,7 +707,8 @@ static grpc_stream_state compute_state(gpr_uint8 write_closed, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) { |
|
|
|
|
grpc_chttp2_stream *s = grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id); |
|
|
|
|
grpc_chttp2_stream *s = |
|
|
|
|
grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id); |
|
|
|
|
GPR_ASSERT(s); |
|
|
|
|
s->global.in_stream_map = 0; |
|
|
|
|
if (t->parsing.incoming_stream == &s->parsing) { |
|
|
|
@ -729,25 +738,44 @@ static void unlock_check_read_write_state(grpc_chttp2_transport *t) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (grpc_chttp2_list_pop_read_write_state_changed(transport_global, &stream_global)) { |
|
|
|
|
while (grpc_chttp2_list_pop_read_write_state_changed(transport_global, |
|
|
|
|
&stream_global)) { |
|
|
|
|
if (!stream_global->publish_sopb) { |
|
|
|
|
gpr_log(GPR_DEBUG, "%s %d: skip rw update: no publish target", |
|
|
|
|
transport_global->is_client ? "CLI" : "SVR", stream_global->id); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if (stream_global->write_state != WRITE_STATE_OPEN && stream_global->read_closed && stream_global->in_stream_map) { |
|
|
|
|
if (stream_global->write_state == WRITE_STATE_SENT_CLOSE && |
|
|
|
|
stream_global->read_closed && stream_global->in_stream_map) { |
|
|
|
|
if (t->parsing_active) { |
|
|
|
|
grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global, stream_global); |
|
|
|
|
gpr_log(GPR_DEBUG, "%s %d: queue wait for close", |
|
|
|
|
transport_global->is_client ? "CLI" : "SVR", stream_global->id); |
|
|
|
|
grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global, |
|
|
|
|
stream_global); |
|
|
|
|
} else { |
|
|
|
|
gpr_log(GPR_DEBUG, "%s %d: late removal from map", |
|
|
|
|
transport_global->is_client ? "CLI" : "SVR", stream_global->id); |
|
|
|
|
remove_stream(t, stream_global->id); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
state = compute_state(stream_global->write_state == WRITE_STATE_SENT_CLOSE, stream_global->read_closed && !stream_global->in_stream_map); |
|
|
|
|
if (stream_global->incoming_sopb.nops == 0 && state == stream_global->published_state) { |
|
|
|
|
state = compute_state( |
|
|
|
|
stream_global->write_state == WRITE_STATE_SENT_CLOSE, |
|
|
|
|
stream_global->read_closed && !stream_global->in_stream_map); |
|
|
|
|
gpr_log(GPR_DEBUG, "%s %d: state=%d->%d; nops=%d", |
|
|
|
|
transport_global->is_client ? "CLI" : "SVR", stream_global->id, |
|
|
|
|
stream_global->published_state, state, |
|
|
|
|
stream_global->incoming_sopb.nops); |
|
|
|
|
if (stream_global->incoming_sopb.nops == 0 && |
|
|
|
|
state == stream_global->published_state) { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op(&stream_global->incoming_metadata, &stream_global->incoming_sopb, &stream_global->outstanding_metadata); |
|
|
|
|
grpc_chttp2_incoming_metadata_buffer_postprocess_sopb_and_begin_live_op( |
|
|
|
|
&stream_global->incoming_metadata, &stream_global->incoming_sopb, |
|
|
|
|
&stream_global->outstanding_metadata); |
|
|
|
|
grpc_sopb_swap(stream_global->publish_sopb, &stream_global->incoming_sopb); |
|
|
|
|
stream_global->published_state = *stream_global->publish_state = state; |
|
|
|
|
grpc_chttp2_schedule_closure(transport_global, stream_global->recv_done_closure, 1); |
|
|
|
|
grpc_chttp2_schedule_closure(transport_global, |
|
|
|
|
stream_global->recv_done_closure, 1); |
|
|
|
|
stream_global->recv_done_closure = NULL; |
|
|
|
|
stream_global->publish_sopb = NULL; |
|
|
|
|
stream_global->publish_state = NULL; |
|
|
|
@ -917,7 +945,8 @@ static void recv_data(void *tp, gpr_slice *slices, size_t nslices, |
|
|
|
|
if (!t->writing_active && t->ep) { |
|
|
|
|
grpc_endpoint_destroy(t->ep); |
|
|
|
|
t->ep = NULL; |
|
|
|
|
UNREF_TRANSPORT(t, "disconnect"); /* safe as we still have a ref for read */ |
|
|
|
|
UNREF_TRANSPORT( |
|
|
|
|
t, "disconnect"); /* safe as we still have a ref for read */ |
|
|
|
|
} |
|
|
|
|
unlock(t); |
|
|
|
|
UNREF_TRANSPORT(t, "recv_data"); |
|
|
|
@ -951,32 +980,6 @@ static void recv_data(void *tp, gpr_slice *slices, size_t nslices, |
|
|
|
|
grpc_chttp2_stream_map_size(&t->parsing_stream_map); |
|
|
|
|
t->parsing_active = 0; |
|
|
|
|
} |
|
|
|
|
#if 0 |
|
|
|
|
while ((s = stream_list_remove_head(t, MAYBE_FINISH_READ_AFTER_PARSE))) { |
|
|
|
|
maybe_finish_read(t, s, 0); |
|
|
|
|
} |
|
|
|
|
while ((s = stream_list_remove_head(t, PARSER_CHECK_WINDOW_UPDATES_AFTER_PARSE))) { |
|
|
|
|
maybe_join_window_updates(t, s); |
|
|
|
|
} |
|
|
|
|
while ((s = stream_list_remove_head(t, OTHER_CHECK_WINDOW_UPDATES_AFTER_PARSE))) { |
|
|
|
|
maybe_join_window_updates(t, s); |
|
|
|
|
} |
|
|
|
|
while ((s = stream_list_remove_head(t, NEW_OUTGOING_WINDOW))) { |
|
|
|
|
int was_window_empty = s->global.outgoing_window <= 0; |
|
|
|
|
FLOWCTL_TRACE(t, s, outgoing, s->global.id, s->global.outgoing_window_update); |
|
|
|
|
s->global.outgoing_window += s->global.outgoing_window_update; |
|
|
|
|
s->global.outgoing_window_update = 0; |
|
|
|
|
/* if this window update makes outgoing ops writable again,
|
|
|
|
|
flag that */ |
|
|
|
|
if (was_window_empty && s->global.outgoing_sopb && |
|
|
|
|
s->global.outgoing_sopb->nops > 0) { |
|
|
|
|
stream_list_join(t, s, WRITABLE); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
t->global.outgoing_window += t->global.outgoing_window_update; |
|
|
|
|
t->global.outgoing_window_update = 0; |
|
|
|
|
maybe_start_some_streams(t); |
|
|
|
|
#endif |
|
|
|
|
if (i == nslices) { |
|
|
|
|
grpc_endpoint_notify_on_read(t->ep, recv_data, t); |
|
|
|
|
} |
|
|
|
@ -1079,6 +1082,37 @@ static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) { |
|
|
|
|
unlock(t); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* TRACING |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
void grpc_chttp2_flowctl_trace(const char *file, int line, const char *reason, |
|
|
|
|
const char *context, const char *var, |
|
|
|
|
int is_client, gpr_uint32 stream_id, |
|
|
|
|
gpr_int64 current_value, gpr_int64 delta) { |
|
|
|
|
char *identifier; |
|
|
|
|
char *context_scope; |
|
|
|
|
char *context_thread; |
|
|
|
|
char *underscore_pos = strchr(context, '_'); |
|
|
|
|
GPR_ASSERT(underscore_pos); |
|
|
|
|
context_thread = gpr_strdup(underscore_pos + 1); |
|
|
|
|
context_scope = gpr_strdup(context); |
|
|
|
|
context_scope[underscore_pos - context] = 0; |
|
|
|
|
if (stream_id) { |
|
|
|
|
gpr_asprintf(&identifier, "%s[%d]", context_scope, stream_id); |
|
|
|
|
} else { |
|
|
|
|
identifier = gpr_strdup(context_scope); |
|
|
|
|
} |
|
|
|
|
gpr_log(GPR_DEBUG, |
|
|
|
|
"FLOWCTL: %s %-10s %8s %-23s %8lld %c %8lld = %8lld %-10s [%s:%d]", |
|
|
|
|
is_client ? "client" : "server", identifier, context_thread, var, |
|
|
|
|
current_value, delta < 0 ? '-' : '+', delta < 0 ? -delta : delta, |
|
|
|
|
current_value + delta, reason, file, line); |
|
|
|
|
gpr_free(identifier); |
|
|
|
|
gpr_free(context_thread); |
|
|
|
|
gpr_free(context_scope); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* INTEGRATION GLUE |
|
|
|
|
*/ |
|
|
|
|