diff options
author | Mark D. Roth <roth@google.com> | 2016-10-19 14:53:42 -0700 |
---|---|---|
committer | Mark D. Roth <roth@google.com> | 2016-10-19 14:53:42 -0700 |
commit | eb35a1d16bf7ccdb3e4006203ad63e5865454652 (patch) | |
tree | e7445fb61be3ff9b3d8a2ed9a8a5b5a4c544609d /src | |
parent | 15195741d7758a80bcf901e7db05b3c57654c4a3 (diff) | |
parent | 20e77f27b0cf2cb1305df21a91e6a51d9a4171d1 (diff) |
Merge remote-tracking branch 'upstream/master' into rename_client_config
Diffstat (limited to 'src')
159 files changed, 6206 insertions, 4392 deletions
diff --git a/src/compiler/README.md b/src/compiler/README.md new file mode 100644 index 0000000000..a2f49b3cd5 --- /dev/null +++ b/src/compiler/README.md @@ -0,0 +1,4 @@ +#Overview + +This directory contains source code for gRPC protocol buffer compiler (*protoc*) plugins. Along with `protoc`, +these plugins are used to generate gRPC client and server stubs from `.proto` files. diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc index 591e5ae3d4..48157033db 100644 --- a/src/compiler/csharp_generator.cc +++ b/src/compiler/csharp_generator.cc @@ -495,6 +495,9 @@ void GenerateClientStub(Printer *out, const ServiceDescriptor *service) { // override NewInstance method out->Print( + "/// <summary>Creates a new instance of client from given " + "<c>ClientBaseConfiguration</c>.</summary>\n"); + out->Print( "protected override $name$ NewInstance(ClientBaseConfiguration " "configuration)\n", "name", GetClientClassName(service)); diff --git a/src/core/README.md b/src/core/README.md index 0d8c0d5bd9..44c6f24772 100644 --- a/src/core/README.md +++ b/src/core/README.md @@ -1,8 +1,4 @@ #Overview -This directory contains source code for shared C library. Libraries in other languages in this repository (C++, Ruby, +This directory contains source code for C library (a.k.a the *gRPC C core*) that provides all gRPC's core functionality through a low level API. Libraries in other languages in this repository (C++, Ruby, Python, PHP, NodeJS, Objective-C) are layered on top of this library. - -#Status - -Beta diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c index 9dacc17eb4..a4cf6f37bd 100644 --- a/src/core/ext/census/grpc_filter.c +++ b/src/core/ext/census/grpc_filter.c @@ -133,7 +133,7 @@ static grpc_error *client_init_call_elem(grpc_exec_ctx *exec_ctx, call_data *d = elem->call_data; GPR_ASSERT(d != NULL); memset(d, 0, sizeof(*d)); - d->start_ts = gpr_now(GPR_CLOCK_REALTIME); + d->start_ts = args->start_time; return GRPC_ERROR_NONE; } @@ -152,7 +152,7 @@ static grpc_error *server_init_call_elem(grpc_exec_ctx *exec_ctx, call_data *d = elem->call_data; GPR_ASSERT(d != NULL); memset(d, 0, sizeof(*d)); - d->start_ts = gpr_now(GPR_CLOCK_REALTIME); + d->start_ts = args->start_time; /* TODO(hongyu): call census_tracing_start_op here. */ grpc_closure_init(&d->finish_recv, server_on_done_recv, elem); return GRPC_ERROR_NONE; diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c index 77291412a5..b61a0fb24b 100644 --- a/src/core/ext/client_channel/client_channel.c +++ b/src/core/ext/client_channel/client_channel.c @@ -43,6 +43,7 @@ #include <grpc/support/useful.h> #include "src/core/ext/client_channel/lb_policy_registry.h" +#include "src/core/ext/client_channel/method_config.h" #include "src/core/ext/client_channel/subchannel.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/connected_channel.h" @@ -53,6 +54,9 @@ #include "src/core/lib/support/string.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/metadata.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/transport/static_metadata.h" /* Client channel implementation */ @@ -68,12 +72,13 @@ typedef struct client_channel_channel_data { /** client channel factory */ grpc_client_channel_factory *client_channel_factory; - /** mutex protecting client configuration, including all - variables below in this data structure */ + /** mutex protecting all variables below in this data structure */ gpr_mu mu; - /** currently active load balancer - guarded by mu */ + /** currently active load balancer */ grpc_lb_policy *lb_policy; - /** incoming resolver result - set by resolver.next(), guarded by mu */ + /** method config table */ + grpc_method_config_table *method_config_table; + /** incoming resolver result - set by resolver.next() */ grpc_resolver_result *resolver_result; /** a list of closures that are all waiting for config to come in */ grpc_closure_list waiting_for_config_closures; @@ -111,10 +116,10 @@ static void set_channel_connectivity_state_locked(grpc_exec_ctx *exec_ctx, if ((state == GRPC_CHANNEL_TRANSIENT_FAILURE || state == GRPC_CHANNEL_SHUTDOWN) && chand->lb_policy != NULL) { - /* cancel fail-fast picks */ + /* cancel picks with wait_for_ready=false */ grpc_lb_policy_cancel_picks( exec_ctx, chand->lb_policy, - /* mask= */ GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY, + /* mask= */ GRPC_INITIAL_METADATA_WAIT_FOR_READY, /* check= */ 0, GRPC_ERROR_REF(error)); } grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, error, @@ -172,6 +177,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, channel_data *chand = arg; grpc_lb_policy *lb_policy = NULL; grpc_lb_policy *old_lb_policy; + grpc_method_config_table *method_config_table = NULL; grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; bool exit_idle = false; grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy"); @@ -220,6 +226,13 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error); } + const grpc_arg *channel_arg = grpc_channel_args_find( + lb_policy_args.additional_args, GRPC_ARG_SERVICE_CONFIG); + if (channel_arg != NULL) { + GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); + method_config_table = grpc_method_config_table_ref( + (grpc_method_config_table *)channel_arg->value.pointer.p); + } grpc_resolver_result_unref(exec_ctx, chand->resolver_result); chand->resolver_result = NULL; } @@ -232,6 +245,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg, gpr_mu_lock(&chand->mu); old_lb_policy = chand->lb_policy; chand->lb_policy = lb_policy; + if (chand->method_config_table != NULL) { + grpc_method_config_table_unref(chand->method_config_table); + } + chand->method_config_table = method_config_table; if (lb_policy != NULL) { grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, NULL); @@ -392,6 +409,9 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, chand->interested_parties); GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); } + if (chand->method_config_table != NULL) { + grpc_method_config_table_unref(chand->method_config_table); + } grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); grpc_pollset_set_destroy(chand->interested_parties); gpr_mu_destroy(&chand->mu); @@ -424,7 +444,16 @@ typedef struct client_channel_call_data { // stack and each has its own mutex. If/when we have time, find a way // to avoid this without breaking the grpc_deadline_state abstraction. grpc_deadline_state deadline_state; + + grpc_mdstr *path; // Request path. + gpr_timespec call_start_time; gpr_timespec deadline; + enum { + WAIT_FOR_READY_UNSET, + WAIT_FOR_READY_FALSE, + WAIT_FOR_READY_TRUE + } wait_for_ready_from_service_config; + grpc_closure read_service_config; grpc_error *cancel_error; @@ -513,10 +542,14 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) { static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - call_data *calld = arg; + grpc_call_element *elem = arg; + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; gpr_mu_lock(&calld->mu); GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); + grpc_polling_entity_del_from_pollset_set(exec_ctx, calld->pollent, + chand->interested_parties); calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; if (calld->connected_subchannel == NULL) { gpr_atm_no_barrier_store(&calld->subchannel_call, 1); @@ -528,10 +561,11 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, GRPC_ERROR_CREATE_REFERENCING( "Cancelled before creating subchannel", &error, 1)); } else { + /* Create call on subchannel. */ grpc_subchannel_call *subchannel_call = NULL; grpc_error *new_error = grpc_connected_subchannel_create_call( - exec_ctx, calld->connected_subchannel, calld->pollent, calld->deadline, - &subchannel_call); + exec_ctx, calld->connected_subchannel, calld->pollent, calld->path, + calld->deadline, &subchannel_call); if (new_error != GRPC_ERROR_NONE) { new_error = grpc_error_add_child(new_error, error); subchannel_call = CANCELLED_CALL; @@ -564,6 +598,9 @@ typedef struct { grpc_closure closure; } continue_picking_args; +/** Return true if subchannel is available immediately (in which case on_ready + should not be called), or false otherwise (in which case on_ready should be + called when the subchannel is available). */ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_metadata_batch *initial_metadata, uint32_t initial_metadata_flags, @@ -577,11 +614,15 @@ static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, /* cancelled, do nothing */ } else if (error != GRPC_ERROR_NONE) { grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_REF(error), NULL); - } else if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, - cpa->initial_metadata_flags, - cpa->connected_subchannel, cpa->on_ready, - GRPC_ERROR_NONE)) { - grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL); + } else { + call_data *calld = cpa->elem->call_data; + gpr_mu_lock(&calld->mu); + if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, + cpa->initial_metadata_flags, cpa->connected_subchannel, + cpa->on_ready, GRPC_ERROR_NONE)) { + grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL); + } + gpr_mu_unlock(&calld->mu); } gpr_free(cpa); } @@ -624,18 +665,33 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, GPR_ASSERT(error == GRPC_ERROR_NONE); if (chand->lb_policy != NULL) { grpc_lb_policy *lb_policy = chand->lb_policy; - int r; GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel"); gpr_mu_unlock(&chand->mu); + // If the application explicitly set wait_for_ready, use that. + // Otherwise, if the service config specified a value for this + // method, use that. + const bool wait_for_ready_set_from_api = + initial_metadata_flags & + GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET; + const bool wait_for_ready_set_from_service_config = + calld->wait_for_ready_from_service_config != WAIT_FOR_READY_UNSET; + if (!wait_for_ready_set_from_api && + wait_for_ready_set_from_service_config) { + if (calld->wait_for_ready_from_service_config == WAIT_FOR_READY_TRUE) { + initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY; + } else { + initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY; + } + } // TODO(dgq): make this deadline configurable somehow. const grpc_lb_policy_pick_args inputs = { - calld->pollent, initial_metadata, initial_metadata_flags, - &calld->lb_token_mdelem, gpr_inf_future(GPR_CLOCK_MONOTONIC)}; - r = grpc_lb_policy_pick(exec_ctx, lb_policy, &inputs, connected_subchannel, - NULL, on_ready); + initial_metadata, initial_metadata_flags, &calld->lb_token_mdelem, + gpr_inf_future(GPR_CLOCK_MONOTONIC)}; + const bool result = grpc_lb_policy_pick( + exec_ctx, lb_policy, &inputs, connected_subchannel, NULL, on_ready); GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "pick_subchannel"); GPR_TIMER_END("pick_subchannel", 0); - return r; + return result; } if (chand->resolver != NULL && !chand->started_resolving) { chand->started_resolving = true; @@ -672,6 +728,7 @@ static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; GRPC_CALL_LOG_OP(GPR_INFO, elem, op); grpc_deadline_state_client_start_transport_stream_op(exec_ctx, elem, op); /* try to (atomically) get the call */ @@ -739,14 +796,20 @@ retry: calld->connected_subchannel == NULL && op->send_initial_metadata != NULL) { calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; - grpc_closure_init(&calld->next_step, subchannel_ready, calld); + grpc_closure_init(&calld->next_step, subchannel_ready, elem); GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel"); + /* If a subchannel is not available immediately, the polling entity from + call_data should be provided to channel_data's interested_parties, so + that IO of the lb_policy and resolver could be done under it. */ if (pick_subchannel(exec_ctx, elem, op->send_initial_metadata, op->send_initial_metadata_flags, &calld->connected_subchannel, &calld->next_step, GRPC_ERROR_NONE)) { calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel"); + } else { + grpc_polling_entity_add_to_pollset_set(exec_ctx, calld->pollent, + chand->interested_parties); } } /* if we've got a subchannel, then let's ask it to create a call */ @@ -754,8 +817,8 @@ retry: calld->connected_subchannel != NULL) { grpc_subchannel_call *subchannel_call = NULL; grpc_error *error = grpc_connected_subchannel_create_call( - exec_ctx, calld->connected_subchannel, calld->pollent, calld->deadline, - &subchannel_call); + exec_ctx, calld->connected_subchannel, calld->pollent, calld->path, + calld->deadline, &subchannel_call); if (error != GRPC_ERROR_NONE) { subchannel_call = CANCELLED_CALL; fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error)); @@ -772,13 +835,69 @@ retry: GPR_TIMER_END("cc_start_transport_stream_op", 0); } +// Gets data from the service config. Invoked when the resolver returns +// its initial result. +static void read_service_config(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + grpc_call_element *elem = arg; + channel_data *chand = elem->channel_data; + call_data *calld = elem->call_data; + // If this is an error, there's no point in looking at the service config. + if (error == GRPC_ERROR_NONE) { + // Get the method config table from channel data. + gpr_mu_lock(&chand->mu); + grpc_method_config_table *method_config_table = NULL; + if (chand->method_config_table != NULL) { + method_config_table = + grpc_method_config_table_ref(chand->method_config_table); + } + gpr_mu_unlock(&chand->mu); + // If the method config table was present, use it. + if (method_config_table != NULL) { + const grpc_method_config *method_config = + grpc_method_config_table_get_method_config(method_config_table, + calld->path); + if (method_config != NULL) { + const gpr_timespec *per_method_timeout = + grpc_method_config_get_timeout(method_config); + const bool *wait_for_ready = + grpc_method_config_get_wait_for_ready(method_config); + if (per_method_timeout != NULL || wait_for_ready != NULL) { + gpr_mu_lock(&calld->mu); + if (per_method_timeout != NULL) { + gpr_timespec per_method_deadline = + gpr_time_add(calld->call_start_time, *per_method_timeout); + if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) { + calld->deadline = per_method_deadline; + // Reset deadline timer. + grpc_deadline_state_reset(exec_ctx, elem, calld->deadline); + } + } + if (wait_for_ready != NULL) { + calld->wait_for_ready_from_service_config = + *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; + } + gpr_mu_unlock(&calld->mu); + } + } + grpc_method_config_table_unref(method_config_table); + } + } + GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "read_service_config"); +} + /* Constructor for call_data */ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_call_element_args *args) { + channel_data *chand = elem->channel_data; call_data *calld = elem->call_data; - grpc_deadline_state_init(exec_ctx, elem, args); - calld->deadline = args->deadline; + // Initialize data members. + grpc_deadline_state_init(exec_ctx, elem, args->call_stack); + calld->path = GRPC_MDSTR_REF(args->path); + calld->call_start_time = args->start_time; + calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); + calld->wait_for_ready_from_service_config = WAIT_FOR_READY_UNSET; calld->cancel_error = GRPC_ERROR_NONE; gpr_atm_rel_store(&calld->subchannel_call, 0); gpr_mu_init(&calld->mu); @@ -789,6 +908,55 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx, calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; calld->owning_call = args->call_stack; calld->pollent = NULL; + // If the resolver has already returned results, then we can access + // the service config parameters immediately. Otherwise, we need to + // defer that work until the resolver returns an initial result. + // TODO(roth): This code is almost but not quite identical to the code + // in read_service_config() above. It would be nice to find a way to + // combine them, to avoid having to maintain it twice. + gpr_mu_lock(&chand->mu); + if (chand->lb_policy != NULL) { + // We already have a resolver result, so check for service config. + if (chand->method_config_table != NULL) { + grpc_method_config_table *method_config_table = + grpc_method_config_table_ref(chand->method_config_table); + gpr_mu_unlock(&chand->mu); + grpc_method_config *method_config = + grpc_method_config_table_get_method_config(method_config_table, + args->path); + if (method_config != NULL) { + const gpr_timespec *per_method_timeout = + grpc_method_config_get_timeout(method_config); + if (per_method_timeout != NULL) { + gpr_timespec per_method_deadline = + gpr_time_add(calld->call_start_time, *per_method_timeout); + calld->deadline = gpr_time_min(calld->deadline, per_method_deadline); + } + const bool *wait_for_ready = + grpc_method_config_get_wait_for_ready(method_config); + if (wait_for_ready != NULL) { + calld->wait_for_ready_from_service_config = + *wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE; + } + } + grpc_method_config_table_unref(method_config_table); + } else { + gpr_mu_unlock(&chand->mu); + } + } else { + // We don't yet have a resolver result, so register a callback to + // get the service config data once the resolver returns. + // Take a reference to the call stack to be owned by the callback. + GRPC_CALL_STACK_REF(calld->owning_call, "read_service_config"); + grpc_closure_init(&calld->read_service_config, read_service_config, elem); + grpc_closure_list_append(&chand->waiting_for_config_closures, + &calld->read_service_config, GRPC_ERROR_NONE); + gpr_mu_unlock(&chand->mu); + } + // Start the deadline timer with the current deadline value. If we + // do not yet have service config data, then the timer may be reset + // later. + grpc_deadline_state_start(exec_ctx, elem, calld->deadline); return GRPC_ERROR_NONE; } @@ -799,6 +967,7 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx, void *and_free_memory) { call_data *calld = elem->call_data; grpc_deadline_state_destroy(exec_ctx, elem); + GRPC_MDSTR_UNREF(calld->path); GRPC_ERROR_UNREF(calld->cancel_error); grpc_subchannel_call *call = GET_CALL(calld); if (call != NULL && call != CANCELLED_CALL) { diff --git a/src/core/ext/client_channel/http_connect_handshaker.c b/src/core/ext/client_channel/http_connect_handshaker.c index fda1df173e..ea2cbbdd97 100644 --- a/src/core/ext/client_channel/http_connect_handshaker.c +++ b/src/core/ext/client_channel/http_connect_handshaker.c @@ -31,7 +31,7 @@ * */ -#include "src/core/ext/client_config/http_connect_handshaker.h" +#include "src/core/ext/client_channel/http_connect_handshaker.h" #include <string.h> @@ -40,7 +40,7 @@ #include <grpc/support/slice_buffer.h> #include <grpc/support/string_util.h> -#include "src/core/ext/client_config/uri_parser.h" +#include "src/core/ext/client_channel/uri_parser.h" #include "src/core/lib/http/format_request.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/timer.h" diff --git a/src/core/ext/client_channel/lb_policy.h b/src/core/ext/client_channel/lb_policy.h index cc24a62d9d..54ad779792 100644 --- a/src/core/ext/client_channel/lb_policy.h +++ b/src/core/ext/client_channel/lb_policy.h @@ -55,8 +55,6 @@ struct grpc_lb_policy { /** Extra arguments for an LB pick */ typedef struct grpc_lb_policy_pick_args { - /** Parties interested in the pick's progress */ - grpc_polling_entity *pollent; /** Initial metadata associated with the picking call. */ grpc_metadata_batch *initial_metadata; /** Bitmask used for selective cancelling. See \a @@ -142,15 +140,19 @@ void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); void grpc_lb_policy_init(grpc_lb_policy *policy, const grpc_lb_policy_vtable *vtable); -/** Find an appropriate target for this call, based on \a pick_args. - Picking can be synchronous or asynchronous. In the synchronous case, when a - pick is readily available, it'll be returned in \a target and a non-zero - value will be returned. - In the asynchronous case, zero is returned and \a on_complete will be called - once \a target and \a user_data have been set. Any IO should be done under - \a pick_args->pollent. The opaque \a user_data output argument corresponds - to information that may need be propagated from the LB policy. It may be - NULL. Errors are signaled by receiving a NULL \a *target. */ +/** Finds an appropriate subchannel for a call, based on \a pick_args. + + \a target will be set to the selected subchannel, or NULL on failure. + Upon success, \a user_data will be set to whatever opaque information + may need to be propagated from the LB policy, or NULL if not needed. + + If the pick succeeds and a result is known immediately, a non-zero + value will be returned. Otherwise, \a on_complete will be invoked + once the pick is complete with its error argument set to indicate + success or failure. + + Any IO should be done under the \a interested_parties \a grpc_pollset_set + in the \a grpc_lb_policy struct. */ int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, const grpc_lb_policy_pick_args *pick_args, grpc_connected_subchannel **target, void **user_data, diff --git a/src/core/ext/client_channel/method_config.c b/src/core/ext/client_channel/method_config.c new file mode 100644 index 0000000000..49d1ad344e --- /dev/null +++ b/src/core/ext/client_channel/method_config.c @@ -0,0 +1,296 @@ +// +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "src/core/ext/client_channel/method_config.h" + +#include <string.h> + +#include <grpc/impl/codegen/grpc_types.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string_util.h> +#include <grpc/support/time.h> + +#include "src/core/lib/transport/mdstr_hash_table.h" +#include "src/core/lib/transport/metadata.h" + +// +// grpc_method_config +// + +// bool vtable + +static void* bool_copy(void* valuep) { + bool value = *(bool*)valuep; + bool* new_value = gpr_malloc(sizeof(bool)); + *new_value = value; + return new_value; +} + +static int bool_cmp(void* v1, void* v2) { + bool b1 = *(bool*)v1; + bool b2 = *(bool*)v2; + if (!b1 && b2) return -1; + if (b1 && !b2) return 1; + return 0; +} + +static grpc_mdstr_hash_table_vtable bool_vtable = {gpr_free, bool_copy, + bool_cmp}; + +// timespec vtable + +static void* timespec_copy(void* valuep) { + gpr_timespec value = *(gpr_timespec*)valuep; + gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec)); + *new_value = value; + return new_value; +} + +static int timespec_cmp(void* v1, void* v2) { + return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2); +} + +static grpc_mdstr_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy, + timespec_cmp}; + +// int32 vtable + +static void* int32_copy(void* valuep) { + int32_t value = *(int32_t*)valuep; + int32_t* new_value = gpr_malloc(sizeof(int32_t)); + *new_value = value; + return new_value; +} + +static int int32_cmp(void* v1, void* v2) { + int32_t i1 = *(int32_t*)v1; + int32_t i2 = *(int32_t*)v2; + if (i1 < i2) return -1; + if (i1 > i2) return 1; + return 0; +} + +static grpc_mdstr_hash_table_vtable int32_vtable = {gpr_free, int32_copy, + int32_cmp}; + +// Hash table keys. +#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool +#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec +#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \ + "grpc.max_request_message_bytes" // int32 +#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \ + "grpc.max_response_message_bytes" // int32 + +struct grpc_method_config { + grpc_mdstr_hash_table* table; + grpc_mdstr* wait_for_ready_key; + grpc_mdstr* timeout_key; + grpc_mdstr* max_request_message_bytes_key; + grpc_mdstr* max_response_message_bytes_key; +}; + +grpc_method_config* grpc_method_config_create( + bool* wait_for_ready, gpr_timespec* timeout, + int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) { + grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config)); + memset(method_config, 0, sizeof(grpc_method_config)); + method_config->wait_for_ready_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY); + method_config->timeout_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT); + method_config->max_request_message_bytes_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES); + method_config->max_response_message_bytes_key = + grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES); + grpc_mdstr_hash_table_entry entries[4]; + size_t num_entries = 0; + if (wait_for_ready != NULL) { + entries[num_entries].key = method_config->wait_for_ready_key; + entries[num_entries].value = wait_for_ready; + entries[num_entries].vtable = &bool_vtable; + ++num_entries; + } + if (timeout != NULL) { + entries[num_entries].key = method_config->timeout_key; + entries[num_entries].value = timeout; + entries[num_entries].vtable = ×pec_vtable; + ++num_entries; + } + if (max_request_message_bytes != NULL) { + entries[num_entries].key = method_config->max_request_message_bytes_key; + entries[num_entries].value = max_request_message_bytes; + entries[num_entries].vtable = &int32_vtable; + ++num_entries; + } + if (max_response_message_bytes != NULL) { + entries[num_entries].key = method_config->max_response_message_bytes_key; + entries[num_entries].value = max_response_message_bytes; + entries[num_entries].vtable = &int32_vtable; + ++num_entries; + } + method_config->table = grpc_mdstr_hash_table_create(num_entries, entries); + return method_config; +} + +grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) { + grpc_mdstr_hash_table_ref(method_config->table); + return method_config; +} + +void grpc_method_config_unref(grpc_method_config* method_config) { + if (grpc_mdstr_hash_table_unref(method_config->table)) { + GRPC_MDSTR_UNREF(method_config->wait_for_ready_key); + GRPC_MDSTR_UNREF(method_config->timeout_key); + GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key); + GRPC_MDSTR_UNREF(method_config->max_response_message_bytes_key); + gpr_free(method_config); + } +} + +int grpc_method_config_cmp(const grpc_method_config* method_config1, + const grpc_method_config* method_config2) { + return grpc_mdstr_hash_table_cmp(method_config1->table, + method_config2->table); +} + +const bool* grpc_method_config_get_wait_for_ready( + const grpc_method_config* method_config) { + return grpc_mdstr_hash_table_get(method_config->table, + method_config->wait_for_ready_key); +} + +const gpr_timespec* grpc_method_config_get_timeout( + const grpc_method_config* method_config) { + return grpc_mdstr_hash_table_get(method_config->table, + method_config->timeout_key); +} + +const int32_t* grpc_method_config_get_max_request_message_bytes( + const grpc_method_config* method_config) { + return grpc_mdstr_hash_table_get( + method_config->table, method_config->max_request_message_bytes_key); +} + +const int32_t* grpc_method_config_get_max_response_message_bytes( + const grpc_method_config* method_config) { + return grpc_mdstr_hash_table_get( + method_config->table, method_config->max_response_message_bytes_key); +} + +// +// grpc_method_config_table +// + +static void method_config_unref(void* valuep) { + grpc_method_config_unref(valuep); +} + +static void* method_config_ref(void* valuep) { + return grpc_method_config_ref(valuep); +} + +static int method_config_cmp(void* valuep1, void* valuep2) { + return grpc_method_config_cmp(valuep1, valuep2); +} + +static const grpc_mdstr_hash_table_vtable method_config_table_vtable = { + method_config_unref, method_config_ref, method_config_cmp}; + +grpc_method_config_table* grpc_method_config_table_create( + size_t num_entries, grpc_method_config_table_entry* entries) { + grpc_mdstr_hash_table_entry* hash_table_entries = + gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) * num_entries); + for (size_t i = 0; i < num_entries; ++i) { + hash_table_entries[i].key = entries[i].method_name; + hash_table_entries[i].value = entries[i].method_config; + hash_table_entries[i].vtable = &method_config_table_vtable; + } + grpc_method_config_table* method_config_table = + grpc_mdstr_hash_table_create(num_entries, hash_table_entries); + gpr_free(hash_table_entries); + return method_config_table; +} + +grpc_method_config_table* grpc_method_config_table_ref( + grpc_method_config_table* table) { + return grpc_mdstr_hash_table_ref(table); +} + +void grpc_method_config_table_unref(grpc_method_config_table* table) { + grpc_mdstr_hash_table_unref(table); +} + +int grpc_method_config_table_cmp(const grpc_method_config_table* table1, + const grpc_method_config_table* table2) { + return grpc_mdstr_hash_table_cmp(table1, table2); +} + +grpc_method_config* grpc_method_config_table_get_method_config( + const grpc_method_config_table* table, const grpc_mdstr* path) { + grpc_method_config* method_config = grpc_mdstr_hash_table_get(table, path); + // If we didn't find a match for the path, try looking for a wildcard + // entry (i.e., change "/service/method" to "/service/*"). + if (method_config == NULL) { + const char* path_str = grpc_mdstr_as_c_string(path); + const char* sep = strrchr(path_str, '/') + 1; + const size_t len = (size_t)(sep - path_str); + char* buf = gpr_malloc(len + 2); // '*' and NUL + memcpy(buf, path_str, len); + buf[len] = '*'; + buf[len + 1] = '\0'; + grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf); + gpr_free(buf); + method_config = grpc_mdstr_hash_table_get(table, wildcard_path); + GRPC_MDSTR_UNREF(wildcard_path); + } + return method_config; +} + +static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); } + +static void destroy_arg(void* p) { grpc_method_config_table_unref(p); } + +static int cmp_arg(void* p1, void* p2) { + return grpc_method_config_table_cmp(p1, p2); +} + +static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg}; + +grpc_arg grpc_method_config_table_create_channel_arg( + grpc_method_config_table* table) { + grpc_arg arg; + arg.type = GRPC_ARG_POINTER; + arg.key = GRPC_ARG_SERVICE_CONFIG; + arg.value.pointer.p = table; + arg.value.pointer.vtable = &arg_vtable; + return arg; +} diff --git a/src/core/ext/client_channel/method_config.h b/src/core/ext/client_channel/method_config.h new file mode 100644 index 0000000000..75b32fcb17 --- /dev/null +++ b/src/core/ext/client_channel/method_config.h @@ -0,0 +1,116 @@ +// +// Copyright 2016, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_METHOD_CONFIG_H +#define GRPC_CORE_EXT_CLIENT_CHANNEL_METHOD_CONFIG_H + +#include <stdbool.h> + +#include <grpc/impl/codegen/gpr_types.h> +#include <grpc/impl/codegen/grpc_types.h> + +#include "src/core/lib/transport/mdstr_hash_table.h" +#include "src/core/lib/transport/metadata.h" + +/// Per-method configuration. +typedef struct grpc_method_config grpc_method_config; + +/// Creates a grpc_method_config with the specified parameters. +/// Any parameter may be NULL to indicate that the value is unset. +/// +/// \a wait_for_ready indicates whether the client should wait until the +/// request deadline for the channel to become ready, even if there is a +/// temporary failure before the deadline while attempting to connect. +/// +/// \a timeout indicates the timeout for calls. +/// +/// \a max_request_message_bytes and \a max_response_message_bytes +/// indicate the maximum sizes of the request (checked when sending) and +/// response (checked when receiving) messages. +grpc_method_config* grpc_method_config_create( + bool* wait_for_ready, gpr_timespec* timeout, + int32_t* max_request_message_bytes, int32_t* max_response_message_bytes); + +grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config); +void grpc_method_config_unref(grpc_method_config* method_config); + +/// Compares two grpc_method_configs. +/// The sort order is stable but undefined. +int grpc_method_config_cmp(const grpc_method_config* method_config1, + const grpc_method_config* method_config2); + +/// These methods return NULL if the requested field is unset. +/// The caller does NOT take ownership of the result. +const bool* grpc_method_config_get_wait_for_ready( + const grpc_method_config* method_config); +const gpr_timespec* grpc_method_config_get_timeout( + const grpc_method_config* method_config); +const int32_t* grpc_method_config_get_max_request_message_bytes( + const grpc_method_config* method_config); +const int32_t* grpc_method_config_get_max_response_message_bytes( + const grpc_method_config* method_config); + +/// A table of method configs. +typedef grpc_mdstr_hash_table grpc_method_config_table; + +typedef struct grpc_method_config_table_entry { + /// The name is of one of the following forms: + /// service/method -- specifies exact service and method name + /// service/* -- matches all methods for the specified service + grpc_mdstr* method_name; + grpc_method_config* method_config; +} grpc_method_config_table_entry; + +/// Takes new references to all keys and values in \a entries. +grpc_method_config_table* grpc_method_config_table_create( + size_t num_entries, grpc_method_config_table_entry* entries); + +grpc_method_config_table* grpc_method_config_table_ref( + grpc_method_config_table* table); +void grpc_method_config_table_unref(grpc_method_config_table* table); + +/// Compares two grpc_method_config_tables. +/// The sort order is stable but undefined. +int grpc_method_config_table_cmp(const grpc_method_config_table* table1, + const grpc_method_config_table* table2); + +/// Gets the method config for the specified \a path, which should be of +/// the form "/service/method". +/// Returns NULL if the method has no config. +/// Caller does NOT own a reference to the result. +grpc_method_config* grpc_method_config_table_get_method_config( + const grpc_method_config_table* table, const grpc_mdstr* path); + +/// Returns a channel arg containing \a table. +grpc_arg grpc_method_config_table_create_channel_arg( + grpc_method_config_table* table); + +#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_METHOD_CONFIG_H */ diff --git a/src/core/ext/client_channel/resolver_result.h b/src/core/ext/client_channel/resolver_result.h index 7107d2ed59..5421fd9470 100644 --- a/src/core/ext/client_channel/resolver_result.h +++ b/src/core/ext/client_channel/resolver_result.h @@ -51,22 +51,17 @@ typedef struct grpc_resolver_result grpc_resolver_result; grpc_resolver_result* grpc_resolver_result_create( const char* server_name, grpc_lb_addresses* addresses, const char* lb_policy_name, grpc_channel_args* lb_policy_args); + void grpc_resolver_result_ref(grpc_resolver_result* result); void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx, grpc_resolver_result* result); -/// Caller does NOT take ownership of result. +/// Accessors. Caller does NOT take ownership of results. const char* grpc_resolver_result_get_server_name(grpc_resolver_result* result); - -/// Caller does NOT take ownership of result. grpc_lb_addresses* grpc_resolver_result_get_addresses( grpc_resolver_result* result); - -/// Caller does NOT take ownership of result. const char* grpc_resolver_result_get_lb_policy_name( grpc_resolver_result* result); - -/// Caller does NOT take ownership of result. grpc_channel_args* grpc_resolver_result_get_lb_policy_args( grpc_resolver_result* result); diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c index ad229e045b..672e5c3a91 100644 --- a/src/core/ext/client_channel/subchannel.c +++ b/src/core/ext/client_channel/subchannel.c @@ -220,8 +220,8 @@ static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta, : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); #ifdef GRPC_STREAM_REFCOUNT_DEBUG gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "SUBCHANNEL: %p %12s 0x%08d -> 0x%08d [%s]", c, purpose, (int)old_val, - (int)(old_val + delta), reason); + "SUBCHANNEL: %p %s 0x%08" PRIxPTR " -> 0x%08" PRIxPTR " [%s]", c, + purpose, old_val, old_val + delta, reason); #endif return old_val; } @@ -704,7 +704,7 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel( grpc_error *grpc_connected_subchannel_create_call( grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, - grpc_polling_entity *pollent, gpr_timespec deadline, + grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline, grpc_subchannel_call **call) { grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); *call = gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); @@ -712,7 +712,7 @@ grpc_error *grpc_connected_subchannel_create_call( (*call)->connection = con; // Ref is added below. grpc_error *error = grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, *call, - NULL, NULL, deadline, callstk); + NULL, NULL, path, deadline, callstk); if (error != GRPC_ERROR_NONE) { const char *error_string = grpc_error_string(error); gpr_log(GPR_ERROR, "error: %s", error_string); diff --git a/src/core/ext/client_channel/subchannel.h b/src/core/ext/client_channel/subchannel.h index 2ba35c7f1b..c4a7da0c24 100644 --- a/src/core/ext/client_channel/subchannel.h +++ b/src/core/ext/client_channel/subchannel.h @@ -38,6 +38,7 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/transport/connectivity_state.h" +#include "src/core/lib/transport/metadata.h" /** A (sub-)channel that knows how to connect to exactly one target address. Provides a target for load balancing. */ @@ -110,7 +111,7 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, /** construct a subchannel call */ grpc_error *grpc_connected_subchannel_create_call( grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel, - grpc_polling_entity *pollent, gpr_timespec deadline, + grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline, grpc_subchannel_call **subchannel_call); /** process a transport level op */ diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c index 9cd1c077d8..412090158a 100644 --- a/src/core/ext/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/lb_policy/grpclb/grpclb.c @@ -69,8 +69,8 @@ * possible scenarios: * * 1. This is the first server list received. There was no previous instance of - * the Round Robin policy. \a rr_handover() will instantiate the RR policy - * and perform all the pending operations over it. + * the Round Robin policy. \a rr_handover_locked() will instantiate the RR + * policy and perform all the pending operations over it. * 2. There's already a RR policy instance active. We need to introduce the new * one build from the new serverlist, but taking care not to disrupt the * operations in progress over the old RR instance. This is done by @@ -78,7 +78,7 @@ * references are held on the old RR policy, it'll be destroyed and \a * glb_rr_connectivity_changed notified with a \a GRPC_CHANNEL_SHUTDOWN * state. At this point we can transition to a new RR instance safely, which - * is done once again via \a rr_handover(). + * is done once again via \a rr_handover_locked(). * * * Once a RR policy instance is in place (and getting updated as described), @@ -86,8 +86,8 @@ * forwarding them to the RR instance. Any time there's no RR policy available * (ie, right after the creation of the gRPCLB policy, if an empty serverlist * is received, etc), pick/ping requests are added to a list of pending - * picks/pings to be flushed and serviced as part of \a rr_handover() the moment - * the RR policy instance becomes available. + * picks/pings to be flushed and serviced as part of \a rr_handover_locked() the + * moment the RR policy instance becomes available. * * \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the * high level design and details. */ @@ -113,6 +113,7 @@ #include "src/core/ext/client_channel/parse_address.h" #include "src/core/ext/lb_policy/grpclb/grpclb.h" #include "src/core/ext/lb_policy/grpclb/load_balancer_api.h" +#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/support/string.h" @@ -134,6 +135,9 @@ static void initial_metadata_add_lb_token( } typedef struct wrapped_rr_closure_arg { + /* the closure instance using this struct as argument */ + grpc_closure wrapper_closure; + /* the original closure. Usually a on_complete/notify cb for pick() and ping() * calls against the internal RR instance, respectively. */ grpc_closure *wrapped_closure; @@ -155,9 +159,8 @@ typedef struct wrapped_rr_closure_arg { /* The RR instance related to the closure */ grpc_lb_policy *rr_policy; - /* when not NULL, represents a pending_{pick,ping} node to be freed upon - * closure execution */ - void *owning_pending_node; /* to be freed if not NULL */ + /* heap memory to be freed upon closure execution. */ + void *free_when_done; } wrapped_rr_closure_arg; /* The \a on_complete closure passed as part of the pick requires keeping a @@ -183,10 +186,10 @@ static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg, } } GPR_ASSERT(wc_arg->wrapped_closure != NULL); - grpc_exec_ctx_sched(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_REF(error), NULL); - gpr_free(wc_arg->owning_pending_node); + GPR_ASSERT(wc_arg->free_when_done != NULL); + gpr_free(wc_arg->free_when_done); } /* Linked list of pending pick requests. It stores all information needed to @@ -207,10 +210,6 @@ typedef struct pending_pick { * upon error. */ grpc_connected_subchannel **target; - /* a closure wrapping the original on_complete one to be invoked once the - * pick() has completed (regardless of success) */ - grpc_closure wrapped_on_complete; - /* args for wrapped_on_complete */ wrapped_rr_closure_arg wrapped_on_complete_arg; } pending_pick; @@ -230,8 +229,9 @@ static void add_pending_pick(pending_pick **root, pp->wrapped_on_complete_arg.initial_metadata = pick_args->initial_metadata; pp->wrapped_on_complete_arg.lb_token_mdelem_storage = pick_args->lb_token_mdelem_storage; - grpc_closure_init(&pp->wrapped_on_complete, wrapped_rr_closure, - &pp->wrapped_on_complete_arg); + pp->wrapped_on_complete_arg.free_when_done = pp; + grpc_closure_init(&pp->wrapped_on_complete_arg.wrapper_closure, + wrapped_rr_closure, &pp->wrapped_on_complete_arg); *root = pp; } @@ -239,10 +239,6 @@ static void add_pending_pick(pending_pick **root, typedef struct pending_ping { struct pending_ping *next; - /* a closure wrapping the original on_complete one to be invoked once the - * ping() has completed (regardless of success) */ - grpc_closure wrapped_notify; - /* args for wrapped_notify */ wrapped_rr_closure_arg wrapped_notify_arg; } pending_ping; @@ -251,10 +247,11 @@ static void add_pending_ping(pending_ping **root, grpc_closure *notify) { pending_ping *pping = gpr_malloc(sizeof(*pping)); memset(pping, 0, sizeof(pending_ping)); memset(&pping->wrapped_notify_arg, 0, sizeof(wrapped_rr_closure_arg)); - pping->next = *root; - grpc_closure_init(&pping->wrapped_notify, wrapped_rr_closure, - &pping->wrapped_notify_arg); pping->wrapped_notify_arg.wrapped_closure = notify; + pping->wrapped_notify_arg.free_when_done = pping; + pping->next = *root; + grpc_closure_init(&pping->wrapped_notify_arg.wrapper_closure, + wrapped_rr_closure, &pping->wrapped_notify_arg); *root = pping; } @@ -274,6 +271,7 @@ typedef struct glb_lb_policy { /** who the client is trying to communicate with */ const char *server_name; grpc_client_channel_factory *cc_factory; + grpc_channel_args *args; /** deadline for the LB's call */ gpr_timespec deadline; @@ -307,13 +305,6 @@ typedef struct glb_lb_policy { /** for tracking of the RR connectivity */ rr_connectivity_data *rr_connectivity; - - /* a wrapped (see \a wrapped_rr_closure) on-complete closure for readily - * available RR picks */ - grpc_closure wrapped_on_complete; - - /* arguments for the wrapped_on_complete closure */ - wrapped_rr_closure_arg wc_arg; } glb_lb_policy; /* Keeps track and reacts to changes in connectivity of the RR instance */ @@ -329,8 +320,8 @@ static bool is_server_valid(const grpc_grpclb_server *server, size_t idx, if (server->port >> 16 != 0) { if (log) { gpr_log(GPR_ERROR, - "Invalid port '%d' at index %zu of serverlist. Ignoring.", - server->port, idx); + "Invalid port '%d' at index %lu of serverlist. Ignoring.", + server->port, (unsigned long)idx); } return false; } @@ -338,9 +329,9 @@ static bool is_server_valid(const grpc_grpclb_server *server, size_t idx, if (ip->size != 4 && ip->size != 16) { if (log) { gpr_log(GPR_ERROR, - "Expected IP to be 4 or 16 bytes, got %d at index %zu of " + "Expected IP to be 4 or 16 bytes, got %d at index %lu of " "serverlist. Ignoring", - ip->size, idx); + ip->size, (unsigned long)idx); } return false; } @@ -399,14 +390,14 @@ static grpc_lb_addresses *process_serverlist( GPR_ARRAY_SIZE(server->load_balance_token) - 1; grpc_mdstr *lb_token_mdstr = grpc_mdstr_from_buffer( (uint8_t *)server->load_balance_token, lb_token_size); - user_data = grpc_mdelem_from_metadata_strings( - GRPC_MDSTR_LOAD_REPORTING_INITIAL, lb_token_mdstr); + user_data = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_LB_TOKEN, + lb_token_mdstr); } else { gpr_log(GPR_ERROR, "Missing LB token for backend address '%s'. The empty token will " "be used instead", grpc_sockaddr_to_uri((struct sockaddr *)&addr.addr)); - user_data = GRPC_MDELEM_LOAD_REPORTING_INITIAL_EMPTY; + user_data = GRPC_MDELEM_LB_TOKEN_EMPTY; } grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, @@ -424,9 +415,43 @@ static void lb_token_destroy(void *token) { if (token != NULL) GRPC_MDELEM_UNREF(token); } -static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx, - const grpc_grpclb_serverlist *serverlist, - glb_lb_policy *glb_policy) { +/* perform a pick over \a rr_policy. Given that a pick can return immediately + * (ignoring its completion callback) we need to perform the cleanups this + * callback would be otherwise resposible for */ +static bool pick_from_internal_rr_locked( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *rr_policy, + const grpc_lb_policy_pick_args *pick_args, + grpc_connected_subchannel **target, wrapped_rr_closure_arg *wc_arg) { + GPR_ASSERT(rr_policy != NULL); + const bool pick_done = + grpc_lb_policy_pick(exec_ctx, rr_policy, pick_args, target, + (void **)&wc_arg->lb_token, &wc_arg->wrapper_closure); + if (pick_done) { + /* synchronous grpc_lb_policy_pick call. Unref the RR policy. */ + if (grpc_lb_glb_trace) { + gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")", + (intptr_t)wc_arg->rr_policy); + } + GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "glb_pick"); + + /* add the load reporting initial metadata */ + initial_metadata_add_lb_token(pick_args->initial_metadata, + pick_args->lb_token_mdelem_storage, + GRPC_MDELEM_REF(wc_arg->lb_token)); + + gpr_free(wc_arg); + } + /* else, the pending pick will be registered and taken care of by the + * pending pick list inside the RR policy (glb_policy->rr_policy). + * Eventually, wrapped_on_complete will be called, which will -among other + * things- add the LB token to the call's initial metadata */ + + return pick_done; +} + +static grpc_lb_policy *create_rr_locked( + grpc_exec_ctx *exec_ctx, const grpc_grpclb_serverlist *serverlist, + glb_lb_policy *glb_policy) { GPR_ASSERT(serverlist != NULL && serverlist->num_servers > 0); grpc_lb_policy_args args; @@ -434,6 +459,7 @@ static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx, args.server_name = glb_policy->server_name; args.client_channel_factory = glb_policy->cc_factory; args.addresses = process_serverlist(serverlist); + args.additional_args = glb_policy->args; grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args); @@ -446,18 +472,21 @@ static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx, return rr; } -static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, - grpc_error *error) { +static void rr_handover_locked(grpc_exec_ctx *exec_ctx, + glb_lb_policy *glb_policy, grpc_error *error) { GPR_ASSERT(glb_policy->serverlist != NULL && glb_policy->serverlist->num_servers > 0); glb_policy->rr_policy = - create_rr(exec_ctx, glb_policy->serverlist, glb_policy); + create_rr_locked(exec_ctx, glb_policy->serverlist, glb_policy); if (grpc_lb_glb_trace) { gpr_log(GPR_INFO, "Created RR policy (0x%" PRIxPTR ")", (intptr_t)glb_policy->rr_policy); } GPR_ASSERT(glb_policy->rr_policy != NULL); + grpc_pollset_set_add_pollset_set(exec_ctx, + glb_policy->rr_policy->interested_parties, + glb_policy->base.interested_parties); glb_policy->rr_connectivity->state = grpc_lb_policy_check_connectivity( exec_ctx, glb_policy->rr_policy, &error); grpc_lb_policy_notify_on_state_change( @@ -478,11 +507,9 @@ static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, gpr_log(GPR_INFO, "Pending pick about to PICK from 0x%" PRIxPTR "", (intptr_t)glb_policy->rr_policy); } - grpc_lb_policy_pick(exec_ctx, glb_policy->rr_policy, &pp->pick_args, - pp->target, - (void **)&pp->wrapped_on_complete_arg.lb_token, - &pp->wrapped_on_complete); - pp->wrapped_on_complete_arg.owning_pending_node = pp; + pick_from_internal_rr_locked(exec_ctx, glb_policy->rr_policy, + &pp->pick_args, pp->target, + &pp->wrapped_on_complete_arg); } pending_ping *pping; @@ -495,8 +522,7 @@ static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy, (intptr_t)glb_policy->rr_policy); } grpc_lb_policy_ping_one(exec_ctx, glb_policy->rr_policy, - &pping->wrapped_notify); - pping->wrapped_notify_arg.owning_pending_node = pping; + &pping->wrapped_notify_arg.wrapper_closure); } } @@ -509,13 +535,16 @@ static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, if (glb_policy->serverlist != NULL) { /* a RR policy is shutting down but there's a serverlist available -> * perform a handover */ - rr_handover(exec_ctx, glb_policy, error); + gpr_mu_lock(&glb_policy->mu); + rr_handover_locked(exec_ctx, glb_policy, error); + gpr_mu_unlock(&glb_policy->mu); } else { /* shutting down and no new serverlist available. Bail out. */ gpr_free(rr_conn_data); } } else { if (error == GRPC_ERROR_NONE) { + gpr_mu_lock(&glb_policy->mu); /* RR not shutting down. Mimic the RR's policy state */ grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker, rr_conn_data->state, GRPC_ERROR_REF(error), @@ -524,6 +553,7 @@ static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy, &rr_conn_data->state, &rr_conn_data->on_change); + gpr_mu_unlock(&glb_policy->mu); } else { /* error */ gpr_free(rr_conn_data); } @@ -557,6 +587,7 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx, * Create a client channel over them to communicate with a LB service */ glb_policy->server_name = gpr_strdup(args->server_name); glb_policy->cc_factory = args->client_channel_factory; + glb_policy->args = grpc_channel_args_copy(args->additional_args); GPR_ASSERT(glb_policy->cc_factory != NULL); /* construct a target from the addresses in args, given in the form @@ -623,6 +654,7 @@ static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { GPR_ASSERT(glb_policy->pending_picks == NULL); GPR_ASSERT(glb_policy->pending_pings == NULL); gpr_free((void *)glb_policy->server_name); + grpc_channel_args_destroy(glb_policy->args); grpc_channel_destroy(glb_policy->lb_channel); glb_policy->lb_channel = NULL; grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker); @@ -648,15 +680,15 @@ static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { while (pp != NULL) { pending_pick *next = pp->next; *pp->target = NULL; - grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete, GRPC_ERROR_NONE, - NULL); + grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, + GRPC_ERROR_NONE, NULL); pp = next; } while (pping != NULL) { pending_ping *next = pping->next; - grpc_exec_ctx_sched(exec_ctx, &pping->wrapped_notify, GRPC_ERROR_NONE, - NULL); + grpc_exec_ctx_sched(exec_ctx, &pping->wrapped_notify_arg.wrapper_closure, + GRPC_ERROR_NONE, NULL); pping = next; } @@ -686,11 +718,9 @@ static void glb_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, while (pp != NULL) { pending_pick *next = pp->next; if (pp->target == target) { - grpc_polling_entity_del_from_pollset_set( - exec_ctx, pp->pick_args.pollent, glb_policy->base.interested_parties); *target = NULL; grpc_exec_ctx_sched( - exec_ctx, &pp->wrapped_on_complete, + exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL); } else { pp->next = glb_policy->pending_picks; @@ -719,10 +749,8 @@ static void glb_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, pending_pick *next = pp->next; if ((pp->pick_args.initial_metadata_flags & initial_metadata_flags_mask) == initial_metadata_flags_eq) { - grpc_polling_entity_del_from_pollset_set( - exec_ctx, pp->pick_args.pollent, glb_policy->base.interested_parties); grpc_exec_ctx_sched( - exec_ctx, &pp->wrapped_on_complete, + exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure, GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL); } else { pp->next = glb_policy->pending_picks; @@ -761,7 +789,7 @@ static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, GRPC_ERROR_CREATE("No mdelem storage for the LB token. Load reporting " "won't work without it. Failing"), NULL); - return 1; + return 0; } glb_lb_policy *glb_policy = (glb_lb_policy *)pol; @@ -775,39 +803,20 @@ static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, (intptr_t)glb_policy->rr_policy); } GRPC_LB_POLICY_REF(glb_policy->rr_policy, "glb_pick"); - memset(&glb_policy->wc_arg, 0, sizeof(wrapped_rr_closure_arg)); - glb_policy->wc_arg.rr_policy = glb_policy->rr_policy; - glb_policy->wc_arg.target = target; - glb_policy->wc_arg.wrapped_closure = on_complete; - glb_policy->wc_arg.lb_token_mdelem_storage = - pick_args->lb_token_mdelem_storage; - glb_policy->wc_arg.initial_metadata = pick_args->initial_metadata; - glb_policy->wc_arg.owning_pending_node = NULL; - grpc_closure_init(&glb_policy->wrapped_on_complete, wrapped_rr_closure, - &glb_policy->wc_arg); - - pick_done = - grpc_lb_policy_pick(exec_ctx, glb_policy->rr_policy, pick_args, target, - (void **)&glb_policy->wc_arg.lb_token, - &glb_policy->wrapped_on_complete); - if (pick_done) { - /* synchronous grpc_lb_policy_pick call. Unref the RR policy. */ - if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")", - (intptr_t)glb_policy->wc_arg.rr_policy); - } - GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->wc_arg.rr_policy, "glb_pick"); - /* add the load reporting initial metadata */ - initial_metadata_add_lb_token( - pick_args->initial_metadata, pick_args->lb_token_mdelem_storage, - GRPC_MDELEM_REF(glb_policy->wc_arg.lb_token)); - } + wrapped_rr_closure_arg *wc_arg = gpr_malloc(sizeof(wrapped_rr_closure_arg)); + memset(wc_arg, 0, sizeof(wrapped_rr_closure_arg)); + + grpc_closure_init(&wc_arg->wrapper_closure, wrapped_rr_closure, wc_arg); + wc_arg->rr_policy = glb_policy->rr_policy; + wc_arg->target = target; + wc_arg->wrapped_closure = on_complete; + wc_arg->lb_token_mdelem_storage = pick_args->lb_token_mdelem_storage; + wc_arg->initial_metadata = pick_args->initial_metadata; + wc_arg->free_when_done = wc_arg; + pick_done = pick_from_internal_rr_locked(exec_ctx, glb_policy->rr_policy, + pick_args, target, wc_arg); } else { - /* else, the pending pick will be registered and taken care of by the - * pending pick list inside the RR policy (glb_policy->rr_policy) */ - grpc_polling_entity_add_to_pollset_set(exec_ctx, pick_args->pollent, - glb_policy->base.interested_parties); add_pending_pick(&glb_policy->pending_picks, pick_args, target, on_complete); @@ -931,7 +940,7 @@ static lb_client_data *lb_client_data_create(glb_lb_policy *glb_policy) { /* Note the following LB call progresses every time there's activity in \a * glb_policy->base.interested_parties, which is comprised of the polling - * entities passed to glb_pick(). */ + * entities from \a client_channel. */ lb_client->lb_call = grpc_channel_create_pollset_set_call( glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS, glb_policy->base.interested_parties, @@ -1070,12 +1079,13 @@ static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { if (serverlist != NULL) { gpr_slice_unref(response_slice); if (grpc_lb_glb_trace) { - gpr_log(GPR_INFO, "Serverlist with %zu servers received", - serverlist->num_servers); + gpr_log(GPR_INFO, "Serverlist with %lu servers received", + (unsigned long)serverlist->num_servers); } /* update serverlist */ if (serverlist->num_servers > 0) { + gpr_mu_lock(&lb_client->glb_policy->mu); if (grpc_grpclb_serverlist_equals(lb_client->glb_policy->serverlist, serverlist)) { if (grpc_lb_glb_trace) { @@ -1093,7 +1103,7 @@ static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { if (lb_client->glb_policy->rr_policy == NULL) { /* initial "handover", in this case from a null RR policy, meaning * it'll just create the first RR policy instance */ - rr_handover(exec_ctx, lb_client->glb_policy, error); + rr_handover_locked(exec_ctx, lb_client->glb_policy, error); } else { /* unref the RR policy, eventually leading to its substitution with a * new one constructed from the received serverlist (see @@ -1101,6 +1111,7 @@ static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { GRPC_LB_POLICY_UNREF(exec_ctx, lb_client->glb_policy->rr_policy, "serverlist_received"); } + gpr_mu_unlock(&lb_client->glb_policy->mu); } else { if (grpc_lb_glb_trace) { gpr_log(GPR_INFO, @@ -1155,10 +1166,10 @@ static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg, if (grpc_lb_glb_trace) { gpr_log(GPR_INFO, "status from lb server received. Status = %d, Details = '%s', " - "Capaticy " - "= %zu", + "Capacity " + "= %lu", lb_client->status, lb_client->status_details, - lb_client->status_details_capacity); + (unsigned long)lb_client->status_details_capacity); } /* TODO(dgq): deal with stream termination properly (fire up another one? * fail the original call?) */ diff --git a/src/core/ext/lb_policy/pick_first/pick_first.c b/src/core/ext/lb_policy/pick_first/pick_first.c index ac0c09f482..270fe3fe70 100644 --- a/src/core/ext/lb_policy/pick_first/pick_first.c +++ b/src/core/ext/lb_policy/pick_first/pick_first.c @@ -39,7 +39,6 @@ typedef struct pending_pick { struct pending_pick *next; - grpc_polling_entity *pollent; uint32_t initial_metadata_flags; grpc_connected_subchannel **target; grpc_closure *on_complete; @@ -119,8 +118,6 @@ static void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { while (pp != NULL) { pending_pick *next = pp->next; *pp->target = NULL; - grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, - p->base.interested_parties); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL); gpr_free(pp); pp = next; @@ -138,8 +135,6 @@ static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, while (pp != NULL) { pending_pick *next = pp->next; if (pp->target == target) { - grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, - p->base.interested_parties); *target = NULL; grpc_exec_ctx_sched( exec_ctx, pp->on_complete, @@ -168,8 +163,6 @@ static void pf_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, pending_pick *next = pp->next; if ((pp->initial_metadata_flags & initial_metadata_flags_mask) == initial_metadata_flags_eq) { - grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, - p->base.interested_parties); grpc_exec_ctx_sched( exec_ctx, pp->on_complete, GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL); @@ -229,11 +222,8 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, if (!p->started_picking) { start_picking(exec_ctx, p); } - grpc_polling_entity_add_to_pollset_set(exec_ctx, pick_args->pollent, - p->base.interested_parties); pp = gpr_malloc(sizeof(*pp)); pp->next = p->pending_picks; - pp->pollent = pick_args->pollent; pp->target = target; pp->initial_metadata_flags = pick_args->initial_metadata_flags; pp->on_complete = on_complete; @@ -319,8 +309,6 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, while ((pp = p->pending_picks)) { p->pending_picks = pp->next; *pp->target = selected; - grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, - p->base.interested_parties); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL); gpr_free(pp); } @@ -478,6 +466,7 @@ static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx, sc_args.addr = (struct sockaddr *)(&args->addresses->addresses[i].address.addr); sc_args.addr_len = args->addresses->addresses[i].address.len; + sc_args.args = args->additional_args; grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( exec_ctx, args->client_channel_factory, &sc_args); diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c index c344312e39..b32f6be99e 100644 --- a/src/core/ext/lb_policy/round_robin/round_robin.c +++ b/src/core/ext/lb_policy/round_robin/round_robin.c @@ -78,9 +78,6 @@ int grpc_lb_round_robin_trace = 0; typedef struct pending_pick { struct pending_pick *next; - /* polling entity for the pick()'s async notification */ - grpc_polling_entity *pollent; - /* output argument where to store the pick()ed user_data. It'll be NULL if no * such data is present or there's an error (the definite test for errors is * \a target being NULL). */ @@ -318,8 +315,6 @@ static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, while (pp != NULL) { pending_pick *next = pp->next; if (pp->target == target) { - grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, - p->base.interested_parties); *target = NULL; grpc_exec_ctx_sched( exec_ctx, pp->on_complete, @@ -348,8 +343,6 @@ static void rr_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, pending_pick *next = pp->next; if ((pp->initial_metadata_flags & initial_metadata_flags_mask) == initial_metadata_flags_eq) { - grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, - p->base.interested_parties); *pp->target = NULL; grpc_exec_ctx_sched( exec_ctx, pp->on_complete, @@ -403,7 +396,6 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, gpr_mu_lock(&p->mu); if ((selected = peek_next_connected_locked(p))) { /* readily available, report right away */ - gpr_mu_unlock(&p->mu); *target = grpc_subchannel_get_connected_subchannel(selected->subchannel); if (user_data != NULL) { @@ -416,17 +408,15 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, } /* only advance the last picked pointer if the selection was used */ advance_last_picked_locked(p); + gpr_mu_unlock(&p->mu); return 1; } else { /* no pick currently available. Save for later in list of pending picks */ if (!p->started_picking) { start_picking(exec_ctx, p); } - grpc_polling_entity_add_to_pollset_set(exec_ctx, pick_args->pollent, - p->base.interested_parties); pp = gpr_malloc(sizeof(*pp)); pp->next = p->pending_picks; - pp->pollent = pick_args->pollent; pp->target = target; pp->on_complete = on_complete; pp->initial_metadata_flags = pick_args->initial_metadata_flags; @@ -482,8 +472,6 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)", (void *)selected->subchannel, (void *)selected); } - grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, - p->base.interested_parties); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL); gpr_free(pp); } @@ -641,6 +629,7 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx, sc_args.addr = (struct sockaddr *)(&args->addresses->addresses[i].address.addr); sc_args.addr_len = args->addresses->addresses[i].address.len; + sc_args.args = args->additional_args; grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( exec_ctx, args->client_channel_factory, &sc_args); diff --git a/src/core/ext/load_reporting/load_reporting.h b/src/core/ext/load_reporting/load_reporting.h index e37817d8c2..e13097654d 100644 --- a/src/core/ext/load_reporting/load_reporting.h +++ b/src/core/ext/load_reporting/load_reporting.h @@ -37,13 +37,21 @@ #include <grpc/impl/codegen/grpc_types.h> #include "src/core/lib/channel/channel_stack.h" -/** Metadata key for initial metadata coming from clients */ -/* TODO(dgq): change to the final value TBD */ -#define GRPC_LOAD_REPORTING_INITIAL_MD_KEY "load-reporting-initial" +/** Metadata key for the gRPC LB load balancer token. + * + * The value corresponding to this key is an opaque token that is given to the + * frontend as part of each pick; the frontend sends this token to the backend + * in each request it sends when using that pick. The token is used by the + * backend to verify the request and to allow the backend to report load to the + * gRPC LB system. */ +#define GRPC_LB_TOKEN_MD_KEY "lb-token" -/** Metadata key for trailing metadata from servers */ -/* TODO(dgq): change to the final value TBD */ -#define GRPC_LOAD_REPORTING_TRAILING_MD_KEY "load-reporting-trailing" +/** Metadata key for gRPC LB cost reporting. + * + * The value corresponding to this key is an opaque binary blob reported by the + * backend as part of its trailing metadata containing cost information for the + * call. */ +#define GRPC_LB_COST_MD_KEY "lb-cost" /** Identifiers for the invocation point of the users LR callback */ typedef enum grpc_load_reporting_source { diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c index 394f0cb832..22bf36367f 100644 --- a/src/core/ext/load_reporting/load_reporting_filter.c +++ b/src/core/ext/load_reporting/load_reporting_filter.c @@ -75,7 +75,7 @@ static grpc_mdelem *recv_md_filter(void *user_data, grpc_mdelem *md) { if (md->key == GRPC_MDSTR_PATH) { calld->service_method = grpc_mdstr_as_c_string(md->value); - } else if (md->key == GRPC_MDSTR_LOAD_REPORTING_INITIAL) { + } else if (md->key == GRPC_MDSTR_LB_TOKEN) { calld->initial_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value)); return NULL; } @@ -193,7 +193,7 @@ static grpc_mdelem *lr_trailing_md_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; - if (md->key == GRPC_MDSTR_LOAD_REPORTING_TRAILING) { + if (md->key == GRPC_MDSTR_LB_COST) { calld->trailing_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value)); return NULL; } diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c index 4293c4d23f..9924fc6fec 100644 --- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c +++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c @@ -33,6 +33,7 @@ #include <stdbool.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <grpc/support/alloc.h> @@ -119,7 +120,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, *r->target_result = grpc_resolver_result_create( r->target_name, grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */), - NULL /* lb_policy_name */, NULL); + NULL /* lb_policy_name */, NULL /* lb_policy_args */); grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL); r->next_completion = NULL; } @@ -128,8 +129,8 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) { sockaddr_resolver *r = (sockaddr_resolver *)gr; gpr_mu_destroy(&r->mu); - grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */); gpr_free(r->target_name); + grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */); gpr_free(r); } diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c index da3e284fcf..563271f4f8 100644 --- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c +++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c @@ -61,13 +61,12 @@ typedef struct server_secure_state { grpc_server_credentials *creds; bool is_shutdown; gpr_mu mu; - gpr_refcount refcount; - grpc_closure destroy_closure; - grpc_closure *destroy_callback; + grpc_closure tcp_server_shutdown_complete; + grpc_closure *server_destroy_listener_done; } server_secure_state; typedef struct server_secure_connect { - server_secure_state *state; + server_secure_state *server_state; grpc_pollset *accepting_pollset; grpc_tcp_server_acceptor *acceptor; grpc_handshake_manager *handshake_mgr; @@ -77,39 +76,28 @@ typedef struct server_secure_connect { grpc_channel_args *args; } server_secure_connect; -static void state_ref(server_secure_state *state) { gpr_ref(&state->refcount); } - -static void state_unref(server_secure_state *state) { - if (gpr_unref(&state->refcount)) { - /* ensure all threads have unlocked */ - gpr_mu_lock(&state->mu); - gpr_mu_unlock(&state->mu); - /* clean up */ - GRPC_SECURITY_CONNECTOR_UNREF(&state->sc->base, "server"); - grpc_server_credentials_unref(state->creds); - gpr_free(state); - } -} - static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep, grpc_security_status status, grpc_endpoint *secure_endpoint, grpc_auth_context *auth_context) { - server_secure_connect *state = statep; + server_secure_connect *connection_state = statep; if (status == GRPC_SECURITY_OK) { if (secure_endpoint) { - gpr_mu_lock(&state->state->mu); - if (!state->state->is_shutdown) { + gpr_mu_lock(&connection_state->server_state->mu); + if (!connection_state->server_state->is_shutdown) { grpc_transport *transport = grpc_create_chttp2_transport( - exec_ctx, grpc_server_get_channel_args(state->state->server), + exec_ctx, grpc_server_get_channel_args( + connection_state->server_state->server), secure_endpoint, 0); grpc_arg args_to_add[2]; - args_to_add[0] = grpc_server_credentials_to_arg(state->state->creds); + args_to_add[0] = grpc_server_credentials_to_arg( + connection_state->server_state->creds); args_to_add[1] = grpc_auth_context_to_arg(auth_context); grpc_channel_args *args_copy = grpc_channel_args_copy_and_add( - state->args, args_to_add, GPR_ARRAY_SIZE(args_to_add)); - grpc_server_setup_transport(exec_ctx, state->state->server, transport, - state->accepting_pollset, args_copy); + connection_state->args, args_to_add, GPR_ARRAY_SIZE(args_to_add)); + grpc_server_setup_transport( + exec_ctx, connection_state->server_state->server, transport, + connection_state->accepting_pollset, args_copy); grpc_channel_args_destroy(args_copy); grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL); } else { @@ -117,21 +105,21 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep, * gone away. */ grpc_endpoint_destroy(exec_ctx, secure_endpoint); } - gpr_mu_unlock(&state->state->mu); + gpr_mu_unlock(&connection_state->server_state->mu); } } else { gpr_log(GPR_ERROR, "Secure transport failed with error %d", status); } - grpc_channel_args_destroy(state->args); - state_unref(state->state); - gpr_free(state); + grpc_channel_args_destroy(connection_state->args); + grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp); + gpr_free(connection_state); } static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint, grpc_channel_args *args, gpr_slice_buffer *read_buffer, void *user_data, grpc_error *error) { - server_secure_connect *state = user_data; + server_secure_connect *connection_state = user_data; if (error != GRPC_ERROR_NONE) { const char *error_str = grpc_error_string(error); gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str); @@ -139,81 +127,107 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint, GRPC_ERROR_UNREF(error); grpc_channel_args_destroy(args); gpr_free(read_buffer); - grpc_handshake_manager_shutdown(exec_ctx, state->handshake_mgr); - grpc_handshake_manager_destroy(exec_ctx, state->handshake_mgr); - state_unref(state->state); - gpr_free(state); + grpc_handshake_manager_shutdown(exec_ctx, connection_state->handshake_mgr); + grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr); + grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp); + gpr_free(connection_state); return; } - grpc_handshake_manager_destroy(exec_ctx, state->handshake_mgr); - state->handshake_mgr = NULL; + grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr); + connection_state->handshake_mgr = NULL; // TODO(roth, jboeuf): Convert security connector handshaking to use new // handshake API, and then move the code from on_secure_handshake_done() // into this function. - state->args = args; + connection_state->args = args; grpc_server_security_connector_do_handshake( - exec_ctx, state->state->sc, state->acceptor, endpoint, read_buffer, - state->deadline, on_secure_handshake_done, state); + exec_ctx, connection_state->server_state->sc, connection_state->acceptor, + endpoint, read_buffer, connection_state->deadline, + on_secure_handshake_done, connection_state); } static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp, grpc_pollset *accepting_pollset, grpc_tcp_server_acceptor *acceptor) { - server_secure_connect *state = gpr_malloc(sizeof(*state)); - state->state = statep; - state_ref(state->state); - state->accepting_pollset = accepting_pollset; - state->acceptor = acceptor; - state->handshake_mgr = grpc_handshake_manager_create(); + server_secure_state *server_state = statep; + server_secure_connect *connection_state = NULL; + gpr_mu_lock(&server_state->mu); + if (server_state->is_shutdown) { + gpr_mu_unlock(&server_state->mu); + grpc_endpoint_destroy(exec_ctx, tcp); + return; + } + gpr_mu_unlock(&server_state->mu); + grpc_tcp_server_ref(server_state->tcp); + connection_state = gpr_malloc(sizeof(*connection_state)); + connection_state->server_state = server_state; + connection_state->accepting_pollset = accepting_pollset; + connection_state->acceptor = acceptor; + connection_state->handshake_mgr = grpc_handshake_manager_create(); // TODO(roth): We should really get this timeout value from channel // args instead of hard-coding it. - state->deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), - gpr_time_from_seconds(120, GPR_TIMESPAN)); + connection_state->deadline = gpr_time_add( + gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN)); grpc_handshake_manager_do_handshake( - exec_ctx, state->handshake_mgr, tcp, - grpc_server_get_channel_args(state->state->server), state->deadline, - acceptor, on_handshake_done, state); + exec_ctx, connection_state->handshake_mgr, tcp, + grpc_server_get_channel_args(connection_state->server_state->server), + connection_state->deadline, acceptor, on_handshake_done, + connection_state); } /* Server callback: start listening on our ports */ -static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep, - grpc_pollset **pollsets, size_t pollset_count) { - server_secure_state *state = statep; - grpc_tcp_server_start(exec_ctx, state->tcp, pollsets, pollset_count, - on_accept, state); +static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server, + void *statep, grpc_pollset **pollsets, + size_t pollset_count) { + server_secure_state *server_state = statep; + gpr_mu_lock(&server_state->mu); + server_state->is_shutdown = false; + gpr_mu_unlock(&server_state->mu); + grpc_tcp_server_start(exec_ctx, server_state->tcp, pollsets, pollset_count, + on_accept, server_state); } -static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, - grpc_error *error) { - server_secure_state *state = statep; - if (state->destroy_callback != NULL) { - state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg, - GRPC_ERROR_REF(error)); +static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *statep, + grpc_error *error) { + server_secure_state *server_state = statep; + /* ensure all threads have unlocked */ + gpr_mu_lock(&server_state->mu); + grpc_closure *destroy_done = server_state->server_destroy_listener_done; + GPR_ASSERT(server_state->is_shutdown); + gpr_mu_unlock(&server_state->mu); + /* clean up */ + grpc_server_security_connector_shutdown(exec_ctx, server_state->sc); + + /* Flush queued work before a synchronous unref. */ + grpc_exec_ctx_flush(exec_ctx); + GRPC_SECURITY_CONNECTOR_UNREF(&server_state->sc->base, "server"); + grpc_server_credentials_unref(server_state->creds); + + if (destroy_done != NULL) { + destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error)); + grpc_exec_ctx_flush(exec_ctx); } - grpc_server_security_connector_shutdown(exec_ctx, state->sc); - state_unref(state); + gpr_free(server_state); } -/* Server callback: destroy the tcp listener (so we don't generate further - callbacks) */ -static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep, - grpc_closure *callback) { - server_secure_state *state = statep; +static void server_destroy_listener(grpc_exec_ctx *exec_ctx, + grpc_server *server, void *statep, + grpc_closure *callback) { + server_secure_state *server_state = statep; grpc_tcp_server *tcp; - gpr_mu_lock(&state->mu); - state->is_shutdown = true; - state->destroy_callback = callback; - tcp = state->tcp; - gpr_mu_unlock(&state->mu); + gpr_mu_lock(&server_state->mu); + server_state->is_shutdown = true; + server_state->server_destroy_listener_done = callback; + tcp = server_state->tcp; + gpr_mu_unlock(&server_state->mu); grpc_tcp_server_shutdown_listeners(exec_ctx, tcp); - grpc_tcp_server_unref(exec_ctx, tcp); + grpc_tcp_server_unref(exec_ctx, server_state->tcp); } int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) { grpc_resolved_addresses *resolved = NULL; grpc_tcp_server *tcp = NULL; - server_secure_state *state = NULL; + server_secure_state *server_state = NULL; size_t i; size_t count = 0; int port_num = -1; @@ -253,22 +267,22 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, if (err != GRPC_ERROR_NONE) { goto error; } - state = gpr_malloc(sizeof(*state)); - memset(state, 0, sizeof(*state)); - grpc_closure_init(&state->destroy_closure, destroy_done, state); - err = grpc_tcp_server_create(&state->destroy_closure, + server_state = gpr_malloc(sizeof(*server_state)); + memset(server_state, 0, sizeof(*server_state)); + grpc_closure_init(&server_state->tcp_server_shutdown_complete, + tcp_server_shutdown_complete, server_state); + err = grpc_tcp_server_create(&server_state->tcp_server_shutdown_complete, grpc_server_get_channel_args(server), &tcp); if (err != GRPC_ERROR_NONE) { goto error; } - state->server = server; - state->tcp = tcp; - state->sc = sc; - state->creds = grpc_server_credentials_ref(creds); - state->is_shutdown = false; - gpr_mu_init(&state->mu); - gpr_ref_init(&state->refcount, 1); + server_state->server = server; + server_state->tcp = tcp; + server_state->sc = sc; + server_state->creds = grpc_server_credentials_ref(creds); + server_state->is_shutdown = true; + gpr_mu_init(&server_state->mu); errors = gpr_malloc(sizeof(*errors) * resolved->naddrs); for (i = 0; i < resolved->naddrs; i++) { @@ -313,7 +327,8 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_resolved_addresses_destroy(resolved); /* Register with the server only upon success */ - grpc_server_add_listener(&exec_ctx, server, state, start, destroy); + grpc_server_add_listener(&exec_ctx, server, server_state, + server_start_listener, server_destroy_listener); grpc_exec_ctx_finish(&exec_ctx); return port_num; @@ -334,10 +349,11 @@ error: grpc_tcp_server_unref(&exec_ctx, tcp); } else { if (sc) { + grpc_exec_ctx_flush(&exec_ctx); GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server"); } - if (state) { - gpr_free(state); + if (server_state) { + gpr_free(server_state); } } grpc_exec_ctx_finish(&exec_ctx); diff --git a/src/core/ext/transport/chttp2/transport/chttp2_plugin.c b/src/core/ext/transport/chttp2/transport/chttp2_plugin.c index 7d5279b9da..bd87253ed3 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_plugin.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_plugin.c @@ -36,14 +36,11 @@ #include "src/core/lib/debug/trace.h" #include "src/core/lib/transport/metadata.h" -extern int grpc_http_write_state_trace; - void grpc_chttp2_plugin_init(void) { grpc_chttp2_base64_encode_and_huffman_compress = grpc_chttp2_base64_encode_and_huffman_compress_impl; grpc_register_tracer("http", &grpc_http_trace); grpc_register_tracer("flowctl", &grpc_flowctl_trace); - grpc_register_tracer("http_write_state", &grpc_http_write_state_trace); } void grpc_chttp2_plugin_shutdown(void) {} diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 1dd7fef76f..97780d90f2 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -65,91 +65,59 @@ #define MAX_CLIENT_STREAM_ID 0x7fffffffu int grpc_http_trace = 0; int grpc_flowctl_trace = 0; -int grpc_http_write_state_trace = 0; - -#define TRANSPORT_FROM_WRITING(tw) \ - ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ - writing))) - -#define TRANSPORT_FROM_PARSING(tp) \ - ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \ - parsing))) - -#define TRANSPORT_FROM_GLOBAL(tg) \ - ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \ - global))) - -#define STREAM_FROM_GLOBAL(sg) \ - ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global))) - -#define STREAM_FROM_PARSING(sg) \ - ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, parsing))) static const grpc_transport_vtable vtable; /* forward declarations of various callbacks that we'll build closures around */ -static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); -static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); -static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); -static void reading_action_locked(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error); -static void post_parse_locked(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error); -static void initiate_writing_locked(grpc_exec_ctx *exec_ctx, void *t, +static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *t, + grpc_error *error); +static void write_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); +static void write_action_end(grpc_exec_ctx *exec_ctx, void *t, + grpc_error *error); +static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); -static void initiate_read_flush_locked(grpc_exec_ctx *exec_ctx, void *t, - grpc_error *error); -static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, void *t, - grpc_error *error); -static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); -static void end_waiting_for_write(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, grpc_error *error); +static void read_action_begin(grpc_exec_ctx *exec_ctx, void *t, + grpc_error *error); +static void read_action_locked(grpc_exec_ctx *exec_ctx, void *t, + grpc_error *error); +static void complete_fetch_locked(grpc_exec_ctx *exec_ctx, void *gs, + grpc_error *error); +static void complete_fetch(grpc_exec_ctx *exec_ctx, void *gs, + grpc_error *error); /** Set a transport level setting, and push it to our peer */ static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_setting_id id, uint32_t value); -/** Start disconnection chain */ -static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_error *error); - -/** Cancel a stream: coming from the transport API */ -static void cancel_from_api(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - grpc_error *error); - -static void close_from_api(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - grpc_error *error); +static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_stream *s, grpc_error *error); /** Start new streams that have been created if we can */ -static void maybe_start_some_streams( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global); - -static void connectivity_state_set( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_connectivity_state state, grpc_error *error, const char *reason); +static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); -static void check_read_ops(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global); - -static void incoming_byte_stream_update_flow_control( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, size_t max_size_hint, - size_t have_already); +static void connectivity_state_set(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_connectivity_state state, + grpc_error *error, const char *reason); + +static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + size_t max_size_hint, + size_t have_already); static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, void *byte_stream, grpc_error *error_ignored); static void fail_pending_writes(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, + grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_error *error); -static void set_write_state(grpc_chttp2_transport *t, - grpc_chttp2_write_state state, const char *reason); +static void close_transport_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, grpc_error *error); +static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_error *error); /******************************************************************************* * CONSTRUCTION/DESTRUCTION/REFCOUNTING @@ -161,34 +129,31 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, grpc_endpoint_destroy(exec_ctx, t->ep); - gpr_slice_buffer_destroy(&t->global.qbuf); + gpr_slice_buffer_destroy(&t->qbuf); - gpr_slice_buffer_destroy(&t->writing.outbuf); - grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor); + gpr_slice_buffer_destroy(&t->outbuf); + grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor); - gpr_slice_buffer_destroy(&t->parsing.qbuf); gpr_slice_buffer_destroy(&t->read_buffer); - grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser); - grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser); + grpc_chttp2_hpack_parser_destroy(&t->hpack_parser); + grpc_chttp2_goaway_parser_destroy(&t->goaway_parser); for (i = 0; i < STREAM_LIST_COUNT; i++) { GPR_ASSERT(t->lists[i].head == NULL); GPR_ASSERT(t->lists[i].tail == NULL); } - GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0); - GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0); + GPR_ASSERT(grpc_chttp2_stream_map_size(&t->stream_map) == 0); - grpc_chttp2_stream_map_destroy(&t->parsing_stream_map); - grpc_chttp2_stream_map_destroy(&t->new_stream_map); + grpc_chttp2_stream_map_destroy(&t->stream_map); grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker); - grpc_combiner_destroy(exec_ctx, t->executor.combiner); + grpc_combiner_destroy(exec_ctx, t->combiner); /* callback remaining pings: they're not allowed to call into the transpot, and maybe they hold resources that need to be freed */ - while (t->global.pings.next != &t->global.pings) { - grpc_chttp2_outstanding_ping *ping = t->global.pings.next; + while (t->pings.next != &t->pings) { + grpc_chttp2_outstanding_ping *ping = t->pings.next; grpc_exec_ctx_sched(exec_ctx, ping->on_recv, GRPC_ERROR_CREATE("Transport closed"), NULL); ping->next->prev = ping->prev; @@ -196,37 +161,40 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx, gpr_free(ping); } + while (t->write_cb_pool) { + grpc_chttp2_write_cb *next = t->write_cb_pool->next; + gpr_free(t->write_cb_pool); + t->write_cb_pool = next; + } + gpr_free(t->peer_string); gpr_free(t); } -/*#define REFCOUNTING_DEBUG 1*/ -#ifdef REFCOUNTING_DEBUG -#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__) -#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__) -static void unref_transport(grpc_exec_ctx *exec_ctx, 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); +#ifdef GRPC_CHTTP2_REFCOUNTING_DEBUG +void grpc_chttp2_unref_transport(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, const char *reason, + const char *file, int line) { + gpr_log(GPR_DEBUG, "chttp2:unref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]", t, + t->refs.count, t->refs.count - 1, reason, file, line); if (!gpr_unref(&t->refs)) return; destruct_transport(exec_ctx, 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); +void grpc_chttp2_ref_transport(grpc_chttp2_transport *t, const char *reason, + const char *file, int line) { + gpr_log(GPR_DEBUG, "chttp2: ref:%p %" PRIdPTR "->%" PRIdPTR " %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) -#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t) -static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { +void grpc_chttp2_unref_transport(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { if (!gpr_unref(&t->refs)) return; destruct_transport(exec_ctx, t); } -static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); } +void grpc_chttp2_ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); } #endif static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, @@ -241,51 +209,41 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, memset(t, 0, sizeof(*t)); t->base.vtable = &vtable; - t->executor.write_state = GRPC_CHTTP2_WRITES_CORKED; t->ep = ep; /* one ref is for destroy */ gpr_ref_init(&t->refs, 1); - /* ref is dropped at transport close() */ - gpr_ref_init(&t->shutdown_ep_refs, 1); - t->executor.combiner = grpc_combiner_create(grpc_endpoint_get_workqueue(ep)); + t->combiner = grpc_combiner_create(grpc_endpoint_get_workqueue(ep)); t->peer_string = grpc_endpoint_get_peer(ep); t->endpoint_reading = 1; - t->global.next_stream_id = is_client ? 1 : 2; - t->global.is_client = is_client; - t->writing.outgoing_window = DEFAULT_WINDOW; - t->parsing.incoming_window = DEFAULT_WINDOW; - t->global.stream_lookahead = DEFAULT_WINDOW; - t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET; - t->global.ping_counter = 1; - t->global.pings.next = t->global.pings.prev = &t->global.pings; - t->parsing.is_client = is_client; - t->parsing.deframe_state = - is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; - t->parsing.is_first_frame = true; - t->writing.is_client = is_client; + t->next_stream_id = is_client ? 1 : 2; + t->is_client = is_client; + t->outgoing_window = DEFAULT_WINDOW; + t->incoming_window = DEFAULT_WINDOW; + t->stream_lookahead = DEFAULT_WINDOW; + t->connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET; + t->ping_counter = 1; + t->pings.next = t->pings.prev = &t->pings; + t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0; + t->is_first_frame = true; grpc_connectivity_state_init( &t->channel_callback.state_tracker, GRPC_CHANNEL_READY, is_client ? "client_transport" : "server_transport"); - gpr_slice_buffer_init(&t->global.qbuf); - - gpr_slice_buffer_init(&t->writing.outbuf); - grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor); - grpc_closure_init(&t->writing_action, writing_action, t); - grpc_closure_init(&t->reading_action, reading_action, t); - grpc_closure_init(&t->reading_action_locked, reading_action_locked, t); - grpc_closure_init(&t->parsing_action, parsing_action, t); - grpc_closure_init(&t->post_parse_locked, post_parse_locked, t); - grpc_closure_init(&t->initiate_writing, initiate_writing_locked, t); - grpc_closure_init(&t->terminate_writing, terminate_writing_with_lock, t); - grpc_closure_init(&t->initiate_read_flush_locked, initiate_read_flush_locked, + gpr_slice_buffer_init(&t->qbuf); + + gpr_slice_buffer_init(&t->outbuf); + grpc_chttp2_hpack_compressor_init(&t->hpack_compressor); + + grpc_closure_init(&t->write_action_begin_locked, write_action_begin_locked, t); - grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing, - &t->writing); + grpc_closure_init(&t->write_action, write_action, t); + grpc_closure_init(&t->write_action_end, write_action_end, t); + grpc_closure_init(&t->write_action_end_locked, write_action_end_locked, t); + grpc_closure_init(&t->read_action_begin, read_action_begin, t); + grpc_closure_init(&t->read_action_locked, read_action_locked, t); - gpr_slice_buffer_init(&t->parsing.qbuf); - grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser); - grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser); + grpc_chttp2_goaway_parser_init(&t->goaway_parser); + grpc_chttp2_hpack_parser_init(&t->hpack_parser); gpr_slice_buffer_init(&t->read_buffer); @@ -294,28 +252,24 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, large enough that the exponential growth should happen nicely when it's needed. TODO(ctiller): tune this */ - grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8); - grpc_chttp2_stream_map_init(&t->new_stream_map, 8); + grpc_chttp2_stream_map_init(&t->stream_map, 8); /* copy in initial settings to all setting sets */ for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) { - t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value; for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) { - t->global.settings[j][i] = - grpc_chttp2_settings_parameters[i].default_value; + t->settings[j][i] = grpc_chttp2_settings_parameters[i].default_value; } } - t->global.dirtied_local_settings = 1; + t->dirtied_local_settings = 1; /* Hack: it's common for implementations to assume 65536 bytes initial send window -- this should by rights be 0 */ - t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; - t->global.sent_local_settings = 0; + t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; + t->sent_local_settings = 0; if (is_client) { - gpr_slice_buffer_add( - &t->writing.outbuf, - gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING)); - grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "initial_write"); + gpr_slice_buffer_add(&t->outbuf, gpr_slice_from_copied_string( + GRPC_CHTTP2_CLIENT_CONNECT_STRING)); + grpc_chttp2_initiate_write(exec_ctx, t, false, "initial_write"); } /* configure http2 the way we like it */ @@ -330,34 +284,18 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, if (channel_args) { for (i = 0; i < channel_args->num_args; i++) { - if (0 == - strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) { - if (is_client) { - gpr_log(GPR_ERROR, "%s: is ignored on the client", - GRPC_ARG_MAX_CONCURRENT_STREAMS); - } else { - const grpc_integer_options options = {-1, 0, INT_MAX}; - const int value = - grpc_channel_arg_get_integer(&channel_args->args[i], options); - if (value >= 0) { - push_setting(exec_ctx, t, - GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, - (uint32_t)value); - } - } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) { + if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) { const grpc_integer_options options = {-1, 0, INT_MAX}; const int value = grpc_channel_arg_get_integer(&channel_args->args[i], options); if (value >= 0) { - if ((t->global.next_stream_id & 1) != (value & 1)) { + if ((t->next_stream_id & 1) != (value & 1)) { gpr_log(GPR_ERROR, "%s: low bit must be %d on %s", GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, - t->global.next_stream_id & 1, - is_client ? "client" : "server"); + t->next_stream_id & 1, is_client ? "client" : "server"); } else { - t->global.next_stream_id = (uint32_t)value; + t->next_stream_id = (uint32_t)value; } } } else if (0 == strcmp(channel_args->args[i].key, @@ -366,16 +304,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, const int value = grpc_channel_arg_get_integer(&channel_args->args[i], options); if (value >= 0) { - t->global.stream_lookahead = (uint32_t)value; - } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) { - const grpc_integer_options options = {-1, 0, INT_MAX}; - const int value = - grpc_channel_arg_get_integer(&channel_args->args[i], options); - if (value >= 0) { - push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, - (uint32_t)value); + t->stream_lookahead = (uint32_t)value; } } else if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) { @@ -383,118 +312,125 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, const int value = grpc_channel_arg_get_integer(&channel_args->args[i], options); if (value >= 0) { - grpc_chttp2_hpack_compressor_set_max_usable_size( - &t->writing.hpack_compressor, (uint32_t)value); - } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_MAX_METADATA_SIZE)) { - const grpc_integer_options options = {-1, 0, INT_MAX}; - const int value = - grpc_channel_arg_get_integer(&channel_args->args[i], options); - if (value >= 0) { - push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, - (uint32_t)value); + grpc_chttp2_hpack_compressor_set_max_usable_size(&t->hpack_compressor, + (uint32_t)value); } - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_MAX_FRAME_SIZE)) { - if (channel_args->args[i].type != GRPC_ARG_INTEGER) { - gpr_log(GPR_ERROR, "%s: must be an integer", - GRPC_ARG_HTTP2_MAX_FRAME_SIZE); - } else if (channel_args->args[i].value.integer < 16384 || - channel_args->args[i].value.integer > 16777215) { - gpr_log(GPR_ERROR, "%s: must be between 16384 and 16777215", - GRPC_ARG_HTTP2_MAX_FRAME_SIZE); - } else { - push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, - (uint32_t)channel_args->args[i].value.integer); + } else { + static const struct { + const char *channel_arg_name; + grpc_chttp2_setting_id setting_id; + grpc_integer_options integer_options; + bool availability[2] /* server, client */; + } settings_map[] = { + {GRPC_ARG_MAX_CONCURRENT_STREAMS, + GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, + {-1, 0, INT_MAX}, + {true, false}}, + {GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER, + GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, + {-1, 0, INT_MAX}, + {true, true}}, + {GRPC_ARG_MAX_METADATA_SIZE, + GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, + {-1, 0, INT_MAX}, + {true, true}}, + {GRPC_ARG_HTTP2_MAX_FRAME_SIZE, + GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE, + {-1, 16384, 16777215}, + {true, true}}, + }; + for (j = 0; j < (int)GPR_ARRAY_SIZE(settings_map); j++) { + if (0 == strcmp(channel_args->args[i].key, + settings_map[j].channel_arg_name)) { + if (!settings_map[j].availability[is_client]) { + gpr_log(GPR_DEBUG, "%s is not available on %s", + settings_map[j].channel_arg_name, + is_client ? "clients" : "servers"); + } else { + int value = grpc_channel_arg_get_integer( + &channel_args->args[i], settings_map[j].integer_options); + if (value >= 0) { + push_setting(exec_ctx, t, settings_map[j].setting_id, + (uint32_t)value); + } + } + break; + } } } } } - set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "uncork"); - grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "init"); + grpc_chttp2_initiate_write(exec_ctx, t, false, "init"); } static void destroy_transport_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error) { grpc_chttp2_transport *t = tp; t->destroying = 1; - drop_connection(exec_ctx, t, GRPC_ERROR_CREATE("Transport destroyed")); - UNREF_TRANSPORT(exec_ctx, t, "destroy"); + close_transport_locked( + exec_ctx, t, + grpc_error_set_int(GRPC_ERROR_CREATE("Transport destroyed"), + GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state)); + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "destroy"); } static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; - grpc_combiner_execute(exec_ctx, t->executor.combiner, + grpc_combiner_execute(exec_ctx, t->combiner, grpc_closure_create(destroy_transport_locked, t), - GRPC_ERROR_NONE); -} - -/** block grpc_endpoint_shutdown being called until a paired - allow_endpoint_shutdown is made */ -static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) { - gpr_ref(&t->shutdown_ep_refs); -} - -static void allow_endpoint_shutdown_locked(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t) { - if (gpr_unref(&t->shutdown_ep_refs)) { - grpc_endpoint_shutdown(exec_ctx, t->ep); - } + GRPC_ERROR_NONE, false); } static void close_transport_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error) { if (!t->closed) { - if (grpc_http_write_state_trace) { - gpr_log(GPR_DEBUG, "W:%p close transport", t); + if (t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE) { + if (t->close_transport_on_writes_finished == NULL) { + t->close_transport_on_writes_finished = + GRPC_ERROR_CREATE("Delayed close due to in-progress write"); + } + t->close_transport_on_writes_finished = + grpc_error_add_child(t->close_transport_on_writes_finished, error); + return; + } + if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) { + error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAVAILABLE); } t->closed = 1; - connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN, + connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), "close_transport"); - allow_endpoint_shutdown_locked(exec_ctx, t); + grpc_endpoint_shutdown(exec_ctx, t->ep); /* flush writable stream list to avoid dangling references */ - grpc_chttp2_stream_global *stream_global; - grpc_chttp2_stream_writing *stream_writing; - while (grpc_chttp2_list_pop_writable_stream( - &t->global, &t->writing, &stream_global, &stream_writing)) { - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); + grpc_chttp2_stream *s; + while (grpc_chttp2_list_pop_writable_stream(t, &s)) { + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close"); } + end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error)); } GRPC_ERROR_UNREF(error); } #ifdef GRPC_STREAM_REFCOUNT_DEBUG -void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global, - const char *reason) { - grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount, reason); +void grpc_chttp2_stream_ref(grpc_chttp2_stream *s, const char *reason) { + grpc_stream_ref(s->refcount, reason); } -void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global, +void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s, const char *reason) { - grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount, - reason); + grpc_stream_unref(exec_ctx, s->refcount, reason); } #else -void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global) { - grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount); +void grpc_chttp2_stream_ref(grpc_chttp2_stream *s) { + grpc_stream_ref(s->refcount); } -void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global) { - grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount); +void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s) { + grpc_stream_unref(exec_ctx, s->refcount); } #endif -static void finish_init_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, - grpc_error *error) { - grpc_chttp2_stream *s = sp; - grpc_chttp2_register_stream(s->t, s); - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "init"); -} - static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_stream *gs, grpc_stream_refcount *refcount, const void *server_data) { @@ -509,41 +445,30 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, /* We reserve one 'active stream' that's dropped when the stream is read-closed. The others are for incoming_byte_streams that are actively reading */ - gpr_ref_init(&s->global.active_streams, 1); - GRPC_CHTTP2_STREAM_REF(&s->global, "chttp2"); + gpr_ref_init(&s->active_streams, 1); + GRPC_CHTTP2_STREAM_REF(s, "chttp2"); - grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[0]); - grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[1]); - grpc_chttp2_incoming_metadata_buffer_init( - &s->global.received_initial_metadata); - grpc_chttp2_incoming_metadata_buffer_init( - &s->global.received_trailing_metadata); - grpc_chttp2_data_parser_init(&s->parsing.data_parser); - gpr_slice_buffer_init(&s->writing.flow_controlled_buffer); - s->global.deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0]); + grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1]); + grpc_chttp2_data_parser_init(&s->data_parser); + gpr_slice_buffer_init(&s->flow_controlled_buffer); + s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + grpc_closure_init(&s->complete_fetch, complete_fetch, s); + grpc_closure_init(&s->complete_fetch_locked, complete_fetch_locked, s); - REF_TRANSPORT(t, "stream"); + GRPC_CHTTP2_REF_TRANSPORT(t, "stream"); if (server_data) { - GPR_ASSERT(t->executor.parsing_active); - s->global.id = (uint32_t)(uintptr_t)server_data; - s->parsing.id = s->global.id; - s->global.outgoing_window = - t->global.settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - s->parsing.incoming_window = s->global.max_recv_bytes = - t->global.settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + s->id = (uint32_t)(uintptr_t)server_data; + s->outgoing_window = t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + s->incoming_window = s->max_recv_bytes = + t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; *t->accepting_stream = s; - grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s); - s->global.in_stream_map = true; + grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); } - grpc_closure_init(&s->init_stream, finish_init_stream_locked, s); - GRPC_CHTTP2_STREAM_REF(&s->global, "init"); - grpc_combiner_execute(exec_ctx, t->executor.combiner, &s->init_stream, - GRPC_ERROR_NONE); - GPR_TIMER_END("init_stream", 0); return 0; @@ -557,55 +482,39 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp, GPR_TIMER_BEGIN("destroy_stream", 0); - GPR_ASSERT((s->global.write_closed && s->global.read_closed) || - s->global.id == 0); - GPR_ASSERT(!s->global.in_stream_map); - if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { - close_transport_locked( - exec_ctx, t, - GRPC_ERROR_CREATE("Last stream closed after sending goaway")); - } - if (!t->executor.parsing_active && s->global.id) { - GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map, - s->global.id) == NULL); + GPR_ASSERT((s->write_closed && s->read_closed) || s->id == 0); + if (s->id != 0) { + GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, s->id) == NULL); } - while ( - (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) { + while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames))) { incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); } - grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global, - &s->global); - grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global); - grpc_chttp2_list_remove_check_read_ops(&t->global, &s->global); + grpc_chttp2_list_remove_stalled_by_transport(t, s); for (int i = 0; i < STREAM_LIST_COUNT; i++) { if (s->included[i]) { gpr_log(GPR_ERROR, "%s stream %d still included in list %d", - t->global.is_client ? "client" : "server", s->global.id, i); + t->is_client ? "client" : "server", s->id, i); abort(); } } - GPR_ASSERT(s->global.send_initial_metadata_finished == NULL); - GPR_ASSERT(s->global.send_message_finished == NULL); - GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL); - GPR_ASSERT(s->global.recv_initial_metadata_ready == NULL); - GPR_ASSERT(s->global.recv_message_ready == NULL); - GPR_ASSERT(s->global.recv_trailing_metadata_finished == NULL); - grpc_chttp2_data_parser_destroy(exec_ctx, &s->parsing.data_parser); - grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[0]); - grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[1]); - grpc_chttp2_incoming_metadata_buffer_destroy( - &s->global.received_initial_metadata); - grpc_chttp2_incoming_metadata_buffer_destroy( - &s->global.received_trailing_metadata); - gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer); - GRPC_ERROR_UNREF(s->global.read_closed_error); - GRPC_ERROR_UNREF(s->global.write_closed_error); - - UNREF_TRANSPORT(exec_ctx, t, "stream"); + GPR_ASSERT(s->send_initial_metadata_finished == NULL); + GPR_ASSERT(s->fetching_send_message == NULL); + GPR_ASSERT(s->send_trailing_metadata_finished == NULL); + GPR_ASSERT(s->recv_initial_metadata_ready == NULL); + GPR_ASSERT(s->recv_message_ready == NULL); + GPR_ASSERT(s->recv_trailing_metadata_finished == NULL); + grpc_chttp2_data_parser_destroy(exec_ctx, &s->data_parser); + grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[0]); + grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[1]); + gpr_slice_buffer_destroy(&s->flow_controlled_buffer); + GRPC_ERROR_UNREF(s->read_closed_error); + GRPC_ERROR_UNREF(s->write_closed_error); + + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "stream"); GPR_TIMER_END("destroy_stream", 0); @@ -620,280 +529,215 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, s->destroy_stream_arg = and_free_memory; grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s); - grpc_combiner_execute(exec_ctx, t->executor.combiner, &s->destroy_stream, - GRPC_ERROR_NONE); + grpc_combiner_execute(exec_ctx, t->combiner, &s->destroy_stream, + GRPC_ERROR_NONE, false); GPR_TIMER_END("destroy_stream", 0); } -grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( - grpc_chttp2_transport_parsing *transport_parsing, uint32_t id) { - grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); - grpc_chttp2_stream *s = - grpc_chttp2_stream_map_find(&t->parsing_stream_map, id); - return s ? &s->parsing : NULL; +grpc_chttp2_stream *grpc_chttp2_parsing_lookup_stream(grpc_chttp2_transport *t, + uint32_t id) { + return grpc_chttp2_stream_map_find(&t->stream_map, id); } -grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - uint32_t id) { +grpc_chttp2_stream *grpc_chttp2_parsing_accept_stream(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + uint32_t id) { + if (t->channel_callback.accept_stream == NULL) { + return NULL; + } grpc_chttp2_stream *accepting; - grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing); GPR_ASSERT(t->accepting_stream == NULL); t->accepting_stream = &accepting; t->channel_callback.accept_stream(exec_ctx, t->channel_callback.accept_stream_user_data, &t->base, (void *)(uintptr_t)id); t->accepting_stream = NULL; - return &accepting->parsing; + return accepting; } /******************************************************************************* - * LOCK MANAGEMENT + * OUTPUT PROCESSING */ -static const char *write_state_name(grpc_chttp2_write_state state) { - switch (state) { - case GRPC_CHTTP2_WRITES_CORKED: - return "CORKED"; - case GRPC_CHTTP2_WRITING_INACTIVE: - return "INACTIVE"; - case GRPC_CHTTP2_WRITE_SCHEDULED: - return "SCHEDULED"; - case GRPC_CHTTP2_WRITING: +static const char *write_state_name(grpc_chttp2_write_state st) { + switch (st) { + case GRPC_CHTTP2_WRITE_STATE_IDLE: + return "IDLE"; + case GRPC_CHTTP2_WRITE_STATE_WRITING: return "WRITING"; - case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER: - return "WRITING[p=1]"; - case GRPC_CHTTP2_WRITING_STALE_NO_POLLER: - return "WRITING[p=0]"; + case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE: + return "WRITING+MORE"; + case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER: + return "WRITING+MORE+COVERED"; } GPR_UNREACHABLE_CODE(return "UNKNOWN"); } -static void set_write_state(grpc_chttp2_transport *t, - grpc_chttp2_write_state state, const char *reason) { - if (grpc_http_write_state_trace) { - gpr_log(GPR_DEBUG, "W:%p %s -> %s because %s", t, - write_state_name(t->executor.write_state), write_state_name(state), - reason); +static void set_write_state(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_write_state st, const char *reason) { + GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_DEBUG, "W:%p %s state %s -> %s [%s]", t, + t->is_client ? "CLIENT" : "SERVER", + write_state_name(t->write_state), + write_state_name(st), reason)); + t->write_state = st; + if (st == GRPC_CHTTP2_WRITE_STATE_IDLE && + t->close_transport_on_writes_finished != NULL) { + grpc_error *err = t->close_transport_on_writes_finished; + t->close_transport_on_writes_finished = NULL; + close_transport_locked(exec_ctx, t, err); } - t->executor.write_state = state; -} - -static void initiate_writing_locked(grpc_exec_ctx *exec_ctx, void *tp, - grpc_error *error) { - grpc_chttp2_transport *t = tp; - GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED); - start_writing(exec_ctx, t); } -static void initiate_read_flush_locked(grpc_exec_ctx *exec_ctx, void *tp, - grpc_error *error) { - grpc_chttp2_transport *t = tp; - t->executor.check_read_ops_scheduled = false; - check_read_ops(exec_ctx, &t->global); -} - -/******************************************************************************* - * OUTPUT PROCESSING - */ - void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport *t, bool covered_by_poller, const char *reason) { GPR_TIMER_BEGIN("grpc_chttp2_initiate_write", 0); - /* Perform state checks, and transition to a scheduled state if appropriate. - If we are inactive, schedule a write chain to begin once the transport - combiner finishes any executions in its current batch (which may be - scheduled AFTER this code executes). The write chain will: - - call start_writing, which verifies (under the global lock) that there - are things that need to be written by calling - grpc_chttp2_unlocking_check_writes, and if so schedules writing_action - against the current exec_ctx, to be executed OUTSIDE of the global lock - - eventually writing_action results in grpc_chttp2_terminate_writing being - called, which re-takes the global lock, updates state, checks if we need - to do *another* write immediately, and if so loops back to - start_writing. - - Current problems: - - too much lock entry/exiting - - the writing thread can become stuck indefinitely (punt through the - workqueue periodically to fix) */ - - grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global); - switch (t->executor.write_state) { - case GRPC_CHTTP2_WRITES_CORKED: + switch (t->write_state) { + case GRPC_CHTTP2_WRITE_STATE_IDLE: + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, reason); + GRPC_CHTTP2_REF_TRANSPORT(t, "writing"); + grpc_combiner_execute_finally(exec_ctx, t->combiner, + &t->write_action_begin_locked, + GRPC_ERROR_NONE, covered_by_poller); break; - case GRPC_CHTTP2_WRITING_INACTIVE: - set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, reason); - REF_TRANSPORT(t, "writing"); - grpc_combiner_execute_finally(exec_ctx, t->executor.combiner, - &t->initiate_writing, GRPC_ERROR_NONE, - covered_by_poller); + case GRPC_CHTTP2_WRITE_STATE_WRITING: + set_write_state( + exec_ctx, t, + covered_by_poller + ? GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER + : GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE, + reason); break; - case GRPC_CHTTP2_WRITE_SCHEDULED: + case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE: if (covered_by_poller) { - /* upgrade to note poller is available to cover the write */ - grpc_combiner_force_async_finally(t->executor.combiner); + set_write_state( + exec_ctx, t, + GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER, + reason); } break; - case GRPC_CHTTP2_WRITING: - set_write_state(t, - covered_by_poller ? GRPC_CHTTP2_WRITING_STALE_WITH_POLLER - : GRPC_CHTTP2_WRITING_STALE_NO_POLLER, - reason); - break; - case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER: - /* nothing to do: write already requested */ - break; - case GRPC_CHTTP2_WRITING_STALE_NO_POLLER: - if (covered_by_poller) { - /* upgrade to note poller is available to cover the write */ - set_write_state(t, GRPC_CHTTP2_WRITING_STALE_WITH_POLLER, reason); - } + case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER: break; } GPR_TIMER_END("grpc_chttp2_initiate_write", 0); } -static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { - GPR_TIMER_BEGIN("start_writing", 0); - GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED); - if (!t->closed && - grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) { - set_write_state(t, GRPC_CHTTP2_WRITING, "start_writing"); - prevent_endpoint_shutdown(t); - grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL); - } else { - if (t->closed) { - set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, - "start_writing:transport_closed"); - } else { - set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, - "start_writing:nothing_to_write"); - } - end_waiting_for_write(exec_ctx, t, GRPC_ERROR_NONE); - UNREF_TRANSPORT(exec_ctx, t, "writing"); +void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, bool covered_by_poller, + const char *reason) { + if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s)) { + GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:become"); + grpc_chttp2_initiate_write(exec_ctx, t, covered_by_poller, reason); } - GPR_TIMER_END("start_writing", 0); } -void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - bool covered_by_poller, const char *reason) { - if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed && - grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) { - GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing"); - grpc_chttp2_initiate_write(exec_ctx, transport_global, covered_by_poller, - reason); +static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *gt, + grpc_error *error_ignored) { + GPR_TIMER_BEGIN("write_action_begin_locked", 0); + grpc_chttp2_transport *t = gt; + GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE); + if (!t->closed && grpc_chttp2_begin_write(exec_ctx, t)) { + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, + "begin writing"); + grpc_exec_ctx_sched(exec_ctx, &t->write_action, GRPC_ERROR_NONE, NULL); + } else { + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_IDLE, + "begin writing nothing"); + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing"); } + GPR_TIMER_END("write_action_begin_locked", 0); } -static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_chttp2_setting_id id, uint32_t value) { - const grpc_chttp2_setting_parameters *sp = - &grpc_chttp2_settings_parameters[id]; - uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value); - if (use_value != value) { - gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name, - value, use_value); - } - if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) { - t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value; - t->global.dirtied_local_settings = 1; - grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "push_setting"); - } +static void write_action(grpc_exec_ctx *exec_ctx, void *gt, grpc_error *error) { + grpc_chttp2_transport *t = gt; + GPR_TIMER_BEGIN("write_action", 0); + grpc_endpoint_write(exec_ctx, t->ep, &t->outbuf, &t->write_action_end); + GPR_TIMER_END("write_action", 0); } -/* error may be GRPC_ERROR_NONE if there is no error allocated yet. - In that case, use "reason" as the text for a new error. */ -static void end_waiting_for_write(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport *t, grpc_error *error) { - grpc_chttp2_stream_global *stream_global; - while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global, - &stream_global)) { - fail_pending_writes(exec_ctx, &t->global, stream_global, - GRPC_ERROR_REF(error)); - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes"); - } - GRPC_ERROR_UNREF(error); +static void write_action_end(grpc_exec_ctx *exec_ctx, void *gt, + grpc_error *error) { + grpc_chttp2_transport *t = gt; + GPR_TIMER_BEGIN("write_action_end", 0); + grpc_combiner_execute(exec_ctx, t->combiner, &t->write_action_end_locked, + GRPC_ERROR_REF(error), false); + GPR_TIMER_END("write_action_end", 0); } -static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, void *tp, - grpc_error *error) { +static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { GPR_TIMER_BEGIN("terminate_writing_with_lock", 0); grpc_chttp2_transport *t = tp; - allow_endpoint_shutdown_locked(exec_ctx, t); if (error != GRPC_ERROR_NONE) { - drop_connection(exec_ctx, t, GRPC_ERROR_REF(error)); + close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error)); } - grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing); + grpc_chttp2_end_write(exec_ctx, t, GRPC_ERROR_REF(error)); - end_waiting_for_write(exec_ctx, t, GRPC_ERROR_REF(error)); - - switch (t->executor.write_state) { - case GRPC_CHTTP2_WRITES_CORKED: - case GRPC_CHTTP2_WRITING_INACTIVE: - case GRPC_CHTTP2_WRITE_SCHEDULED: + switch (t->write_state) { + case GRPC_CHTTP2_WRITE_STATE_IDLE: GPR_UNREACHABLE_CODE(break); - case GRPC_CHTTP2_WRITING: + case GRPC_CHTTP2_WRITE_STATE_WRITING: GPR_TIMER_MARK("state=writing", 0); - set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "terminate_writing"); + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_IDLE, + "finish writing"); break; - case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER: - GPR_TIMER_MARK("state=writing_stale_with_poller", 0); - set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "terminate_writing"); - REF_TRANSPORT(t, "writing"); - grpc_combiner_execute_finally(exec_ctx, t->executor.combiner, - &t->initiate_writing, GRPC_ERROR_NONE, - true); - break; - case GRPC_CHTTP2_WRITING_STALE_NO_POLLER: + case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE: GPR_TIMER_MARK("state=writing_stale_no_poller", 0); - set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "terminate_writing"); - REF_TRANSPORT(t, "writing"); - grpc_combiner_execute_finally(exec_ctx, t->executor.combiner, - &t->initiate_writing, GRPC_ERROR_NONE, - false); + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, + "continue writing [!covered]"); + GRPC_CHTTP2_REF_TRANSPORT(t, "writing"); + grpc_combiner_execute_finally(exec_ctx, t->combiner, + &t->write_action_begin_locked, + GRPC_ERROR_NONE, false); + break; + case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER: + GPR_TIMER_MARK("state=writing_stale_with_poller", 0); + set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, + "continue writing [covered]"); + GRPC_CHTTP2_REF_TRANSPORT(t, "writing"); + grpc_combiner_execute_finally(exec_ctx, t->combiner, + &t->write_action_begin_locked, + GRPC_ERROR_NONE, true); break; } - UNREF_TRANSPORT(exec_ctx, t, "writing"); + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing"); GPR_TIMER_END("terminate_writing_with_lock", 0); } -void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, - void *transport_writing, grpc_error *error) { - GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0); - grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing); - grpc_combiner_execute(exec_ctx, t->executor.combiner, &t->terminate_writing, - GRPC_ERROR_REF(error)); - GPR_TIMER_END("grpc_chttp2_terminate_writing", 0); -} - -static void writing_action(grpc_exec_ctx *exec_ctx, void *gt, - grpc_error *error) { - grpc_chttp2_transport *t = gt; - GPR_TIMER_BEGIN("writing_action", 0); - grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep); - GPR_TIMER_END("writing_action", 0); +static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_setting_id id, uint32_t value) { + const grpc_chttp2_setting_parameters *sp = + &grpc_chttp2_settings_parameters[id]; + uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value); + if (use_value != value) { + gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name, + value, use_value); + } + if (use_value != t->settings[GRPC_LOCAL_SETTINGS][id]) { + t->settings[GRPC_LOCAL_SETTINGS][id] = use_value; + t->dirtied_local_settings = 1; + grpc_chttp2_initiate_write(exec_ctx, t, false, "push_setting"); + } } -void grpc_chttp2_add_incoming_goaway( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - uint32_t goaway_error, gpr_slice goaway_text) { +void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + uint32_t goaway_error, + gpr_slice goaway_text) { char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII); GRPC_CHTTP2_IF_TRACING( gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg)); gpr_slice_unref(goaway_text); - transport_global->seen_goaway = 1; + t->seen_goaway = 1; /* lie: use transient failure from the transport to indicate goaway has been * received */ connectivity_state_set( - exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE, + exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE, grpc_error_set_str( grpc_error_set_int(GRPC_ERROR_CREATE("GOAWAY received"), GRPC_ERROR_INT_HTTP2_ERROR, @@ -903,61 +747,49 @@ void grpc_chttp2_add_incoming_goaway( gpr_free(msg); } -static void maybe_start_some_streams( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global) { - grpc_chttp2_stream_global *stream_global; +static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + grpc_chttp2_stream *s; uint32_t stream_incoming_window; /* start streams where we have free grpc_chttp2_stream ids and free * concurrency */ - while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID && - transport_global->concurrent_stream_count < - transport_global - ->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] && - grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, - &stream_global)) { + while (t->next_stream_id <= MAX_CLIENT_STREAM_ID && + grpc_chttp2_stream_map_size(&t->stream_map) < + t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] && + grpc_chttp2_list_pop_waiting_for_concurrency(t, &s)) { /* safe since we can't (legally) be parsing this stream yet */ - grpc_chttp2_stream_parsing *stream_parsing = - &STREAM_FROM_GLOBAL(stream_global)->parsing; GRPC_CHTTP2_IF_TRACING(gpr_log( GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d", - transport_global->is_client ? "CLI" : "SVR", stream_global, - transport_global->next_stream_id)); + t->is_client ? "CLI" : "SVR", s, t->next_stream_id)); - GPR_ASSERT(stream_global->id == 0); - stream_global->id = stream_parsing->id = transport_global->next_stream_id; - transport_global->next_stream_id += 2; + GPR_ASSERT(s->id == 0); + s->id = t->next_stream_id; + t->next_stream_id += 2; - if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) { - connectivity_state_set( - exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE, - GRPC_ERROR_CREATE("Stream IDs exhausted"), "no_more_stream_ids"); + if (t->next_stream_id >= MAX_CLIENT_STREAM_ID) { + connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE, + GRPC_ERROR_CREATE("Stream IDs exhausted"), + "no_more_stream_ids"); } - stream_global->outgoing_window = - transport_global->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - stream_parsing->incoming_window = stream_incoming_window = - transport_global->settings[GRPC_SENT_SETTINGS] - [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; - stream_global->max_recv_bytes = - GPR_MAX(stream_incoming_window, stream_global->max_recv_bytes); - grpc_chttp2_stream_map_add( - &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map, - stream_global->id, STREAM_FROM_GLOBAL(stream_global)); - stream_global->in_stream_map = true; - transport_global->concurrent_stream_count++; - grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, true, - "new_stream"); + s->outgoing_window = t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + s->incoming_window = stream_incoming_window = + t->settings[GRPC_SENT_SETTINGS] + [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]; + s->max_recv_bytes = GPR_MAX(stream_incoming_window, s->max_recv_bytes); + grpc_chttp2_stream_map_add(&t->stream_map, s->id, s); + grpc_chttp2_become_writable(exec_ctx, t, s, true, "new_stream"); } /* cancel out streams that will never be started */ - while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID && - grpc_chttp2_list_pop_waiting_for_concurrency(transport_global, - &stream_global)) { - cancel_from_api(exec_ctx, transport_global, stream_global, - grpc_error_set_int( - GRPC_ERROR_CREATE("Stream IDs exhausted"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE)); + while (t->next_stream_id >= MAX_CLIENT_STREAM_ID && + grpc_chttp2_list_pop_waiting_for_concurrency(t, &s)) { + grpc_chttp2_cancel_stream( + exec_ctx, t, s, + grpc_error_set_int(GRPC_ERROR_CREATE("Stream IDs exhausted"), + GRPC_ERROR_INT_GRPC_STATUS, + GRPC_STATUS_UNAVAILABLE)); } } @@ -969,48 +801,126 @@ static grpc_closure *add_closure_barrier(grpc_closure *closure) { return closure; } -void grpc_chttp2_complete_closure_step( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure, - grpc_error *error) { +static void null_then_run_closure(grpc_exec_ctx *exec_ctx, + grpc_closure **closure, grpc_error *error) { + grpc_closure *c = *closure; + *closure = NULL; + grpc_closure_run(exec_ctx, c, error); +} + +void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + grpc_closure **pclosure, + grpc_error *error, const char *desc) { grpc_closure *closure = *pclosure; + *pclosure = NULL; if (closure == NULL) { GRPC_ERROR_UNREF(error); return; } closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT; if (error != GRPC_ERROR_NONE) { - if (closure->error == GRPC_ERROR_NONE) { - closure->error = + if (closure->error_data.error == GRPC_ERROR_NONE) { + closure->error_data.error = GRPC_ERROR_CREATE("Error in HTTP transport completing operation"); - closure->error = grpc_error_set_str( - closure->error, GRPC_ERROR_STR_TARGET_ADDRESS, - TRANSPORT_FROM_GLOBAL(transport_global)->peer_string); + closure->error_data.error = + grpc_error_set_str(closure->error_data.error, + GRPC_ERROR_STR_TARGET_ADDRESS, t->peer_string); } - closure->error = grpc_error_add_child(closure->error, error); + closure->error_data.error = + grpc_error_add_child(closure->error_data.error, error); } if (closure->next_data.scratch < CLOSURE_BARRIER_FIRST_REF_BIT) { if (closure->next_data.scratch & CLOSURE_BARRIER_STATS_BIT) { - grpc_transport_move_stats(&stream_global->stats, - stream_global->collecting_stats); - stream_global->collecting_stats = NULL; + grpc_transport_move_stats(&s->stats, s->collecting_stats); + s->collecting_stats = NULL; } - grpc_exec_ctx_sched(exec_ctx, closure, closure->error, NULL); + grpc_closure_run(exec_ctx, closure, closure->error_data.error); } - *pclosure = NULL; } -static int contains_non_ok_status( - grpc_chttp2_transport_global *transport_global, - grpc_metadata_batch *batch) { +static bool contains_non_ok_status(grpc_metadata_batch *batch) { grpc_linked_mdelem *l; for (l = batch->list.head; l; l = l->next) { if (l->md->key == GRPC_MDSTR_GRPC_STATUS && l->md != GRPC_MDELEM_GRPC_STATUS_0) { - return 1; + return true; } } - return 0; + return false; +} + +static void add_fetched_slice_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s); + +static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + if (s->fetching_send_message == NULL) { + /* Stream was cancelled before message fetch completed */ + abort(); /* TODO(ctiller): what cleanup here? */ + return; + } + if (s->fetched_send_message_length == s->fetching_send_message->length) { + int64_t notify_offset = s->next_message_end_offset; + if (notify_offset <= s->flow_controlled_bytes_written) { + grpc_chttp2_complete_closure_step( + exec_ctx, t, s, &s->fetching_send_message_finished, GRPC_ERROR_NONE, + "fetching_send_message_finished"); + } else { + grpc_chttp2_write_cb *cb = t->write_cb_pool; + if (cb == NULL) { + cb = gpr_malloc(sizeof(*cb)); + } else { + t->write_cb_pool = cb->next; + } + cb->call_at_byte = notify_offset; + cb->closure = s->fetching_send_message_finished; + s->fetching_send_message_finished = NULL; + cb->next = s->on_write_finished_cbs; + s->on_write_finished_cbs = cb; + } + s->fetching_send_message = NULL; + } else if (grpc_byte_stream_next(exec_ctx, s->fetching_send_message, + &s->fetching_slice, UINT32_MAX, + &s->complete_fetch)) { + add_fetched_slice_locked(exec_ctx, t, s); + } +} + +static void add_fetched_slice_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + s->fetched_send_message_length += + (uint32_t)GPR_SLICE_LENGTH(s->fetching_slice); + gpr_slice_buffer_add(&s->flow_controlled_buffer, s->fetching_slice); + if (s->id != 0) { + grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message"); + } + continue_fetching_send_locked(exec_ctx, t, s); +} + +static void complete_fetch_locked(grpc_exec_ctx *exec_ctx, void *gs, + grpc_error *error) { + grpc_chttp2_stream *s = gs; + grpc_chttp2_transport *t = s->t; + if (error == GRPC_ERROR_NONE) { + add_fetched_slice_locked(exec_ctx, t, s); + } else { + /* TODO(ctiller): what to do here */ + abort(); + } +} + +static void complete_fetch(grpc_exec_ctx *exec_ctx, void *gs, + grpc_error *error) { + grpc_chttp2_stream *s = gs; + grpc_chttp2_transport *t = s->t; + grpc_combiner_execute(exec_ctx, t->combiner, &s->complete_fetch_locked, + GRPC_ERROR_REF(error), + s->complete_fetch_covered_by_poller); } static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {} @@ -1022,12 +932,11 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, grpc_transport_stream_op *op = stream_op; grpc_chttp2_transport *t = op->transport_private.args[0]; grpc_chttp2_stream *s = op->transport_private.args[1]; - grpc_chttp2_transport_global *transport_global = &t->global; - grpc_chttp2_stream_global *stream_global = &s->global; if (grpc_http_trace) { char *str = grpc_transport_stream_op_string(op); - gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s", str); + gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s; on_complete = %p", str, + op->on_complete); gpr_free(str); } @@ -1035,45 +944,42 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, if (on_complete == NULL) { on_complete = grpc_closure_create(do_nothing, NULL); } + /* use final_data as a barrier until enqueue time; the inital counter is dropped at the end of this function */ on_complete->next_data.scratch = CLOSURE_BARRIER_FIRST_REF_BIT; - on_complete->error = GRPC_ERROR_NONE; + on_complete->error_data.error = GRPC_ERROR_NONE; if (op->collect_stats != NULL) { - GPR_ASSERT(stream_global->collecting_stats == NULL); - stream_global->collecting_stats = op->collect_stats; + GPR_ASSERT(s->collecting_stats == NULL); + s->collecting_stats = op->collect_stats; on_complete->next_data.scratch |= CLOSURE_BARRIER_STATS_BIT; } if (op->cancel_error != GRPC_ERROR_NONE) { - cancel_from_api(exec_ctx, transport_global, stream_global, - GRPC_ERROR_REF(op->cancel_error)); + grpc_chttp2_cancel_stream(exec_ctx, t, s, GRPC_ERROR_REF(op->cancel_error)); } if (op->close_error != GRPC_ERROR_NONE) { - close_from_api(exec_ctx, transport_global, stream_global, - GRPC_ERROR_REF(op->close_error)); + close_from_api(exec_ctx, t, s, GRPC_ERROR_REF(op->close_error)); } if (op->send_initial_metadata != NULL) { - GPR_ASSERT(stream_global->send_initial_metadata_finished == NULL); - stream_global->send_initial_metadata_finished = - add_closure_barrier(on_complete); - stream_global->send_initial_metadata = op->send_initial_metadata; + GPR_ASSERT(s->send_initial_metadata_finished == NULL); + s->send_initial_metadata_finished = add_closure_barrier(on_complete); + s->send_initial_metadata = op->send_initial_metadata; const size_t metadata_size = grpc_metadata_batch_size(op->send_initial_metadata); const size_t metadata_peer_limit = - transport_global->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; - if (transport_global->is_client) { - stream_global->deadline = - gpr_time_min(stream_global->deadline, - stream_global->send_initial_metadata->deadline); + t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; + if (t->is_client) { + s->deadline = + gpr_time_min(s->deadline, s->send_initial_metadata->deadline); } if (metadata_size > metadata_peer_limit) { - cancel_from_api( - exec_ctx, transport_global, stream_global, + grpc_chttp2_cancel_stream( + exec_ctx, t, s, grpc_error_set_int( grpc_error_set_int( grpc_error_set_int( @@ -1083,64 +989,78 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); } else { - if (contains_non_ok_status(transport_global, op->send_initial_metadata)) { - stream_global->seen_error = true; - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); + if (contains_non_ok_status(op->send_initial_metadata)) { + s->seen_error = true; } - if (!stream_global->write_closed) { - if (transport_global->is_client) { - GPR_ASSERT(stream_global->id == 0); - grpc_chttp2_list_add_waiting_for_concurrency(transport_global, - stream_global); - maybe_start_some_streams(exec_ctx, transport_global); + if (!s->write_closed) { + if (t->is_client) { + GPR_ASSERT(s->id == 0); + grpc_chttp2_list_add_waiting_for_concurrency(t, s); + maybe_start_some_streams(exec_ctx, t); } else { - GPR_ASSERT(stream_global->id != 0); - grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, - true, "op.send_initial_metadata"); + GPR_ASSERT(s->id != 0); + grpc_chttp2_become_writable(exec_ctx, t, s, true, + "op.send_initial_metadata"); } } else { - stream_global->send_trailing_metadata = NULL; + s->send_trailing_metadata = NULL; grpc_chttp2_complete_closure_step( - exec_ctx, transport_global, stream_global, - &stream_global->send_initial_metadata_finished, + exec_ctx, t, s, &s->send_initial_metadata_finished, GRPC_ERROR_CREATE( - "Attempt to send initial metadata after stream was closed")); + "Attempt to send initial metadata after stream was closed"), + "send_initial_metadata_finished"); } } } if (op->send_message != NULL) { - GPR_ASSERT(stream_global->send_message_finished == NULL); - GPR_ASSERT(stream_global->send_message == NULL); - stream_global->send_message_finished = add_closure_barrier(on_complete); - if (stream_global->write_closed) { + s->fetching_send_message_finished = add_closure_barrier(op->on_complete); + if (s->write_closed) { grpc_chttp2_complete_closure_step( - exec_ctx, transport_global, stream_global, - &stream_global->send_message_finished, - GRPC_ERROR_CREATE("Attempt to send message after stream was closed")); + exec_ctx, t, s, &s->fetching_send_message_finished, + GRPC_ERROR_CREATE("Attempt to send message after stream was closed"), + "fetching_send_message_finished"); } else { - stream_global->send_message = op->send_message; - if (stream_global->id != 0) { - grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, - true, "op.send_message"); + GPR_ASSERT(s->fetching_send_message == NULL); + uint8_t *frame_hdr = + gpr_slice_buffer_tiny_add(&s->flow_controlled_buffer, 5); + uint32_t flags = op->send_message->flags; + frame_hdr[0] = (flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0; + size_t len = op->send_message->length; + frame_hdr[1] = (uint8_t)(len >> 24); + frame_hdr[2] = (uint8_t)(len >> 16); + frame_hdr[3] = (uint8_t)(len >> 8); + frame_hdr[4] = (uint8_t)(len); + s->fetching_send_message = op->send_message; + s->fetched_send_message_length = 0; + s->next_message_end_offset = s->flow_controlled_bytes_written + + (int64_t)s->flow_controlled_buffer.length + + (int64_t)len; + s->complete_fetch_covered_by_poller = op->covered_by_poller; + if (flags & GRPC_WRITE_BUFFER_HINT) { + /* allow up to 64kb to be buffered */ + /* TODO(ctiller): make this configurable */ + s->next_message_end_offset -= 65536; + } + continue_fetching_send_locked(exec_ctx, t, s); + if (s->id != 0) { + grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message"); } } } if (op->send_trailing_metadata != NULL) { - GPR_ASSERT(stream_global->send_trailing_metadata_finished == NULL); - stream_global->send_trailing_metadata_finished = - add_closure_barrier(on_complete); - stream_global->send_trailing_metadata = op->send_trailing_metadata; + GPR_ASSERT(s->send_trailing_metadata_finished == NULL); + s->send_trailing_metadata_finished = add_closure_barrier(on_complete); + s->send_trailing_metadata = op->send_trailing_metadata; const size_t metadata_size = grpc_metadata_batch_size(op->send_trailing_metadata); const size_t metadata_peer_limit = - transport_global->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; + t->settings[GRPC_PEER_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; if (metadata_size > metadata_peer_limit) { - cancel_from_api( - exec_ctx, transport_global, stream_global, + grpc_chttp2_cancel_stream( + exec_ctx, t, s, grpc_error_set_int( grpc_error_set_int( grpc_error_set_int( @@ -1150,69 +1070,59 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op, GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); } else { - if (contains_non_ok_status(transport_global, - op->send_trailing_metadata)) { - stream_global->seen_error = true; - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); + if (contains_non_ok_status(op->send_trailing_metadata)) { + s->seen_error = true; } - if (stream_global->write_closed) { - stream_global->send_trailing_metadata = NULL; + if (s->write_closed) { + s->send_trailing_metadata = NULL; grpc_chttp2_complete_closure_step( - exec_ctx, transport_global, stream_global, - &stream_global->send_trailing_metadata_finished, + exec_ctx, t, s, &s->send_trailing_metadata_finished, grpc_metadata_batch_is_empty(op->send_trailing_metadata) ? GRPC_ERROR_NONE : GRPC_ERROR_CREATE("Attempt to send trailing metadata after " - "stream was closed")); - } else if (stream_global->id != 0) { + "stream was closed"), + "send_trailing_metadata_finished"); + } else if (s->id != 0) { /* TODO(ctiller): check if there's flow control for any outstanding bytes before going writable */ - grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, - true, "op.send_trailing_metadata"); + grpc_chttp2_become_writable(exec_ctx, t, s, true, + "op.send_trailing_metadata"); } } } if (op->recv_initial_metadata != NULL) { - GPR_ASSERT(stream_global->recv_initial_metadata_ready == NULL); - stream_global->recv_initial_metadata_ready = - op->recv_initial_metadata_ready; - stream_global->recv_initial_metadata = op->recv_initial_metadata; - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); + GPR_ASSERT(s->recv_initial_metadata_ready == NULL); + s->recv_initial_metadata_ready = op->recv_initial_metadata_ready; + s->recv_initial_metadata = op->recv_initial_metadata; + grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s); } if (op->recv_message != NULL) { - GPR_ASSERT(stream_global->recv_message_ready == NULL); - stream_global->recv_message_ready = op->recv_message_ready; - stream_global->recv_message = op->recv_message; - if (stream_global->id != 0 && - (stream_global->incoming_frames.head == NULL || - stream_global->incoming_frames.head->is_tail)) { - incoming_byte_stream_update_flow_control( - exec_ctx, transport_global, stream_global, - transport_global->stream_lookahead, 0); + GPR_ASSERT(s->recv_message_ready == NULL); + s->recv_message_ready = op->recv_message_ready; + s->recv_message = op->recv_message; + if (s->id != 0 && + (s->incoming_frames.head == NULL || s->incoming_frames.head->is_tail)) { + incoming_byte_stream_update_flow_control(exec_ctx, t, s, + t->stream_lookahead, 0); } - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); + grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); } if (op->recv_trailing_metadata != NULL) { - GPR_ASSERT(stream_global->recv_trailing_metadata_finished == NULL); - stream_global->recv_trailing_metadata_finished = - add_closure_barrier(on_complete); - stream_global->recv_trailing_metadata = op->recv_trailing_metadata; - stream_global->final_metadata_requested = true; - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); + GPR_ASSERT(s->recv_trailing_metadata_finished == NULL); + s->recv_trailing_metadata_finished = add_closure_barrier(on_complete); + s->recv_trailing_metadata = op->recv_trailing_metadata; + s->final_metadata_requested = true; + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); } - grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global, - &on_complete, GRPC_ERROR_NONE); + grpc_chttp2_complete_closure_step(exec_ctx, t, s, &on_complete, + GRPC_ERROR_NONE, "op->on_complete"); GPR_TIMER_END("perform_stream_op_locked", 0); - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "perform_stream_op"); + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "perform_stream_op"); } static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, @@ -1220,70 +1130,60 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, GPR_TIMER_BEGIN("perform_stream_op", 0); grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs; + + if (grpc_http_trace) { + char *str = grpc_transport_stream_op_string(op); + gpr_log(GPR_DEBUG, "perform_stream_op[s=%p/%d]: %s", s, s->id, str); + gpr_free(str); + } + grpc_closure_init(&op->transport_private.closure, perform_stream_op_locked, op); op->transport_private.args[0] = gt; op->transport_private.args[1] = gs; - GRPC_CHTTP2_STREAM_REF(&s->global, "perform_stream_op"); - grpc_combiner_execute(exec_ctx, t->executor.combiner, - &op->transport_private.closure, GRPC_ERROR_NONE); + GRPC_CHTTP2_STREAM_REF(s, "perform_stream_op"); + grpc_combiner_execute(exec_ctx, t->combiner, &op->transport_private.closure, + GRPC_ERROR_NONE, op->covered_by_poller); GPR_TIMER_END("perform_stream_op", 0); } static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_closure *on_recv) { grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p)); - p->next = &t->global.pings; + p->next = &t->pings; p->prev = p->next->prev; p->prev->next = p->next->prev = p; - p->id[0] = (uint8_t)((t->global.ping_counter >> 56) & 0xff); - p->id[1] = (uint8_t)((t->global.ping_counter >> 48) & 0xff); - p->id[2] = (uint8_t)((t->global.ping_counter >> 40) & 0xff); - p->id[3] = (uint8_t)((t->global.ping_counter >> 32) & 0xff); - p->id[4] = (uint8_t)((t->global.ping_counter >> 24) & 0xff); - p->id[5] = (uint8_t)((t->global.ping_counter >> 16) & 0xff); - p->id[6] = (uint8_t)((t->global.ping_counter >> 8) & 0xff); - p->id[7] = (uint8_t)(t->global.ping_counter & 0xff); + p->id[0] = (uint8_t)((t->ping_counter >> 56) & 0xff); + p->id[1] = (uint8_t)((t->ping_counter >> 48) & 0xff); + p->id[2] = (uint8_t)((t->ping_counter >> 40) & 0xff); + p->id[3] = (uint8_t)((t->ping_counter >> 32) & 0xff); + p->id[4] = (uint8_t)((t->ping_counter >> 24) & 0xff); + p->id[5] = (uint8_t)((t->ping_counter >> 16) & 0xff); + p->id[6] = (uint8_t)((t->ping_counter >> 8) & 0xff); + p->id[7] = (uint8_t)(t->ping_counter & 0xff); + t->ping_counter++; p->on_recv = on_recv; - gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id)); - grpc_chttp2_initiate_write(exec_ctx, &t->global, true, "send_ping"); + gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(0, p->id)); + grpc_chttp2_initiate_write(exec_ctx, t, true, "send_ping"); } -typedef struct ack_ping_args { - grpc_closure closure; - grpc_chttp2_transport *t; - uint8_t opaque_8bytes[8]; -} ack_ping_args; - -static void ack_ping_locked(grpc_exec_ctx *exec_ctx, void *a, - grpc_error *error_ignored) { - ack_ping_args *args = a; +void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + const uint8_t *opaque_8bytes) { grpc_chttp2_outstanding_ping *ping; - grpc_chttp2_transport_global *transport_global = &args->t->global; - for (ping = transport_global->pings.next; ping != &transport_global->pings; - ping = ping->next) { - if (0 == memcmp(args->opaque_8bytes, ping->id, 8)) { + for (ping = t->pings.next; ping != &t->pings; ping = ping->next) { + if (0 == memcmp(opaque_8bytes, ping->id, 8)) { grpc_exec_ctx_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE, NULL); ping->next->prev = ping->prev; ping->prev->next = ping->next; gpr_free(ping); - break; + return; } } - UNREF_TRANSPORT(exec_ctx, args->t, "ack_ping"); - gpr_free(args); -} - -void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *transport_parsing, - const uint8_t *opaque_8bytes) { - ack_ping_args *args = gpr_malloc(sizeof(*args)); - args->t = TRANSPORT_FROM_PARSING(transport_parsing); - memcpy(args->opaque_8bytes, opaque_8bytes, sizeof(args->opaque_8bytes)); - grpc_closure_init(&args->closure, ack_ping_locked, args); - REF_TRANSPORT(args->t, "ack_ping"); - grpc_combiner_execute(exec_ctx, args->t->executor.combiner, &args->closure, - GRPC_ERROR_NONE); + char *msg = gpr_dump((const char *)opaque_8bytes, 8, GPR_DUMP_HEX); + char *from = grpc_endpoint_get_peer(t->ep); + gpr_log(GPR_DEBUG, "Unknown ping response from %s: %s", from, msg); + gpr_free(from); + gpr_free(msg); } static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, @@ -1293,15 +1193,6 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t = op->transport_private.args[0]; grpc_error *close_transport = op->disconnect_with_error; - /* If there's a set_accept_stream ensure that we're not parsing - to avoid changing things out from underneath */ - if (t->executor.parsing_active && op->set_accept_stream) { - GPR_ASSERT(t->post_parsing_op == NULL); - t->post_parsing_op = gpr_malloc(sizeof(*op)); - memcpy(t->post_parsing_op, op, sizeof(*op)); - return; - } - if (op->on_connectivity_state_change != NULL) { grpc_connectivity_state_notify_on_state_change( exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state, @@ -1309,15 +1200,15 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, } if (op->send_goaway) { - t->global.sent_goaway = 1; + t->sent_goaway = 1; grpc_chttp2_goaway_append( - t->global.last_incoming_stream_id, + t->last_new_stream_id, (uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status), - gpr_slice_ref(*op->goaway_message), &t->global.qbuf); - close_transport = grpc_chttp2_has_streams(t) - ? GRPC_ERROR_NONE - : GRPC_ERROR_CREATE("GOAWAY sent"); - grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "goaway_sent"); + gpr_slice_ref(*op->goaway_message), &t->qbuf); + close_transport = grpc_chttp2_stream_map_size(&t->stream_map) == 0 + ? GRPC_ERROR_CREATE("GOAWAY sent") + : GRPC_ERROR_NONE; + grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent"); } if (op->set_accept_stream) { @@ -1342,154 +1233,127 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, close_transport_locked(exec_ctx, t, close_transport); } - grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL); + grpc_closure_run(exec_ctx, op->on_consumed, GRPC_ERROR_NONE); - UNREF_TRANSPORT(exec_ctx, t, "transport_op"); + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "transport_op"); } static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, grpc_transport_op *op) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt; + char *msg = grpc_transport_op_string(op); + gpr_free(msg); op->transport_private.args[0] = gt; grpc_closure_init(&op->transport_private.closure, perform_transport_op_locked, op); - REF_TRANSPORT(t, "transport_op"); - grpc_combiner_execute(exec_ctx, t->executor.combiner, - &op->transport_private.closure, GRPC_ERROR_NONE); + GRPC_CHTTP2_REF_TRANSPORT(t, "transport_op"); + grpc_combiner_execute(exec_ctx, t->combiner, &op->transport_private.closure, + GRPC_ERROR_NONE, false); } /******************************************************************************* * INPUT PROCESSING - GENERAL */ -static void check_read_ops(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global) { - GPR_TIMER_BEGIN("check_read_ops", 0); - grpc_chttp2_stream_global *stream_global; +void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { grpc_byte_stream *bs; - while ( - grpc_chttp2_list_pop_check_read_ops(transport_global, &stream_global)) { - if (stream_global->recv_initial_metadata_ready != NULL && - stream_global->published_initial_metadata) { - if (stream_global->seen_error) { - while ((bs = grpc_chttp2_incoming_frame_queue_pop( - &stream_global->incoming_frames)) != NULL) { - incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); - } - if (stream_global->exceeded_metadata_size) { - cancel_from_api( - exec_ctx, transport_global, stream_global, - grpc_error_set_int( - GRPC_ERROR_CREATE( - "received initial metadata size exceeds limit"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); - } + if (s->recv_initial_metadata_ready != NULL && + s->published_metadata[0] != GRPC_METADATA_NOT_PUBLISHED) { + if (s->seen_error) { + while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) != + NULL) { + incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); } - grpc_chttp2_incoming_metadata_buffer_publish( - &stream_global->received_initial_metadata, - stream_global->recv_initial_metadata); - grpc_exec_ctx_sched(exec_ctx, stream_global->recv_initial_metadata_ready, - GRPC_ERROR_NONE, NULL); - stream_global->recv_initial_metadata_ready = NULL; } - if (stream_global->recv_message_ready != NULL) { - while (stream_global->final_metadata_requested && - stream_global->seen_error && - (bs = grpc_chttp2_incoming_frame_queue_pop( - &stream_global->incoming_frames)) != NULL) { + grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[0], + s->recv_initial_metadata); + null_then_run_closure(exec_ctx, &s->recv_initial_metadata_ready, + GRPC_ERROR_NONE); + } +} + +void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + grpc_byte_stream *bs; + if (s->recv_message_ready != NULL) { + while (s->final_metadata_requested && s->seen_error && + (bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) != + NULL) { + incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); + } + if (s->incoming_frames.head != NULL) { + *s->recv_message = + grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames); + GPR_ASSERT(*s->recv_message != NULL); + null_then_run_closure(exec_ctx, &s->recv_message_ready, GRPC_ERROR_NONE); + } else if (s->published_metadata[1] != GRPC_METADATA_NOT_PUBLISHED) { + *s->recv_message = NULL; + null_then_run_closure(exec_ctx, &s->recv_message_ready, GRPC_ERROR_NONE); + } + } +} + +void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + grpc_byte_stream *bs; + grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); + if (s->recv_trailing_metadata_finished != NULL && s->read_closed && + s->write_closed) { + if (s->seen_error) { + while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) != + NULL) { incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); } - if (stream_global->incoming_frames.head != NULL) { - *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop( - &stream_global->incoming_frames); - GPR_ASSERT(*stream_global->recv_message != NULL); - grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready, - GRPC_ERROR_NONE, NULL); - stream_global->recv_message_ready = NULL; - } else if (stream_global->published_trailing_metadata) { - *stream_global->recv_message = NULL; - grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready, - GRPC_ERROR_NONE, NULL); - stream_global->recv_message_ready = NULL; - } } - if (stream_global->recv_trailing_metadata_finished != NULL && - stream_global->read_closed && stream_global->write_closed) { - if (stream_global->seen_error) { - while ((bs = grpc_chttp2_incoming_frame_queue_pop( - &stream_global->incoming_frames)) != NULL) { - incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE); - } - if (stream_global->exceeded_metadata_size) { - cancel_from_api( - exec_ctx, transport_global, stream_global, - grpc_error_set_int( - GRPC_ERROR_CREATE( - "received trailing metadata size exceeds limit"), - GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); - } - } - if (stream_global->all_incoming_byte_streams_finished) { - grpc_chttp2_incoming_metadata_buffer_publish( - &stream_global->received_trailing_metadata, - stream_global->recv_trailing_metadata); - grpc_chttp2_complete_closure_step( - exec_ctx, transport_global, stream_global, - &stream_global->recv_trailing_metadata_finished, GRPC_ERROR_NONE); - } + if (s->all_incoming_byte_streams_finished && + s->recv_trailing_metadata_finished != NULL) { + grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[1], + s->recv_trailing_metadata); + grpc_chttp2_complete_closure_step( + exec_ctx, t, s, &s->recv_trailing_metadata_finished, GRPC_ERROR_NONE, + "recv_trailing_metadata_finished"); } } - GPR_TIMER_END("check_read_ops", 0); } -static void decrement_active_streams_locked( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - if ((stream_global->all_incoming_byte_streams_finished = - gpr_unref(&stream_global->active_streams))) { - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); +static void decrement_active_streams_locked(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + if ((s->all_incoming_byte_streams_finished = gpr_unref(&s->active_streams))) { + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); } } static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, uint32_t id, grpc_error *error) { - size_t new_stream_count; - grpc_chttp2_stream *s = - grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id); - if (!s) { - s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id); - } + grpc_chttp2_stream *s = grpc_chttp2_stream_map_delete(&t->stream_map, id); GPR_ASSERT(s); - s->global.in_stream_map = false; - if (t->parsing.incoming_stream == &s->parsing) { - t->parsing.incoming_stream = NULL; - grpc_chttp2_parsing_become_skip_parser(exec_ctx, &t->parsing); + if (t->incoming_stream == s) { + t->incoming_stream = NULL; + grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); } - if (s->parsing.data_parser.parsing_frame != NULL) { + if (s->data_parser.parsing_frame != NULL) { grpc_chttp2_incoming_byte_stream_finished( - exec_ctx, s->parsing.data_parser.parsing_frame, GRPC_ERROR_REF(error), - 0); - s->parsing.data_parser.parsing_frame = NULL; + exec_ctx, s->data_parser.parsing_frame, GRPC_ERROR_REF(error)); + s->data_parser.parsing_frame = NULL; } - if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { + if (grpc_chttp2_stream_map_size(&t->stream_map) == 0 && t->sent_goaway) { close_transport_locked( exec_ctx, t, GRPC_ERROR_CREATE_REFERENCING( "Last stream closed after sending GOAWAY", &error, 1)); } - if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) { - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing"); + if (grpc_chttp2_list_remove_writable_stream(t, s)) { + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:remove_stream"); } - new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) + - grpc_chttp2_stream_map_size(&t->new_stream_map); - GPR_ASSERT(new_stream_count <= UINT32_MAX); - if (new_stream_count != t->global.concurrent_stream_count) { - t->global.concurrent_stream_count = (uint32_t)new_stream_count; - maybe_start_some_streams(exec_ctx, &t->global); - } GRPC_ERROR_UNREF(error); + + maybe_start_some_streams(exec_ctx, t); } static void status_codes_from_error(grpc_error *error, gpr_timespec deadline, @@ -1519,23 +1383,20 @@ static void status_codes_from_error(grpc_error *error, gpr_timespec deadline, } } -static void cancel_from_api(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - grpc_error *due_to_error) { - if (!stream_global->read_closed || !stream_global->write_closed) { +void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, grpc_chttp2_stream *s, + grpc_error *due_to_error) { + if (!s->read_closed || !s->write_closed) { grpc_status_code grpc_status; grpc_chttp2_error_code http_error; - status_codes_from_error(due_to_error, stream_global->deadline, &http_error, + status_codes_from_error(due_to_error, s->deadline, &http_error, &grpc_status); - if (stream_global->id != 0) { + if (s->id != 0) { gpr_slice_buffer_add( - &transport_global->qbuf, - grpc_chttp2_rst_stream_create(stream_global->id, (uint32_t)http_error, - &stream_global->stats.outgoing)); - grpc_chttp2_initiate_write(exec_ctx, transport_global, false, - "rst_stream"); + &t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error, + &s->stats.outgoing)); + grpc_chttp2_initiate_write(exec_ctx, t, false, "rst_stream"); } const char *msg = @@ -1546,27 +1407,21 @@ static void cancel_from_api(grpc_exec_ctx *exec_ctx, msg = grpc_error_string(due_to_error); } gpr_slice msg_slice = gpr_slice_from_copied_string(msg); - grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, - grpc_status, &msg_slice); + grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice); if (free_msg) grpc_error_free_string(msg); } - if (due_to_error != GRPC_ERROR_NONE && !stream_global->seen_error) { - stream_global->seen_error = true; - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); + if (due_to_error != GRPC_ERROR_NONE && !s->seen_error) { + s->seen_error = true; + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); } - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, - 1, due_to_error); + grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, due_to_error); } -void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - grpc_status_code status, gpr_slice *slice) { +void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_stream *s, grpc_status_code status, + gpr_slice *slice) { if (status != GRPC_STATUS_OK) { - stream_global->seen_error = true; - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); + s->seen_error = true; } /* stream_global->recv_trailing_metadata_finished gives us a last chance replacement: we've received trailing metadata, @@ -1574,24 +1429,23 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, to the upper layers - drop what we've got, and then publish what we want - which is safe because we haven't told anyone about the metadata yet */ - if (!stream_global->published_trailing_metadata || - stream_global->recv_trailing_metadata_finished != NULL) { + if (s->published_metadata[1] == GRPC_METADATA_NOT_PUBLISHED || + s->recv_trailing_metadata_finished != NULL) { char status_string[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(status, status_string); grpc_chttp2_incoming_metadata_buffer_add( - &stream_global->received_trailing_metadata, + &s->metadata_buffer[1], grpc_mdelem_from_metadata_strings( GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string))); if (slice) { grpc_chttp2_incoming_metadata_buffer_add( - &stream_global->received_trailing_metadata, + &s->metadata_buffer[1], grpc_mdelem_from_metadata_strings( GRPC_MDSTR_GRPC_MESSAGE, grpc_mdstr_from_slice(gpr_slice_ref(*slice)))); } - stream_global->published_trailing_metadata = true; - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); + s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE; + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); } if (slice) { gpr_slice_unref(*slice); @@ -1609,91 +1463,88 @@ static void add_error(grpc_error *error, grpc_error **refs, size_t *nrefs) { ++*nrefs; } -static grpc_error *removal_error(grpc_error *extra_error, - grpc_chttp2_stream_global *stream_global) { +static grpc_error *removal_error(grpc_error *extra_error, grpc_chttp2_stream *s, + const char *master_error_msg) { grpc_error *refs[3]; size_t nrefs = 0; - add_error(stream_global->read_closed_error, refs, &nrefs); - add_error(stream_global->write_closed_error, refs, &nrefs); + add_error(s->read_closed_error, refs, &nrefs); + add_error(s->write_closed_error, refs, &nrefs); add_error(extra_error, refs, &nrefs); grpc_error *error = GRPC_ERROR_NONE; if (nrefs > 0) { - error = GRPC_ERROR_CREATE_REFERENCING("Failed due to stream removal", refs, - nrefs); + error = GRPC_ERROR_CREATE_REFERENCING(master_error_msg, refs, nrefs); } GRPC_ERROR_UNREF(extra_error); return error; } static void fail_pending_writes(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, + grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_error *error) { - error = removal_error(error, stream_global); - stream_global->send_message = NULL; + error = + removal_error(error, s, "Pending writes failed due to stream closure"); + s->fetching_send_message = NULL; grpc_chttp2_complete_closure_step( - exec_ctx, transport_global, stream_global, - &stream_global->send_initial_metadata_finished, GRPC_ERROR_REF(error)); + exec_ctx, t, s, &s->send_initial_metadata_finished, GRPC_ERROR_REF(error), + "send_initial_metadata_finished"); grpc_chttp2_complete_closure_step( - exec_ctx, transport_global, stream_global, - &stream_global->send_trailing_metadata_finished, GRPC_ERROR_REF(error)); - grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global, - &stream_global->send_message_finished, - error); + exec_ctx, t, s, &s->send_trailing_metadata_finished, + GRPC_ERROR_REF(error), "send_trailing_metadata_finished"); + grpc_chttp2_complete_closure_step( + exec_ctx, t, s, &s->fetching_send_message_finished, GRPC_ERROR_REF(error), + "fetching_send_message_finished"); + while (s->on_write_finished_cbs) { + grpc_chttp2_write_cb *cb = s->on_write_finished_cbs; + s->on_write_finished_cbs = cb->next; + grpc_chttp2_complete_closure_step(exec_ctx, t, s, &cb->closure, + GRPC_ERROR_REF(error), + "on_write_finished_cb"); + cb->next = t->write_cb_pool; + t->write_cb_pool = cb; + } + GRPC_ERROR_UNREF(error); } -void grpc_chttp2_mark_stream_closed( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes, - grpc_error *error) { - if (stream_global->read_closed && stream_global->write_closed) { +void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, int close_reads, + int close_writes, grpc_error *error) { + if (s->read_closed && s->write_closed) { /* already closed */ GRPC_ERROR_UNREF(error); return; } - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); - if (close_reads && !stream_global->read_closed) { - stream_global->read_closed_error = GRPC_ERROR_REF(error); - stream_global->read_closed = true; - stream_global->published_initial_metadata = true; - stream_global->published_trailing_metadata = true; - decrement_active_streams_locked(exec_ctx, transport_global, stream_global); - } - if (close_writes && !stream_global->write_closed) { - stream_global->write_closed_error = GRPC_ERROR_REF(error); - stream_global->write_closed = true; - if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.write_state != - GRPC_CHTTP2_WRITING_INACTIVE) { - GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes"); - grpc_chttp2_list_add_closed_waiting_for_writing(transport_global, - stream_global); - } else { - fail_pending_writes(exec_ctx, transport_global, stream_global, - GRPC_ERROR_REF(error)); - } - } - if (stream_global->read_closed && stream_global->write_closed) { - if (stream_global->id != 0 && - TRANSPORT_FROM_GLOBAL(transport_global)->executor.parsing_active) { - grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global, - stream_global); - } else { - if (stream_global->id != 0) { - remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global), - stream_global->id, - removal_error(GRPC_ERROR_REF(error), stream_global)); + if (close_reads && !s->read_closed) { + s->read_closed_error = GRPC_ERROR_REF(error); + s->read_closed = true; + for (int i = 0; i < 2; i++) { + if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) { + s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE; } - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); } + decrement_active_streams_locked(exec_ctx, t, s); + grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s); + grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); + } + if (close_writes && !s->write_closed) { + s->write_closed_error = GRPC_ERROR_REF(error); + s->write_closed = true; + fail_pending_writes(exec_ctx, t, s, GRPC_ERROR_REF(error)); + grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); + } + if (s->read_closed && s->write_closed) { + if (s->id != 0) { + remove_stream(exec_ctx, t, s->id, + removal_error(GRPC_ERROR_REF(error), s, "Stream removed")); + } + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2"); } GRPC_ERROR_UNREF(error); } -static void close_from_api(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - grpc_error *error) { +static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_stream *s, grpc_error *error) { gpr_slice hdr; gpr_slice status_hdr; gpr_slice message_pfx; @@ -1701,16 +1552,17 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, uint32_t len = 0; grpc_status_code grpc_status; grpc_chttp2_error_code http_error; - status_codes_from_error(error, stream_global->deadline, &http_error, - &grpc_status); + status_codes_from_error(error, s->deadline, &http_error, &grpc_status); GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100); - if (stream_global->id != 0 && !transport_global->is_client) { + if (s->id != 0 && !t->is_client) { /* Hand roll a header block. - This is unnecessarily ugly - at some point we should find a more elegant + This is unnecessarily ugly - at some point we should find a more + elegant solution. - It's complicated by the fact that our send machinery would be dead by the + It's complicated by the fact that our send machinery would be dead by + the time we got around to sending this, so instead we ignore HPACK compression and just write the uncompressed bytes onto the wire. */ @@ -1775,23 +1627,22 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, *p++ = (uint8_t)(len); *p++ = GRPC_CHTTP2_FRAME_HEADER; *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS; - *p++ = (uint8_t)(stream_global->id >> 24); - *p++ = (uint8_t)(stream_global->id >> 16); - *p++ = (uint8_t)(stream_global->id >> 8); - *p++ = (uint8_t)(stream_global->id); + *p++ = (uint8_t)(s->id >> 24); + *p++ = (uint8_t)(s->id >> 16); + *p++ = (uint8_t)(s->id >> 8); + *p++ = (uint8_t)(s->id); GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr)); - gpr_slice_buffer_add(&transport_global->qbuf, hdr); - gpr_slice_buffer_add(&transport_global->qbuf, status_hdr); + gpr_slice_buffer_add(&t->qbuf, hdr); + gpr_slice_buffer_add(&t->qbuf, status_hdr); if (optional_message) { - gpr_slice_buffer_add(&transport_global->qbuf, message_pfx); - gpr_slice_buffer_add(&transport_global->qbuf, + gpr_slice_buffer_add(&t->qbuf, message_pfx); + gpr_slice_buffer_add(&t->qbuf, gpr_slice_from_copied_string(optional_message)); } gpr_slice_buffer_add( - &transport_global->qbuf, - grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR, - &stream_global->stats.outgoing)); + &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR, + &s->stats.outgoing)); } const char *msg = grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE); @@ -1801,46 +1652,33 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, msg = grpc_error_string(error); } gpr_slice msg_slice = gpr_slice_from_copied_string(msg); - grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, - grpc_status, &msg_slice); + grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice); if (free_msg) grpc_error_free_string(msg); - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, - 1, error); - grpc_chttp2_initiate_write(exec_ctx, transport_global, false, - "close_from_api"); + grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, error); + grpc_chttp2_initiate_write(exec_ctx, t, false, "close_from_api"); } typedef struct { grpc_exec_ctx *exec_ctx; grpc_error *error; + grpc_chttp2_transport *t; } cancel_stream_cb_args; -static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global, - void *user_data, - grpc_chttp2_stream_global *stream_global) { +static void cancel_stream_cb(void *user_data, uint32_t key, void *stream) { cancel_stream_cb_args *args = user_data; - cancel_from_api(args->exec_ctx, transport_global, stream_global, - GRPC_ERROR_REF(args->error)); + grpc_chttp2_stream *s = stream; + grpc_chttp2_cancel_stream(args->exec_ctx, args->t, s, + GRPC_ERROR_REF(args->error)); } static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_error *error) { - cancel_stream_cb_args args = {exec_ctx, error}; - grpc_chttp2_for_all_streams(&t->global, &args, cancel_stream_cb); + cancel_stream_cb_args args = {exec_ctx, error, t}; + grpc_chttp2_stream_map_for_each(&t->stream_map, cancel_stream_cb, &args); GRPC_ERROR_UNREF(error); } -static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, - grpc_error *error) { - if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) { - error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, - GRPC_STATUS_UNAVAILABLE); - } - close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error)); - end_all_the_calls(exec_ctx, t, error); -} - /** update window from a settings change */ typedef struct { grpc_chttp2_transport *t; @@ -1851,20 +1689,23 @@ static void update_global_window(void *args, uint32_t id, void *stream) { update_global_window_args *a = args; grpc_chttp2_transport *t = a->t; grpc_chttp2_stream *s = stream; - grpc_chttp2_transport_global *transport_global = &t->global; - grpc_chttp2_stream_global *stream_global = &s->global; int was_zero; int is_zero; - int64_t initial_window_update = t->parsing.initial_window_update; + int64_t initial_window_update = t->initial_window_update; - was_zero = stream_global->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", transport_global, stream_global, - outgoing_window, initial_window_update); - is_zero = stream_global->outgoing_window <= 0; + if (initial_window_update > 0) { + was_zero = s->outgoing_window <= 0; + GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", t, s, outgoing_window, + initial_window_update); + is_zero = s->outgoing_window <= 0; - if (was_zero && !is_zero) { - grpc_chttp2_become_writable(a->exec_ctx, transport_global, stream_global, - true, "update_global_window"); + if (was_zero && !is_zero) { + grpc_chttp2_become_writable(a->exec_ctx, t, s, true, + "update_global_window"); + } + } else { + GRPC_CHTTP2_FLOW_DEBIT_STREAM("settings", t, s, outgoing_window, + -initial_window_update); } } @@ -1872,50 +1713,19 @@ static void update_global_window(void *args, uint32_t id, void *stream) { * INPUT PROCESSING - PARSING */ -static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error); -static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error); -static void post_parse_locked(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error); - -static void reading_action(grpc_exec_ctx *exec_ctx, void *tp, - grpc_error *error) { +static void read_action_begin(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { /* Control flow: reading_action_locked -> (parse_unlocked -> post_parse_locked)? -> post_reading_action_locked */ GPR_TIMER_BEGIN("reading_action", 0); grpc_chttp2_transport *t = tp; - grpc_combiner_execute(exec_ctx, t->executor.combiner, - &t->reading_action_locked, GRPC_ERROR_REF(error)); + grpc_combiner_execute(exec_ctx, t->combiner, &t->read_action_locked, + GRPC_ERROR_REF(error), false); GPR_TIMER_END("reading_action", 0); } -static void reading_action_locked(grpc_exec_ctx *exec_ctx, void *tp, - grpc_error *error) { - GPR_TIMER_BEGIN("reading_action_locked", 0); - - grpc_chttp2_transport *t = tp; - grpc_chttp2_transport_global *transport_global = &t->global; - grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; - - GPR_ASSERT(!t->executor.parsing_active); - if (!t->closed) { - t->executor.parsing_active = 1; - /* merge stream lists */ - grpc_chttp2_stream_map_move_into(&t->new_stream_map, - &t->parsing_stream_map); - grpc_chttp2_prepare_to_read(transport_global, transport_parsing); - grpc_exec_ctx_sched(exec_ctx, &t->parsing_action, GRPC_ERROR_REF(error), - NULL); - } else { - post_reading_action_locked(exec_ctx, t, error); - } - - GPR_TIMER_END("reading_action_locked", 0); -} - static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { grpc_http_parser parser; @@ -1944,131 +1754,102 @@ static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx, return error; } -static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - grpc_chttp2_transport *t = arg; - grpc_error *err = GRPC_ERROR_NONE; - GPR_TIMER_BEGIN("reading_action.parse", 0); - size_t i = 0; - grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE, - GRPC_ERROR_NONE}; - for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) { - errors[1] = grpc_chttp2_perform_read(exec_ctx, &t->parsing, - t->read_buffer.slices[i]); - }; - if (errors[1] == GRPC_ERROR_NONE) { - err = GRPC_ERROR_REF(error); - } else { - errors[2] = try_http_parsing(exec_ctx, t); - err = GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors, - GPR_ARRAY_SIZE(errors)); +static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + GPR_TIMER_BEGIN("reading_action_locked", 0); + + grpc_chttp2_transport *t = tp; + + GRPC_ERROR_REF(error); + + grpc_error *err = error; + if (err != GRPC_ERROR_NONE) { + err = grpc_error_set_int( + GRPC_ERROR_CREATE_REFERENCING("Endpoint read failed", &err, 1), + GRPC_ERROR_INT_OCCURRED_DURING_WRITE, t->write_state); } - for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) { - GRPC_ERROR_UNREF(errors[i]); + GPR_SWAP(grpc_error *, err, error); + GRPC_ERROR_UNREF(err); + if (!t->closed) { + GPR_TIMER_BEGIN("reading_action.parse", 0); + size_t i = 0; + grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE, + GRPC_ERROR_NONE}; + for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) { + errors[1] = + grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]); + }; + if (errors[1] != GRPC_ERROR_NONE) { + errors[2] = try_http_parsing(exec_ctx, t); + GRPC_ERROR_UNREF(error); + error = GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors, + GPR_ARRAY_SIZE(errors)); + } + for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) { + GRPC_ERROR_UNREF(errors[i]); + } + GPR_TIMER_END("reading_action.parse", 0); + + GPR_TIMER_BEGIN("post_parse_locked", 0); + if (t->initial_window_update != 0) { + update_global_window_args args = {t, exec_ctx}; + grpc_chttp2_stream_map_for_each(&t->stream_map, update_global_window, + &args); + t->initial_window_update = 0; + } + /* handle higher level things */ + if (t->incoming_window < t->connection_window_target * 3 / 4) { + int64_t announce_bytes = t->connection_window_target - t->incoming_window; + GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, announce_incoming_window, + announce_bytes); + GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, incoming_window, + announce_bytes); + grpc_chttp2_initiate_write(exec_ctx, t, false, "global incoming window"); + } + + GPR_TIMER_END("post_parse_locked", 0); } - grpc_combiner_execute(exec_ctx, t->executor.combiner, &t->post_parse_locked, - err); - GPR_TIMER_END("reading_action.parse", 0); -} -static void post_parse_locked(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - GPR_TIMER_BEGIN("post_parse_locked", 0); - grpc_chttp2_transport *t = arg; - grpc_chttp2_transport_global *transport_global = &t->global; - grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; - /* copy parsing qbuf to global qbuf */ - if (t->parsing.qbuf.count > 0) { - gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf); - grpc_chttp2_initiate_write(exec_ctx, transport_global, false, - "parsing_qbuf"); - } - /* merge stream lists */ - grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map); - transport_global->concurrent_stream_count = - (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map); - if (transport_parsing->initial_window_update != 0) { - update_global_window_args args = {t, exec_ctx}; - grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, - update_global_window, &args); - transport_parsing->initial_window_update = 0; - } - /* handle higher level things */ - grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing); - t->executor.parsing_active = 0; - /* handle delayed transport ops (if there is one) */ - if (t->post_parsing_op) { - grpc_transport_op *op = t->post_parsing_op; - t->post_parsing_op = NULL; - perform_transport_op_locked(exec_ctx, op, GRPC_ERROR_NONE); - gpr_free(op); - } - /* if a stream is in the stream map, and gets cancelled, we need to - * ensure we are not parsing before continuing the cancellation to keep - * things in a sane state */ - grpc_chttp2_stream_global *stream_global; - while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global, - &stream_global)) { - GPR_ASSERT(stream_global->in_stream_map); - GPR_ASSERT(stream_global->write_closed); - GPR_ASSERT(stream_global->read_closed); - remove_stream(exec_ctx, t, stream_global->id, - removal_error(GRPC_ERROR_NONE, stream_global)); - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); - } - - post_reading_action_locked(exec_ctx, t, error); - GPR_TIMER_END("post_parse_locked", 0); -} - -static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { GPR_TIMER_BEGIN("post_reading_action_locked", 0); - grpc_chttp2_transport *t = arg; bool keep_reading = false; - GRPC_ERROR_REF(error); if (error == GRPC_ERROR_NONE && t->closed) { error = GRPC_ERROR_CREATE("Transport closed"); } if (error != GRPC_ERROR_NONE) { - drop_connection(exec_ctx, t, GRPC_ERROR_REF(error)); + close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error)); t->endpoint_reading = 0; - if (grpc_http_write_state_trace) { - gpr_log(GPR_DEBUG, "R:%p -> 0 ws=%s", t, - write_state_name(t->executor.write_state)); - } } else if (!t->closed) { keep_reading = true; - REF_TRANSPORT(t, "keep_reading"); - prevent_endpoint_shutdown(t); + GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading"); } gpr_slice_buffer_reset_and_unref(&t->read_buffer); if (keep_reading) { - grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->reading_action); - allow_endpoint_shutdown_locked(exec_ctx, t); - UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); + grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->read_action_begin); + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading"); } else { - UNREF_TRANSPORT(exec_ctx, t, "reading_action"); + GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action"); } - GRPC_ERROR_UNREF(error); GPR_TIMER_END("post_reading_action_locked", 0); + + GRPC_ERROR_UNREF(error); + + GPR_TIMER_END("reading_action_locked", 0); } /******************************************************************************* * CALLBACK LOOP */ -static void connectivity_state_set( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_connectivity_state state, grpc_error *error, const char *reason) { +static void connectivity_state_set(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_connectivity_state state, + grpc_error *error, const char *reason) { GRPC_CHTTP2_IF_TRACING( gpr_log(GPR_DEBUG, "set connectivity_state=%d", state)); - grpc_connectivity_state_set( - exec_ctx, - &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker, - state, error, reason); + grpc_connectivity_state_set(exec_ctx, &t->channel_callback.state_tracker, + state, error, reason); } /******************************************************************************* @@ -2101,15 +1882,16 @@ static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx, } } -static void incoming_byte_stream_update_flow_control( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, size_t max_size_hint, - size_t have_already) { +static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + size_t max_size_hint, + size_t have_already) { uint32_t max_recv_bytes; /* clamp max recv hint to an allowable size */ - if (max_size_hint >= UINT32_MAX - transport_global->stream_lookahead) { - max_recv_bytes = UINT32_MAX - transport_global->stream_lookahead; + if (max_size_hint >= UINT32_MAX - t->stream_lookahead) { + max_recv_bytes = UINT32_MAX - t->stream_lookahead; } else { max_recv_bytes = (uint32_t)max_size_hint; } @@ -2122,23 +1904,21 @@ static void incoming_byte_stream_update_flow_control( } /* add some small lookahead to keep pipelines flowing */ - GPR_ASSERT(max_recv_bytes <= UINT32_MAX - transport_global->stream_lookahead); - max_recv_bytes += transport_global->stream_lookahead; - if (stream_global->max_recv_bytes < max_recv_bytes) { - uint32_t add_max_recv_bytes = - max_recv_bytes - stream_global->max_recv_bytes; - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global, - max_recv_bytes, add_max_recv_bytes); - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global, - unannounced_incoming_window_for_parse, + GPR_ASSERT(max_recv_bytes <= UINT32_MAX - t->stream_lookahead); + max_recv_bytes += t->stream_lookahead; + if (s->max_recv_bytes < max_recv_bytes) { + uint32_t add_max_recv_bytes = max_recv_bytes - s->max_recv_bytes; + bool new_window_write_is_covered_by_poller = + s->max_recv_bytes < have_already; + GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, max_recv_bytes, + add_max_recv_bytes); + GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, incoming_window, add_max_recv_bytes); - GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global, - unannounced_incoming_window_for_writing, + GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, announce_window, add_max_recv_bytes); - grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global, - stream_global); - grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, - false, "read_incoming_stream"); + grpc_chttp2_become_writable(exec_ctx, t, s, + new_window_write_is_covered_by_poller, + "read_incoming_stream"); } } @@ -2146,25 +1926,23 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx, void *argp, grpc_error *error_ignored) { grpc_chttp2_incoming_byte_stream *bs = argp; - grpc_chttp2_transport_global *transport_global = &bs->transport->global; - grpc_chttp2_stream_global *stream_global = &bs->stream->global; + grpc_chttp2_transport *t = bs->transport; + grpc_chttp2_stream *s = bs->stream; if (bs->is_tail) { gpr_mu_lock(&bs->slice_mu); size_t cur_length = bs->slices.length; gpr_mu_unlock(&bs->slice_mu); incoming_byte_stream_update_flow_control( - exec_ctx, transport_global, stream_global, - bs->next_action.max_size_hint, cur_length); + exec_ctx, t, s, bs->next_action.max_size_hint, cur_length); } gpr_mu_lock(&bs->slice_mu); if (bs->slices.count > 0) { *bs->next_action.slice = gpr_slice_buffer_take_first(&bs->slices); - grpc_exec_ctx_sched(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE, - NULL); + grpc_closure_run(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE); } else if (bs->error != GRPC_ERROR_NONE) { - grpc_exec_ctx_sched(exec_ctx, bs->next_action.on_complete, - GRPC_ERROR_REF(bs->error), NULL); + grpc_closure_run(exec_ctx, bs->next_action.on_complete, + GRPC_ERROR_REF(bs->error)); } else { bs->on_next = bs->next_action.on_complete; bs->next = bs->next_action.slice; @@ -2186,8 +1964,8 @@ static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx, bs->next_action.on_complete = on_complete; grpc_closure_init(&bs->next_action.closure, incoming_byte_stream_next_locked, bs); - grpc_combiner_execute(exec_ctx, bs->transport->executor.combiner, - &bs->next_action.closure, GRPC_ERROR_NONE); + grpc_combiner_execute(exec_ctx, bs->transport->combiner, + &bs->next_action.closure, GRPC_ERROR_NONE, false); GPR_TIMER_END("incoming_byte_stream_next", 0); return 0; } @@ -2200,8 +1978,7 @@ static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, grpc_error *error_ignored) { grpc_chttp2_incoming_byte_stream *bs = byte_stream; GPR_ASSERT(bs->base.destroy == incoming_byte_stream_destroy); - decrement_active_streams_locked(exec_ctx, &bs->transport->global, - &bs->stream->global); + decrement_active_streams_locked(exec_ctx, bs->transport, bs->stream); incoming_byte_stream_unref(exec_ctx, bs); } @@ -2212,84 +1989,86 @@ static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx, (grpc_chttp2_incoming_byte_stream *)byte_stream; grpc_closure_init(&bs->destroy_action, incoming_byte_stream_destroy_locked, bs); - grpc_combiner_execute(exec_ctx, bs->transport->executor.combiner, - &bs->destroy_action, GRPC_ERROR_NONE); + grpc_combiner_execute(exec_ctx, bs->transport->combiner, &bs->destroy_action, + GRPC_ERROR_NONE, false); GPR_TIMER_END("incoming_byte_stream_destroy", 0); } -typedef struct { - grpc_chttp2_incoming_byte_stream *byte_stream; - gpr_slice slice; -} incoming_byte_stream_push_arg; +static void incoming_byte_stream_publish_error( + grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, + grpc_error *error) { + GPR_ASSERT(error != GRPC_ERROR_NONE); + grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL); + bs->on_next = NULL; + GRPC_ERROR_UNREF(bs->error); + bs->error = error; +} void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, gpr_slice slice) { gpr_mu_lock(&bs->slice_mu); - if (bs->on_next != NULL) { - *bs->next = slice; - grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL); - bs->on_next = NULL; + if (bs->remaining_bytes < GPR_SLICE_LENGTH(slice)) { + incoming_byte_stream_publish_error( + exec_ctx, bs, GRPC_ERROR_CREATE("Too many bytes in stream")); } else { - gpr_slice_buffer_add(&bs->slices, slice); + bs->remaining_bytes -= (uint32_t)GPR_SLICE_LENGTH(slice); + if (bs->on_next != NULL) { + *bs->next = slice; + grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL); + bs->on_next = NULL; + } else { + gpr_slice_buffer_add(&bs->slices, slice); + } } gpr_mu_unlock(&bs->slice_mu); } -static void incoming_byte_stream_finished_locked(grpc_exec_ctx *exec_ctx, - void *bsp, grpc_error *error) { - grpc_chttp2_incoming_byte_stream *bs = bsp; - if (error != GRPC_ERROR_NONE) { - grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL); - bs->on_next = NULL; - GRPC_ERROR_UNREF(bs->error); - bs->error = error; - } - incoming_byte_stream_unref(exec_ctx, bs); -} - void grpc_chttp2_incoming_byte_stream_finished( grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, - grpc_error *error, int from_parsing_thread) { - GPR_TIMER_BEGIN("grpc_chttp2_incoming_byte_stream_finished", 0); - if (from_parsing_thread) { - grpc_closure_init(&bs->finished_action, - incoming_byte_stream_finished_locked, bs); - grpc_combiner_execute(exec_ctx, bs->transport->executor.combiner, - &bs->finished_action, GRPC_ERROR_REF(error)); - } else { - incoming_byte_stream_finished_locked(exec_ctx, bs, error); + grpc_error *error) { + if (error == GRPC_ERROR_NONE) { + gpr_mu_lock(&bs->slice_mu); + if (bs->remaining_bytes != 0) { + error = GRPC_ERROR_CREATE("Truncated message"); + } + gpr_mu_unlock(&bs->slice_mu); + } + if (error != GRPC_ERROR_NONE) { + incoming_byte_stream_publish_error(exec_ctx, bs, error); } - GPR_TIMER_END("grpc_chttp2_incoming_byte_stream_finished", 0); + incoming_byte_stream_unref(exec_ctx, bs); } grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size, - uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue) { + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, + uint32_t frame_size, uint32_t flags) { grpc_chttp2_incoming_byte_stream *incoming_byte_stream = gpr_malloc(sizeof(*incoming_byte_stream)); incoming_byte_stream->base.length = frame_size; + incoming_byte_stream->remaining_bytes = frame_size; incoming_byte_stream->base.flags = flags; incoming_byte_stream->base.next = incoming_byte_stream_next; incoming_byte_stream->base.destroy = incoming_byte_stream_destroy; gpr_mu_init(&incoming_byte_stream->slice_mu); gpr_ref_init(&incoming_byte_stream->refs, 2); incoming_byte_stream->next_message = NULL; - incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing); - incoming_byte_stream->stream = STREAM_FROM_PARSING(stream_parsing); - gpr_ref(&incoming_byte_stream->stream->global.active_streams); + incoming_byte_stream->transport = t; + incoming_byte_stream->stream = s; + gpr_ref(&incoming_byte_stream->stream->active_streams); gpr_slice_buffer_init(&incoming_byte_stream->slices); incoming_byte_stream->on_next = NULL; incoming_byte_stream->is_tail = 1; incoming_byte_stream->error = GRPC_ERROR_NONE; - if (add_to_queue->head == NULL) { - add_to_queue->head = incoming_byte_stream; + grpc_chttp2_incoming_frame_queue *q = &s->incoming_frames; + if (q->head == NULL) { + q->head = incoming_byte_stream; } else { - add_to_queue->tail->is_tail = 0; - add_to_queue->tail->next_message = incoming_byte_stream; + q->tail->is_tail = 0; + q->tail->next_message = incoming_byte_stream; } - add_to_queue->tail = incoming_byte_stream; + q->tail = incoming_byte_stream; + grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s); return incoming_byte_stream; } @@ -2298,40 +2077,30 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( */ static char *format_flowctl_context_var(const char *context, const char *var, - int64_t val, uint32_t id, - char **scope) { - char *underscore_pos; - char *buf; - char *result; + int64_t val, uint32_t id) { + char *name; if (context == NULL) { - *scope = NULL; - gpr_asprintf(&buf, "%s(%" PRId64 ")", var, val); - result = gpr_leftpad(buf, ' ', 60); - gpr_free(buf); - return result; - } - underscore_pos = strchr(context, '_'); - *scope = gpr_strdup(context); - (*scope)[underscore_pos - context] = 0; - if (id != 0) { - char *tmp = *scope; - gpr_asprintf(scope, "%s[%d]", tmp, id); - gpr_free(tmp); - } - gpr_asprintf(&buf, "%s.%s(%" PRId64 ")", underscore_pos + 1, var, val); - result = gpr_leftpad(buf, ' ', 60); - gpr_free(buf); - return result; -} - -static int samestr(char *a, char *b) { - if (a == NULL) { - return b == NULL; - } - if (b == NULL) { - return 0; + name = gpr_strdup(var); + } else if (0 == strcmp(context, "t")) { + GPR_ASSERT(id == 0); + gpr_asprintf(&name, "TRANSPORT:%s", var); + } else if (0 == strcmp(context, "s")) { + GPR_ASSERT(id != 0); + gpr_asprintf(&name, "STREAM[%d]:%s", id, var); + } else { + gpr_asprintf(&name, "BAD_CONTEXT[%s][%d]:%s", context, id, var); } - return 0 == strcmp(a, b); + char *name_fld = gpr_leftpad(name, ' ', 64); + char *value; + gpr_asprintf(&value, "%" PRId64, val); + char *value_fld = gpr_leftpad(value, ' ', 8); + char *result; + gpr_asprintf(&result, "%s %s", name_fld, value_fld); + gpr_free(name); + gpr_free(name_fld); + gpr_free(value); + gpr_free(value_fld); + return result; } void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, @@ -2339,26 +2108,18 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, const char *var1, const char *context2, const char *var2, int is_client, uint32_t stream_id, int64_t val1, int64_t val2) { - char *scope1; - char *scope2; char *tmp_phase; - char *tmp_scope1; - char *label1 = - format_flowctl_context_var(context1, var1, val1, stream_id, &scope1); - char *label2 = - format_flowctl_context_var(context2, var2, val2, stream_id, &scope2); + char *label1 = format_flowctl_context_var(context1, var1, val1, stream_id); + char *label2 = format_flowctl_context_var(context2, var2, val2, stream_id); char *clisvr = is_client ? "client" : "server"; char *prefix; tmp_phase = gpr_leftpad(phase, ' ', 8); - tmp_scope1 = gpr_leftpad(scope1, ' ', 11); - gpr_asprintf(&prefix, "FLOW %s: %s %s ", tmp_phase, clisvr, scope1); + gpr_asprintf(&prefix, "FLOW %s: %s ", tmp_phase, clisvr); gpr_free(tmp_phase); - gpr_free(tmp_scope1); switch (op) { case GRPC_CHTTP2_FLOWCTL_MOVE: - GPR_ASSERT(samestr(scope1, scope2)); if (val2 != 0) { gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%sMOVE %s <- %s giving %" PRId64, prefix, label1, label2, @@ -2383,8 +2144,6 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, break; } - gpr_free(scope1); - gpr_free(scope2); gpr_free(label1); gpr_free(label2); gpr_free(prefix); @@ -2421,10 +2180,11 @@ void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx, grpc_transport *transport, gpr_slice_buffer *read_buffer) { grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport; - REF_TRANSPORT(t, "reading_action"); /* matches unref inside reading_action */ + GRPC_CHTTP2_REF_TRANSPORT( + t, "reading_action"); /* matches unref inside reading_action */ if (read_buffer != NULL) { gpr_slice_buffer_move_into(read_buffer, &t->read_buffer); gpr_free(read_buffer); } - reading_action(exec_ctx, t, GRPC_ERROR_NONE); + read_action_begin(exec_ctx, t, GRPC_ERROR_NONE); } diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h index 507aae4100..1e444a91fd 100644 --- a/src/core/ext/transport/chttp2/transport/frame.h +++ b/src/core/ext/transport/chttp2/transport/frame.h @@ -40,8 +40,8 @@ #include "src/core/lib/iomgr/error.h" /* defined in internal.h */ -typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing; -typedef struct grpc_chttp2_transport_parsing grpc_chttp2_transport_parsing; +typedef struct grpc_chttp2_stream grpc_chttp2_stream; +typedef struct grpc_chttp2_transport grpc_chttp2_transport; #define GRPC_CHTTP2_FRAME_DATA 0 #define GRPC_CHTTP2_FRAME_HEADER 1 diff --git a/src/core/ext/transport/chttp2/transport/frame_data.c b/src/core/ext/transport/chttp2/transport/frame_data.c index 9046fbc453..8668816930 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.c +++ b/src/core/ext/transport/chttp2/transport/frame_data.c @@ -51,16 +51,11 @@ grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser) { void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx, grpc_chttp2_data_parser *parser) { - grpc_byte_stream *bs; - if (parser->parsing_frame) { + if (parser->parsing_frame != NULL) { grpc_chttp2_incoming_byte_stream_finished( - exec_ctx, parser->parsing_frame, GRPC_ERROR_CREATE("Parser destroyed"), - 1); - } - while ( - (bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) { - grpc_byte_stream_destroy(exec_ctx, bs); + exec_ctx, parser->parsing_frame, GRPC_ERROR_CREATE("Parser destroyed")); } + GRPC_ERROR_UNREF(parser->error); } grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser, @@ -145,22 +140,17 @@ void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf, stats->data_bytes += write_bytes; } -grpc_error *grpc_chttp2_data_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { +static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx, + grpc_chttp2_data_parser *p, + grpc_chttp2_transport *t, grpc_chttp2_stream *s, + gpr_slice slice) { uint8_t *const beg = GPR_SLICE_START_PTR(slice); uint8_t *const end = GPR_SLICE_END_PTR(slice); uint8_t *cur = beg; - grpc_chttp2_data_parser *p = parser; uint32_t message_flags; grpc_chttp2_incoming_byte_stream *incoming_byte_stream; char *msg; - if (is_last && p->is_last_frame) { - stream_parsing->received_close = 1; - } - if (cur == end) { return GRPC_ERROR_NONE; } @@ -171,7 +161,7 @@ grpc_error *grpc_chttp2_data_parser_parse( return GRPC_ERROR_REF(p->error); fh_0: case GRPC_CHTTP2_DATA_FH_0: - stream_parsing->stats.incoming.framing_bytes++; + s->stats.incoming.framing_bytes++; p->frame_type = *cur; switch (p->frame_type) { case 0: @@ -184,7 +174,7 @@ grpc_error *grpc_chttp2_data_parser_parse( gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type); p->error = GRPC_ERROR_CREATE(msg); p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID, - (intptr_t)stream_parsing->id); + (intptr_t)s->id); gpr_free(msg); msg = gpr_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); p->error = @@ -201,7 +191,7 @@ grpc_error *grpc_chttp2_data_parser_parse( } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_1: - stream_parsing->stats.incoming.framing_bytes++; + s->stats.incoming.framing_bytes++; p->frame_size = ((uint32_t)*cur) << 24; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_2; @@ -209,7 +199,7 @@ grpc_error *grpc_chttp2_data_parser_parse( } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_2: - stream_parsing->stats.incoming.framing_bytes++; + s->stats.incoming.framing_bytes++; p->frame_size |= ((uint32_t)*cur) << 16; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_3; @@ -217,7 +207,7 @@ grpc_error *grpc_chttp2_data_parser_parse( } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_3: - stream_parsing->stats.incoming.framing_bytes++; + s->stats.incoming.framing_bytes++; p->frame_size |= ((uint32_t)*cur) << 8; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_4; @@ -225,7 +215,7 @@ grpc_error *grpc_chttp2_data_parser_parse( } /* fallthrough */ case GRPC_CHTTP2_DATA_FH_4: - stream_parsing->stats.incoming.framing_bytes++; + s->stats.incoming.framing_bytes++; p->frame_size |= ((uint32_t)*cur); p->state = GRPC_CHTTP2_DATA_FRAME; ++cur; @@ -234,35 +224,32 @@ grpc_error *grpc_chttp2_data_parser_parse( message_flags |= GRPC_WRITE_INTERNAL_COMPRESS; } p->parsing_frame = incoming_byte_stream = - grpc_chttp2_incoming_byte_stream_create( - exec_ctx, transport_parsing, stream_parsing, p->frame_size, - message_flags, &p->incoming_frames); + grpc_chttp2_incoming_byte_stream_create(exec_ctx, t, s, p->frame_size, + message_flags); /* fallthrough */ case GRPC_CHTTP2_DATA_FRAME: - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); if (cur == end) { return GRPC_ERROR_NONE; } uint32_t remaining = (uint32_t)(end - cur); if (remaining == p->frame_size) { - stream_parsing->stats.incoming.data_bytes += p->frame_size; + s->stats.incoming.data_bytes += p->frame_size; grpc_chttp2_incoming_byte_stream_push( exec_ctx, p->parsing_frame, gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, - GRPC_ERROR_NONE, 1); + GRPC_ERROR_NONE); p->parsing_frame = NULL; p->state = GRPC_CHTTP2_DATA_FH_0; return GRPC_ERROR_NONE; } else if (remaining > p->frame_size) { - stream_parsing->stats.incoming.data_bytes += p->frame_size; + s->stats.incoming.data_bytes += p->frame_size; grpc_chttp2_incoming_byte_stream_push( exec_ctx, p->parsing_frame, gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(cur + p->frame_size - beg))); grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, - GRPC_ERROR_NONE, 1); + GRPC_ERROR_NONE); p->parsing_frame = NULL; cur += p->frame_size; goto fh_0; /* loop */ @@ -272,10 +259,25 @@ grpc_error *grpc_chttp2_data_parser_parse( exec_ctx, p->parsing_frame, gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); p->frame_size -= remaining; - stream_parsing->stats.incoming.data_bytes += remaining; + s->stats.incoming.data_bytes += remaining; return GRPC_ERROR_NONE; } } GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); } + +grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last) { + grpc_chttp2_data_parser *p = parser; + grpc_error *error = parse_inner(exec_ctx, p, t, s, slice); + + if (is_last && p->is_last_frame) { + grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false, + GRPC_ERROR_NONE); + } + + return error; +} diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h index a21a7942b9..eb2d97d898 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.h +++ b/src/core/ext/transport/chttp2/transport/frame_data.h @@ -69,7 +69,6 @@ typedef struct { grpc_error *error; int is_frame_compressed; - grpc_chttp2_incoming_frame_queue incoming_frames; grpc_chttp2_incoming_byte_stream *parsing_frame; } grpc_chttp2_data_parser; @@ -92,10 +91,10 @@ grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser, /* handle a slice of a data frame - is_last indicates the last slice of a frame */ -grpc_error *grpc_chttp2_data_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); +grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last); void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf, uint32_t write_bytes, int is_eof, diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.c b/src/core/ext/transport/chttp2/transport/frame_goaway.c index 299e27ad70..33d2269169 100644 --- a/src/core/ext/transport/chttp2/transport/frame_goaway.c +++ b/src/core/ext/transport/chttp2/transport/frame_goaway.c @@ -67,10 +67,11 @@ grpc_error *grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser *p, return GRPC_ERROR_NONE; } -grpc_error *grpc_chttp2_goaway_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { +grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx, + void *parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last) { uint8_t *const beg = GPR_SLICE_START_PTR(slice); uint8_t *const end = GPR_SLICE_END_PTR(slice); uint8_t *cur = beg; @@ -148,12 +149,9 @@ grpc_error *grpc_chttp2_goaway_parser_parse( p->debug_pos += (uint32_t)(end - cur); p->state = GRPC_CHTTP2_GOAWAY_DEBUG; if (is_last) { - transport_parsing->goaway_received = 1; - transport_parsing->goaway_last_stream_index = p->last_stream_id; - gpr_slice_unref(transport_parsing->goaway_text); - transport_parsing->goaway_error = (grpc_status_code)p->error_code; - transport_parsing->goaway_text = - gpr_slice_new(p->debug_data, p->debug_length, gpr_free); + grpc_chttp2_add_incoming_goaway( + exec_ctx, t, (uint32_t)p->error_code, + gpr_slice_new(p->debug_data, p->debug_length, gpr_free)); p->debug_data = NULL; } return GRPC_ERROR_NONE; diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.h b/src/core/ext/transport/chttp2/transport/frame_goaway.h index eb4303405a..355104a5a7 100644 --- a/src/core/ext/transport/chttp2/transport/frame_goaway.h +++ b/src/core/ext/transport/chttp2/transport/frame_goaway.h @@ -65,10 +65,11 @@ void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p); void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p); grpc_error *grpc_chttp2_goaway_parser_begin_frame( grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags); -grpc_error *grpc_chttp2_goaway_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); +grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx, + void *parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last); void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code, gpr_slice debug_data, diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c index 1f814ab1bd..624f42649d 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.c +++ b/src/core/ext/transport/chttp2/transport/frame_ping.c @@ -73,10 +73,10 @@ grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser, return GRPC_ERROR_NONE; } -grpc_error *grpc_chttp2_ping_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { +grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last) { uint8_t *const beg = GPR_SLICE_START_PTR(slice); uint8_t *const end = GPR_SLICE_END_PTR(slice); uint8_t *cur = beg; @@ -91,10 +91,11 @@ grpc_error *grpc_chttp2_ping_parser_parse( if (p->byte == 8) { GPR_ASSERT(is_last); if (p->is_ack) { - grpc_chttp2_ack_ping(exec_ctx, transport_parsing, p->opaque_8bytes); + grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes); } else { - gpr_slice_buffer_add(&transport_parsing->qbuf, + gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(1, p->opaque_8bytes)); + grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response"); } } diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h index 5a8723421c..2071f647fb 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.h +++ b/src/core/ext/transport/chttp2/transport/frame_ping.h @@ -48,9 +48,9 @@ gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes); grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags); -grpc_error *grpc_chttp2_ping_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); +grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H */ diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c index e3a3c9e4a7..9eac050797 100644 --- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c +++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c @@ -39,6 +39,8 @@ #include <grpc/support/string_util.h> #include "src/core/ext/transport/chttp2/transport/frame.h" +#include "src/core/ext/transport/chttp2/transport/http2_errors.h" +#include "src/core/ext/transport/chttp2/transport/status_conversion.h" gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code, grpc_transport_one_way_stats *stats) { @@ -83,10 +85,11 @@ grpc_error *grpc_chttp2_rst_stream_parser_begin_frame( return GRPC_ERROR_NONE; } -grpc_error *grpc_chttp2_rst_stream_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { +grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx, + void *parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last) { uint8_t *const beg = GPR_SLICE_START_PTR(slice); uint8_t *const end = GPR_SLICE_END_PTR(slice); uint8_t *cur = beg; @@ -97,19 +100,28 @@ grpc_error *grpc_chttp2_rst_stream_parser_parse( cur++; p->byte++; } - stream_parsing->stats.incoming.framing_bytes += (uint64_t)(end - cur); + s->stats.incoming.framing_bytes += (uint64_t)(end - cur); if (p->byte == 4) { GPR_ASSERT(is_last); - stream_parsing->received_close = 1; - if (stream_parsing->forced_close_error == GRPC_ERROR_NONE) { - stream_parsing->forced_close_error = grpc_error_set_int( - GRPC_ERROR_CREATE("RST_STREAM"), GRPC_ERROR_INT_HTTP2_ERROR, - (intptr_t)((((uint32_t)p->reason_bytes[0]) << 24) | - (((uint32_t)p->reason_bytes[1]) << 16) | - (((uint32_t)p->reason_bytes[2]) << 8) | - (((uint32_t)p->reason_bytes[3])))); + uint32_t reason = (((uint32_t)p->reason_bytes[0]) << 24) | + (((uint32_t)p->reason_bytes[1]) << 16) | + (((uint32_t)p->reason_bytes[2]) << 8) | + (((uint32_t)p->reason_bytes[3])); + grpc_error *error = GRPC_ERROR_NONE; + if (reason != GRPC_CHTTP2_NO_ERROR) { + error = grpc_error_set_int(GRPC_ERROR_CREATE("RST_STREAM"), + GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason); + grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status( + (grpc_chttp2_error_code)reason, s->deadline); + char *status_details; + gpr_asprintf(&status_details, "Received RST_STREAM with error code %d", + reason); + gpr_slice slice_details = gpr_slice_from_copied_string(status_details); + gpr_free(status_details); + grpc_chttp2_fake_status(exec_ctx, t, s, status_code, &slice_details); } + grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, true, error); } return GRPC_ERROR_NONE; diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h index 11cf94f3ea..5a1f578a29 100644 --- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h +++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h @@ -49,9 +49,10 @@ gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code, grpc_error *grpc_chttp2_rst_stream_parser_begin_frame( grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags); -grpc_error *grpc_chttp2_rst_stream_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); +grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx, + void *parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H */ diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c index 04b96c4cd9..92022f90c9 100644 --- a/src/core/ext/transport/chttp2/transport/frame_settings.c +++ b/src/core/ext/transport/chttp2/transport/frame_settings.c @@ -143,10 +143,10 @@ grpc_error *grpc_chttp2_settings_parser_begin_frame( } } -grpc_error *grpc_chttp2_settings_parser_parse( - grpc_exec_ctx *exec_ctx, void *p, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { +grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last) { grpc_chttp2_settings_parser *parser = p; const uint8_t *cur = GPR_SLICE_START_PTR(slice); const uint8_t *end = GPR_SLICE_END_PTR(slice); @@ -162,11 +162,9 @@ grpc_error *grpc_chttp2_settings_parser_parse( if (cur == end) { parser->state = GRPC_CHTTP2_SPS_ID0; if (is_last) { - transport_parsing->settings_updated = 1; memcpy(parser->target_settings, parser->incoming_settings, GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); - gpr_slice_buffer_add(&transport_parsing->qbuf, - grpc_chttp2_settings_ack_create()); + gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create()); } return GRPC_ERROR_NONE; } @@ -226,9 +224,9 @@ grpc_error *grpc_chttp2_settings_parser_parse( break; case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE: grpc_chttp2_goaway_append( - transport_parsing->last_incoming_stream_id, sp->error_value, + t->last_new_stream_id, sp->error_value, gpr_slice_from_static_string("HTTP2 settings error"), - &transport_parsing->qbuf); + &t->qbuf); gpr_asprintf(&msg, "invalid value %u passed for %s", parser->value, sp->name); grpc_error *err = GRPC_ERROR_CREATE(msg); @@ -238,18 +236,17 @@ grpc_error *grpc_chttp2_settings_parser_parse( } if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && parser->incoming_settings[parser->id] != parser->value) { - transport_parsing->initial_window_update = + t->initial_window_update = (int64_t)parser->value - parser->incoming_settings[parser->id]; if (grpc_http_trace) { gpr_log(GPR_DEBUG, "adding %d for initial_window change", - (int)transport_parsing->initial_window_update); + (int)t->initial_window_update); } } parser->incoming_settings[parser->id] = parser->value; if (grpc_http_trace) { gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d", - transport_parsing->is_client ? "CLI" : "SVR", parser->id, - parser->value); + t->is_client ? "CLI" : "SVR", parser->id, parser->value); } } else if (grpc_http_trace) { gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h index f654c598c8..4bfa944cf1 100644 --- a/src/core/ext/transport/chttp2/transport/frame_settings.h +++ b/src/core/ext/transport/chttp2/transport/frame_settings.h @@ -95,9 +95,10 @@ gpr_slice grpc_chttp2_settings_ack_create(void); grpc_error *grpc_chttp2_settings_parser_begin_frame( grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags, uint32_t *settings); -grpc_error *grpc_chttp2_settings_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); +grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, + void *parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H */ diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.c b/src/core/ext/transport/chttp2/transport/frame_window_update.c index 3cf848fd5c..418166a6df 100644 --- a/src/core/ext/transport/chttp2/transport/frame_window_update.c +++ b/src/core/ext/transport/chttp2/transport/frame_window_update.c @@ -80,9 +80,8 @@ grpc_error *grpc_chttp2_window_update_parser_begin_frame( } grpc_error *grpc_chttp2_window_update_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { + grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_transport *t, + grpc_chttp2_stream *s, gpr_slice slice, int is_last) { uint8_t *const beg = GPR_SLICE_START_PTR(slice); uint8_t *const end = GPR_SLICE_END_PTR(slice); uint8_t *cur = beg; @@ -94,8 +93,8 @@ grpc_error *grpc_chttp2_window_update_parser_parse( p->byte++; } - if (stream_parsing != NULL) { - stream_parsing->stats.incoming.framing_bytes += (uint32_t)(end - cur); + if (s != NULL) { + s->stats.incoming.framing_bytes += (uint32_t)(end - cur); } if (p->byte == 4) { @@ -109,17 +108,26 @@ grpc_error *grpc_chttp2_window_update_parser_parse( } GPR_ASSERT(is_last); - if (transport_parsing->incoming_stream_id != 0) { - if (stream_parsing != NULL) { - GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", transport_parsing, - stream_parsing, outgoing_window, + if (t->incoming_stream_id != 0) { + if (s != NULL) { + bool was_zero = s->outgoing_window <= 0; + GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", t, s, outgoing_window, received_update); - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); + bool is_zero = s->outgoing_window <= 0; + if (was_zero && !is_zero) { + grpc_chttp2_become_writable(exec_ctx, t, s, false, + "stream.read_flow_control"); + } } } else { - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", transport_parsing, - outgoing_window, received_update); + bool was_zero = t->outgoing_window <= 0; + GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", t, outgoing_window, + received_update); + bool is_zero = t->outgoing_window <= 0; + if (was_zero && !is_zero) { + grpc_chttp2_initiate_write(exec_ctx, t, false, + "new_global_flow_control"); + } } } diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.h b/src/core/ext/transport/chttp2/transport/frame_window_update.h index 1bcbbf9247..6e62f31872 100644 --- a/src/core/ext/transport/chttp2/transport/frame_window_update.h +++ b/src/core/ext/transport/chttp2/transport/frame_window_update.h @@ -51,8 +51,7 @@ gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta, grpc_error *grpc_chttp2_window_update_parser_begin_frame( grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags); grpc_error *grpc_chttp2_window_update_parser_parse( - grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); + grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_transport *t, + grpc_chttp2_stream *s, gpr_slice slice, int is_last); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H */ diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c index 522455f7dc..8180f78fc0 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_parser.c +++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c @@ -78,69 +78,96 @@ typedef enum { a set of indirect jumps, and so not waste stack space. */ /* forward declarations for parsing states */ -static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_begin(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_error(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end, grpc_error *error); -static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p, +static grpc_error *still_parse_error(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_illegal_op(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_string_prefix(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_key_string(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); static grpc_error *parse_value_string_with_indexed_key( - grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); + grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); static grpc_error *parse_value_string_with_literal_key( - grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); + grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end); -static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value0(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value1(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value2(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value3(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value4(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_value5up(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_indexed_field(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_indexed_field_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_incidx(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_incidx_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_incidx_v(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_notidx(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_notidx_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_notidx_v(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_nvridx(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_nvridx_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_max_tbl_size(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); -static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_max_tbl_size_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end); /* we translate the first byte of a hpack field into one of these decoding @@ -639,8 +666,8 @@ static const uint8_t inverse_base64[256] = { }; /* emission helpers */ -static grpc_error *on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md, - int add_to_table) { +static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, + grpc_mdelem *md, int add_to_table) { if (add_to_table) { grpc_error *err = grpc_chttp2_hptbl_add(&p->table, md); if (err != GRPC_ERROR_NONE) return err; @@ -649,7 +676,7 @@ static grpc_error *on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md, GRPC_MDELEM_UNREF(md); return GRPC_ERROR_CREATE("on_header callback not set"); } - p->on_header(p->on_header_user_data, md); + p->on_header(exec_ctx, p->on_header_user_data, md); return GRPC_ERROR_NONE; } @@ -661,78 +688,86 @@ static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p, } /* jump to the next state */ -static grpc_error *parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_next(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { p->state = *p->next_state++; - return p->state(p, cur, end); + return p->state(exec_ctx, p, cur, end); } /* begin parsing a header: all functionality is encoded into lookup tables above */ -static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_begin(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_begin; return GRPC_ERROR_NONE; } - return first_byte_action[first_byte_lut[*cur]](p, cur, end); + return first_byte_action[first_byte_lut[*cur]](exec_ctx, p, cur, end); } /* stream dependency and prioritization data: we just skip it */ -static grpc_error *parse_stream_weight(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_stream_weight(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_stream_weight; return GRPC_ERROR_NONE; } - return p->after_prioritization(p, cur + 1, end); + return p->after_prioritization(exec_ctx, p, cur + 1, end); } -static grpc_error *parse_stream_dep3(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_stream_dep3(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_stream_dep3; return GRPC_ERROR_NONE; } - return parse_stream_weight(p, cur + 1, end); + return parse_stream_weight(exec_ctx, p, cur + 1, end); } -static grpc_error *parse_stream_dep2(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_stream_dep2(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_stream_dep2; return GRPC_ERROR_NONE; } - return parse_stream_dep3(p, cur + 1, end); + return parse_stream_dep3(exec_ctx, p, cur + 1, end); } -static grpc_error *parse_stream_dep1(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_stream_dep1(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_stream_dep1; return GRPC_ERROR_NONE; } - return parse_stream_dep2(p, cur + 1, end); + return parse_stream_dep2(exec_ctx, p, cur + 1, end); } -static grpc_error *parse_stream_dep0(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_stream_dep0(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_stream_dep0; return GRPC_ERROR_NONE; } - return parse_stream_dep1(p, cur + 1, end); + return parse_stream_dep1(exec_ctx, p, cur + 1, end); } /* emit an indexed field; for now just logs it to console; jumps to begin the next field on completion */ -static grpc_error *finish_indexed_field(grpc_chttp2_hpack_parser *p, +static grpc_error *finish_indexed_field(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); @@ -743,21 +778,23 @@ static grpc_error *finish_indexed_field(grpc_chttp2_hpack_parser *p, GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents); } GRPC_MDELEM_REF(md); - grpc_error *err = on_hdr(p, md, 0); + grpc_error *err = on_hdr(exec_ctx, p, md, 0); if (err != GRPC_ERROR_NONE) return err; - return parse_begin(p, cur, end); + return parse_begin(exec_ctx, p, cur, end); } /* parse an indexed field with index < 127 */ -static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_indexed_field(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { p->dynamic_table_update_allowed = 0; p->index = (*cur) & 0x7f; - return finish_indexed_field(p, cur + 1, end); + return finish_indexed_field(exec_ctx, p, cur + 1, end); } /* parse an indexed field with index >= 127 */ -static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_indexed_field_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { @@ -766,49 +803,53 @@ static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p, p->next_state = and_then; p->index = 0x7f; p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); + return parse_value0(exec_ctx, p, cur + 1, end); } /* finish a literal header with incremental indexing: just log, and jump to ' begin */ -static grpc_error *finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, +static grpc_error *finish_lithdr_incidx(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); GPR_ASSERT(md != NULL); /* handled in string parsing */ - grpc_error *err = - on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), - 1); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - return parse_begin(p, cur, end); + grpc_error *err = on_hdr( + exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), + take_string(p, &p->value)), + 1); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + return parse_begin(exec_ctx, p, cur, end); } /* finish a literal header with incremental indexing with no index */ -static grpc_error *finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, +static grpc_error *finish_lithdr_incidx_v(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - grpc_error *err = - on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), - take_string(p, &p->value)), - 1); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - return parse_begin(p, cur, end); + grpc_error *err = on_hdr( + exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), + take_string(p, &p->value)), + 1); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + return parse_begin(exec_ctx, p, cur, end); } /* parse a literal header with incremental indexing; index < 63 */ -static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_incidx(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_value_string_with_indexed_key, finish_lithdr_incidx}; p->dynamic_table_update_allowed = 0; p->next_state = and_then; p->index = (*cur) & 0x3f; - return parse_string_prefix(p, cur + 1, end); + return parse_string_prefix(exec_ctx, p, cur + 1, end); } /* parse a literal header with incremental indexing; index >= 63 */ -static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_incidx_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { @@ -818,11 +859,12 @@ static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p, p->next_state = and_then; p->index = 0x3f; p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); + return parse_value0(exec_ctx, p, cur + 1, end); } /* parse a literal header with incremental indexing; index = 0 */ -static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_incidx_v(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { @@ -830,48 +872,52 @@ static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p, parse_value_string_with_literal_key, finish_lithdr_incidx_v}; p->dynamic_table_update_allowed = 0; p->next_state = and_then; - return parse_string_prefix(p, cur + 1, end); + return parse_string_prefix(exec_ctx, p, cur + 1, end); } /* finish a literal header without incremental indexing */ -static grpc_error *finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, +static grpc_error *finish_lithdr_notidx(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); GPR_ASSERT(md != NULL); /* handled in string parsing */ - grpc_error *err = - on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), - 0); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - return parse_begin(p, cur, end); + grpc_error *err = on_hdr( + exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), + take_string(p, &p->value)), + 0); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + return parse_begin(exec_ctx, p, cur, end); } /* finish a literal header without incremental indexing with index = 0 */ -static grpc_error *finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, +static grpc_error *finish_lithdr_notidx_v(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - grpc_error *err = - on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), - take_string(p, &p->value)), - 0); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - return parse_begin(p, cur, end); + grpc_error *err = on_hdr( + exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), + take_string(p, &p->value)), + 0); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + return parse_begin(exec_ctx, p, cur, end); } /* parse a literal header without incremental indexing; index < 15 */ -static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_notidx(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_value_string_with_indexed_key, finish_lithdr_notidx}; p->dynamic_table_update_allowed = 0; p->next_state = and_then; p->index = (*cur) & 0xf; - return parse_string_prefix(p, cur + 1, end); + return parse_string_prefix(exec_ctx, p, cur + 1, end); } /* parse a literal header without incremental indexing; index >= 15 */ -static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_notidx_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { @@ -881,11 +927,12 @@ static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p, p->next_state = and_then; p->index = 0xf; p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); + return parse_value0(exec_ctx, p, cur + 1, end); } /* parse a literal header without incremental indexing; index == 0 */ -static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_notidx_v(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { @@ -893,48 +940,52 @@ static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p, parse_value_string_with_literal_key, finish_lithdr_notidx_v}; p->dynamic_table_update_allowed = 0; p->next_state = and_then; - return parse_string_prefix(p, cur + 1, end); + return parse_string_prefix(exec_ctx, p, cur + 1, end); } /* finish a literal header that is never indexed */ -static grpc_error *finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, +static grpc_error *finish_lithdr_nvridx(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index); GPR_ASSERT(md != NULL); /* handled in string parsing */ - grpc_error *err = - on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), - take_string(p, &p->value)), - 0); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - return parse_begin(p, cur, end); + grpc_error *err = on_hdr( + exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key), + take_string(p, &p->value)), + 0); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + return parse_begin(exec_ctx, p, cur, end); } /* finish a literal header that is never indexed with an extra value */ -static grpc_error *finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, +static grpc_error *finish_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - grpc_error *err = - on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), - take_string(p, &p->value)), - 0); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - return parse_begin(p, cur, end); + grpc_error *err = on_hdr( + exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key), + take_string(p, &p->value)), + 0); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + return parse_begin(exec_ctx, p, cur, end); } /* parse a literal header that is never indexed; index < 15 */ -static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_nvridx(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { parse_value_string_with_indexed_key, finish_lithdr_nvridx}; p->dynamic_table_update_allowed = 0; p->next_state = and_then; p->index = (*cur) & 0xf; - return parse_string_prefix(p, cur + 1, end); + return parse_string_prefix(exec_ctx, p, cur + 1, end); } /* parse a literal header that is never indexed; index >= 15 */ -static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_nvridx_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { @@ -944,11 +995,12 @@ static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p, p->next_state = and_then; p->index = 0xf; p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); + return parse_value0(exec_ctx, p, cur + 1, end); } /* parse a literal header that is never indexed; index == 0 */ -static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { @@ -956,44 +1008,47 @@ static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p, parse_value_string_with_literal_key, finish_lithdr_nvridx_v}; p->dynamic_table_update_allowed = 0; p->next_state = and_then; - return parse_string_prefix(p, cur + 1, end); + return parse_string_prefix(exec_ctx, p, cur + 1, end); } /* finish parsing a max table size change */ -static grpc_error *finish_max_tbl_size(grpc_chttp2_hpack_parser *p, +static grpc_error *finish_max_tbl_size(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (grpc_http_trace) { gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index); } grpc_error *err = grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - return parse_begin(p, cur, end); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + return parse_begin(exec_ctx, p, cur, end); } /* parse a max table size change, max size < 15 */ -static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_max_tbl_size(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (p->dynamic_table_update_allowed == 0) { return parse_error( - p, cur, end, + exec_ctx, p, cur, end, GRPC_ERROR_CREATE( "More than two max table size changes in a single frame")); } p->dynamic_table_update_allowed--; p->index = (*cur) & 0x1f; - return finish_max_tbl_size(p, cur + 1, end); + return finish_max_tbl_size(exec_ctx, p, cur + 1, end); } /* parse a max table size change, max size >= 15 */ -static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_max_tbl_size_x(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { static const grpc_chttp2_hpack_parser_state and_then[] = { finish_max_tbl_size}; if (p->dynamic_table_update_allowed == 0) { return parse_error( - p, cur, end, + exec_ctx, p, cur, end, GRPC_ERROR_CREATE( "More than two max table size changes in a single frame")); } @@ -1001,11 +1056,12 @@ static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, p->next_state = and_then; p->index = 0x1f; p->parsing.value = &p->index; - return parse_value0(p, cur + 1, end); + return parse_value0(exec_ctx, p, cur + 1, end); } /* a parse error: jam the parse state into parse_error, and return error */ -static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_error(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end, grpc_error *err) { GPR_ASSERT(err != GRPC_ERROR_NONE); if (p->last_error == GRPC_ERROR_NONE) { @@ -1015,24 +1071,27 @@ static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur, return err; } -static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p, +static grpc_error *still_parse_error(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { return GRPC_ERROR_REF(p->last_error); } -static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_illegal_op(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { GPR_ASSERT(cur != end); char *msg; gpr_asprintf(&msg, "Illegal hpack op code %d", *cur); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); - return parse_error(p, cur, end, err); + return parse_error(exec_ctx, p, cur, end, err); } /* parse the 1st byte of a varint into p->parsing.value no overflow is possible */ -static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value0(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_value0; @@ -1042,15 +1101,16 @@ static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur, *p->parsing.value += (*cur) & 0x7f; if ((*cur) & 0x80) { - return parse_value1(p, cur + 1, end); + return parse_value1(exec_ctx, p, cur + 1, end); } else { - return parse_next(p, cur + 1, end); + return parse_next(exec_ctx, p, cur + 1, end); } } /* parse the 2nd byte of a varint into p->parsing.value no overflow is possible */ -static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value1(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_value1; @@ -1060,15 +1120,16 @@ static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur, *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7; if ((*cur) & 0x80) { - return parse_value2(p, cur + 1, end); + return parse_value2(exec_ctx, p, cur + 1, end); } else { - return parse_next(p, cur + 1, end); + return parse_next(exec_ctx, p, cur + 1, end); } } /* parse the 3rd byte of a varint into p->parsing.value no overflow is possible */ -static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value2(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_value2; @@ -1078,15 +1139,16 @@ static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur, *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14; if ((*cur) & 0x80) { - return parse_value3(p, cur + 1, end); + return parse_value3(exec_ctx, p, cur + 1, end); } else { - return parse_next(p, cur + 1, end); + return parse_next(exec_ctx, p, cur + 1, end); } } /* parse the 4th byte of a varint into p->parsing.value no overflow is possible */ -static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value3(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_value3; @@ -1096,15 +1158,16 @@ static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur, *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21; if ((*cur) & 0x80) { - return parse_value4(p, cur + 1, end); + return parse_value4(exec_ctx, p, cur + 1, end); } else { - return parse_next(p, cur + 1, end); + return parse_next(exec_ctx, p, cur + 1, end); } } /* parse the 5th byte of a varint into p->parsing.value depending on the byte, we may overflow, and care must be taken */ -static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_value4(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { uint8_t c; uint32_t cur_value; @@ -1130,9 +1193,9 @@ static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur, *p->parsing.value = cur_value + add_value; if ((*cur) & 0x80) { - return parse_value5up(p, cur + 1, end); + return parse_value5up(exec_ctx, p, cur + 1, end); } else { - return parse_next(p, cur + 1, end); + return parse_next(exec_ctx, p, cur + 1, end); } error: @@ -1142,13 +1205,14 @@ error: *p->parsing.value, *cur); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); - return parse_error(p, cur, end, err); + return parse_error(exec_ctx, p, cur, end, err); } /* parse any trailing bytes in a varint: it's possible to append an arbitrary number of 0x80's and not affect the value - a zero will terminate - and anything else will overflow */ -static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_value5up(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { while (cur != end && *cur == 0x80) { ++cur; @@ -1160,7 +1224,7 @@ static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p, } if (*cur == 0) { - return parse_next(p, cur + 1, end); + return parse_next(exec_ctx, p, cur + 1, end); } char *msg; @@ -1170,11 +1234,12 @@ static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p, *p->parsing.value, *cur); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); - return parse_error(p, cur, end, err); + return parse_error(exec_ctx, p, cur, end, err); } /* parse a string prefix */ -static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_string_prefix(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (cur == end) { p->state = parse_string_prefix; @@ -1185,9 +1250,9 @@ static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p, p->huff = (*cur) >> 7; if (p->strlen == 0x7f) { p->parsing.value = &p->strlen; - return parse_value0(p, cur + 1, end); + return parse_value0(exec_ctx, p, cur + 1, end); } else { - return parse_next(p, cur + 1, end); + return parse_next(exec_ctx, p, cur + 1, end); } } @@ -1205,7 +1270,8 @@ static void append_bytes(grpc_chttp2_hpack_parser_string *str, str->length += (uint32_t)length; } -static grpc_error *append_string(grpc_chttp2_hpack_parser *p, +static grpc_error *append_string(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { grpc_chttp2_hpack_parser_string *str = p->parsing.str; uint32_t bits; @@ -1223,7 +1289,7 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p, bits = inverse_base64[*cur]; ++cur; if (bits == 255) - return parse_error(p, cur, end, + return parse_error(exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Illegal base64 character")); else if (bits == 64) goto b64_byte0; @@ -1238,7 +1304,7 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p, bits = inverse_base64[*cur]; ++cur; if (bits == 255) - return parse_error(p, cur, end, + return parse_error(exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Illegal base64 character")); else if (bits == 64) goto b64_byte1; @@ -1253,7 +1319,7 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p, bits = inverse_base64[*cur]; ++cur; if (bits == 255) - return parse_error(p, cur, end, + return parse_error(exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Illegal base64 character")); else if (bits == 64) goto b64_byte2; @@ -1268,7 +1334,7 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p, bits = inverse_base64[*cur]; ++cur; if (bits == 255) - return parse_error(p, cur, end, + return parse_error(exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Illegal base64 character")); else if (bits == 64) goto b64_byte3; @@ -1281,11 +1347,12 @@ static grpc_error *append_string(grpc_chttp2_hpack_parser *p, goto b64_byte0; } GPR_UNREACHABLE_CODE(return parse_error( - p, cur, end, GRPC_ERROR_CREATE("Should never reach here"))); + exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Should never reach here"))); } /* append a null terminator to a string */ -static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *finish_str(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { uint8_t terminator = 0; uint8_t decoded[2]; @@ -1298,7 +1365,7 @@ static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur, break; case B64_BYTE1: return parse_error( - p, cur, end, + exec_ctx, p, cur, end, GRPC_ERROR_CREATE("illegal base64 encoding")); /* illegal encoding */ case B64_BYTE2: bits = p->base64_buffer; @@ -1308,7 +1375,7 @@ static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur, bits & 0xffff); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); - return parse_error(p, cur, end, err); + return parse_error(exec_ctx, p, cur, end, err); } decoded[0] = (uint8_t)(bits >> 16); append_bytes(str, decoded, 1); @@ -1321,7 +1388,7 @@ static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur, bits & 0xff); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); - return parse_error(p, cur, end, err); + return parse_error(exec_ctx, p, cur, end, err); } decoded[0] = (uint8_t)(bits >> 16); decoded[1] = (uint8_t)(bits >> 8); @@ -1334,13 +1401,14 @@ static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur, } /* decode a nibble from a huffman encoded stream */ -static grpc_error *huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) { +static grpc_error *huff_nibble(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, uint8_t nibble) { int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble]; int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble]; if (emit != -1) { if (emit >= 0 && emit < 256) { uint8_t c = (uint8_t)emit; - grpc_error *err = append_string(p, &c, (&c) + 1); + grpc_error *err = append_string(exec_ctx, p, &c, (&c) + 1); if (err != GRPC_ERROR_NONE) return err; } else { assert(emit == 256); @@ -1351,42 +1419,45 @@ static grpc_error *huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) { } /* decode full bytes from a huffman encoded stream */ -static grpc_error *add_huff_bytes(grpc_chttp2_hpack_parser *p, +static grpc_error *add_huff_bytes(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { for (; cur != end; ++cur) { - grpc_error *err = huff_nibble(p, *cur >> 4); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - err = huff_nibble(p, *cur & 0xf); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); + grpc_error *err = huff_nibble(exec_ctx, p, *cur >> 4); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + err = huff_nibble(exec_ctx, p, *cur & 0xf); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); } return GRPC_ERROR_NONE; } /* decode some string bytes based on the current decoding mode (huffman or not) */ -static grpc_error *add_str_bytes(grpc_chttp2_hpack_parser *p, +static grpc_error *add_str_bytes(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { if (p->huff) { - return add_huff_bytes(p, cur, end); + return add_huff_bytes(exec_ctx, p, cur, end); } else { - return append_string(p, cur, end); + return append_string(exec_ctx, p, cur, end); } } /* parse a string - tries to do large chunks at a time */ -static grpc_error *parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, +static grpc_error *parse_string(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { size_t remaining = p->strlen - p->strgot; size_t given = (size_t)(end - cur); if (remaining <= given) { - grpc_error *err = add_str_bytes(p, cur, cur + remaining); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - err = finish_str(p, cur + remaining, end); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - return parse_next(p, cur + remaining, end); + grpc_error *err = add_str_bytes(exec_ctx, p, cur, cur + remaining); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + err = finish_str(exec_ctx, p, cur + remaining, end); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + return parse_next(exec_ctx, p, cur + remaining, end); } else { - grpc_error *err = add_str_bytes(p, cur, cur + given); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); + grpc_error *err = add_str_bytes(exec_ctx, p, cur, cur + given); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); GPR_ASSERT(given <= UINT32_MAX - p->strgot); p->strgot += (uint32_t)given; p->state = parse_string; @@ -1395,7 +1466,8 @@ static grpc_error *parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur, } /* begin parsing a string - performs setup, calls parse_string */ -static grpc_error *begin_parse_string(grpc_chttp2_hpack_parser *p, +static grpc_error *begin_parse_string(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end, uint8_t binary, grpc_chttp2_hpack_parser_string *str) { @@ -1404,13 +1476,14 @@ static grpc_error *begin_parse_string(grpc_chttp2_hpack_parser *p, p->parsing.str = str; p->huff_state = 0; p->binary = binary; - return parse_string(p, cur, end); + return parse_string(exec_ctx, p, cur, end); } /* parse the key string */ -static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_key_string(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - return begin_parse_string(p, cur, end, NOT_BINARY, &p->key); + return begin_parse_string(exec_ctx, p, cur, end, NOT_BINARY, &p->key); } /* check if a key represents a binary header or not */ @@ -1435,24 +1508,27 @@ static grpc_error *is_binary_indexed_header(grpc_chttp2_hpack_parser *p, } /* parse the value string */ -static grpc_error *parse_value_string(grpc_chttp2_hpack_parser *p, +static grpc_error *parse_value_string(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end, bool is_binary) { - return begin_parse_string(p, cur, end, is_binary ? B64_BYTE0 : NOT_BINARY, - &p->value); + return begin_parse_string(exec_ctx, p, cur, end, + is_binary ? B64_BYTE0 : NOT_BINARY, &p->value); } static grpc_error *parse_value_string_with_indexed_key( - grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { + grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { bool is_binary = false; grpc_error *err = is_binary_indexed_header(p, &is_binary); - if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err); - return parse_value_string(p, cur, end, is_binary); + if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err); + return parse_value_string(exec_ctx, p, cur, end, is_binary); } static grpc_error *parse_value_string_with_literal_key( - grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) { - return parse_value_string(p, cur, end, is_binary_literal_header(p)); + grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur, + const uint8_t *end) { + return parse_value_string(exec_ctx, p, cur, end, is_binary_literal_header(p)); } /* PUBLIC INTERFACE */ @@ -1484,27 +1560,36 @@ void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) { gpr_free(p->value.str); } -grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, +grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *beg, const uint8_t *end) { /* TODO(ctiller): limit the distance of end from beg, and perform multiple steps in the event of a large chunk of data to limit stack space usage when no tail call optimization is available */ - return p->state(p, beg, end); + return p->state(exec_ctx, p, beg, end); } -grpc_error *grpc_chttp2_header_parser_parse( - grpc_exec_ctx *exec_ctx, void *hpack_parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { +typedef void (*maybe_complete_func_type)(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +static const maybe_complete_func_type maybe_complete_funcs[] = { + grpc_chttp2_maybe_complete_recv_initial_metadata, + grpc_chttp2_maybe_complete_recv_trailing_metadata}; + +grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx, + void *hpack_parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last) { grpc_chttp2_hpack_parser *parser = hpack_parser; GPR_TIMER_BEGIN("grpc_chttp2_hpack_parser_parse", 0); - if (stream_parsing != NULL) { - stream_parsing->stats.incoming.header_bytes += GPR_SLICE_LENGTH(slice); + if (s != NULL) { + s->stats.incoming.header_bytes += GPR_SLICE_LENGTH(slice); } grpc_error *error = grpc_chttp2_hpack_parser_parse( - parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice)); + exec_ctx, parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice)); if (error != GRPC_ERROR_NONE) { GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0); return error; @@ -1517,20 +1602,19 @@ grpc_error *grpc_chttp2_header_parser_parse( } /* need to check for null stream: this can occur if we receive an invalid stream id on a header */ - if (stream_parsing != NULL) { + if (s != NULL) { if (parser->is_boundary) { - if (stream_parsing->header_frames_received == - GPR_ARRAY_SIZE(stream_parsing->got_metadata_on_parse)) { + if (s->header_frames_received == GPR_ARRAY_SIZE(s->metadata_buffer)) { return GRPC_ERROR_CREATE("Too many trailer frames"); } - stream_parsing - ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1; - stream_parsing->header_frames_received++; - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); + s->published_metadata[s->header_frames_received] = + GRPC_METADATA_PUBLISHED_FROM_WIRE; + maybe_complete_funcs[s->header_frames_received](exec_ctx, t, s); + s->header_frames_received++; } if (parser->is_eof) { - stream_parsing->received_close = 1; + grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false, + GRPC_ERROR_NONE); } } parser->on_header = NULL; diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h index 78eb38db5e..0290c78d5a 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_parser.h +++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h @@ -45,7 +45,8 @@ typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser; typedef grpc_error *(*grpc_chttp2_hpack_parser_state)( - grpc_chttp2_hpack_parser *p, const uint8_t *beg, const uint8_t *end); + grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *beg, + const uint8_t *end); typedef struct { char *str; @@ -55,7 +56,7 @@ typedef struct { struct grpc_chttp2_hpack_parser { /* user specified callback for each header output */ - void (*on_header)(void *user_data, grpc_mdelem *md); + void (*on_header)(grpc_exec_ctx *exec_ctx, void *user_data, grpc_mdelem *md); void *on_header_user_data; grpc_error *last_error; @@ -104,15 +105,17 @@ void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p); void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p); /* returns 1 on success, 0 on error */ -grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, +grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx, + grpc_chttp2_hpack_parser *p, const uint8_t *beg, const uint8_t *end); /* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for the transport */ -grpc_error *grpc_chttp2_header_parser_parse( - grpc_exec_ctx *exec_ctx, void *hpack_parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); +grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx, + void *hpack_parser, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + gpr_slice slice, int is_last); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H */ diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 04b788b702..01f521c360 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -53,31 +53,25 @@ #include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/transport_impl.h" -typedef struct grpc_chttp2_transport grpc_chttp2_transport; -typedef struct grpc_chttp2_stream grpc_chttp2_stream; - /* streams are kept in various linked lists depending on what things need to happen to them... this enum labels each list */ typedef enum { - GRPC_CHTTP2_LIST_ALL_STREAMS, - GRPC_CHTTP2_LIST_CHECK_READ_OPS, - GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE, GRPC_CHTTP2_LIST_WRITABLE, GRPC_CHTTP2_LIST_WRITING, - GRPC_CHTTP2_LIST_WRITTEN, - GRPC_CHTTP2_LIST_PARSING_SEEN, - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING, - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT, - /* streams waiting for the outgoing window in the writing path, they will be - * merged to the stalled list or writable list under transport lock. */ - GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT, /** streams that are waiting to start because there are too many concurrent streams on the connection */ GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY, STREAM_LIST_COUNT /* must be last */ } grpc_chttp2_stream_list_id; +typedef enum { + GRPC_CHTTP2_WRITE_STATE_IDLE, + GRPC_CHTTP2_WRITE_STATE_WRITING, + GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE, + GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER, +} grpc_chttp2_write_state; + /* deframer state for the overall http2 stream of bytes */ typedef enum { /* prefix: one entry per http2 connection prefix byte */ @@ -152,6 +146,12 @@ typedef struct grpc_chttp2_outstanding_ping { struct grpc_chttp2_outstanding_ping *prev; } grpc_chttp2_outstanding_ping; +typedef struct grpc_chttp2_write_cb { + int64_t call_at_byte; + grpc_closure *closure; + struct grpc_chttp2_write_cb *next; +} grpc_chttp2_write_cb; + /* forward declared in frame_data.h */ struct grpc_chttp2_incoming_byte_stream { grpc_byte_stream base; @@ -161,12 +161,13 @@ struct grpc_chttp2_incoming_byte_stream { grpc_chttp2_transport *transport; grpc_chttp2_stream *stream; - int is_tail; + bool is_tail; gpr_mu slice_mu; // protects slices, on_next gpr_slice_buffer slices; grpc_closure *on_next; gpr_slice *next; + uint32_t remaining_bytes; struct { grpc_closure closure; @@ -178,12 +179,68 @@ struct grpc_chttp2_incoming_byte_stream { grpc_closure finished_action; }; -typedef struct { +struct grpc_chttp2_transport { + grpc_transport base; /* must be first */ + gpr_refcount refs; + grpc_endpoint *ep; + char *peer_string; + + grpc_combiner *combiner; + + /** write execution state of the transport */ + grpc_chttp2_write_state write_state; + + /** is the transport destroying itself? */ + uint8_t destroying; + /** has the upper layer closed the transport? */ + uint8_t closed; + + /** is there a read request to the endpoint outstanding? */ + uint8_t endpoint_reading; + + /** various lists of streams */ + grpc_chttp2_stream_list lists[STREAM_LIST_COUNT]; + + /** maps stream id to grpc_chttp2_stream objects */ + grpc_chttp2_stream_map stream_map; + + grpc_closure write_action_begin_locked; + grpc_closure write_action; + grpc_closure write_action_end; + grpc_closure write_action_end_locked; + + grpc_closure read_action_begin; + grpc_closure read_action_locked; + + /** incoming read bytes */ + gpr_slice_buffer read_buffer; + + /** address to place a newly accepted stream - set and unset by + grpc_chttp2_parsing_accept_stream; used by init_stream to + publish the accepted server stream */ + grpc_chttp2_stream **accepting_stream; + + struct { + /* accept stream callback */ + void (*accept_stream)(grpc_exec_ctx *exec_ctx, void *user_data, + grpc_transport *transport, const void *server_data); + void *accept_stream_user_data; + + /** connectivity tracking */ + grpc_connectivity_state_tracker state_tracker; + } channel_callback; + + /** data to write now */ + gpr_slice_buffer outbuf; + /** hpack encoding */ + grpc_chttp2_hpack_compressor hpack_compressor; + int64_t outgoing_window; + /** is this a client? */ + uint8_t is_client; + /** data to write next write */ gpr_slice_buffer qbuf; - /** window available for us to send to peer */ - int64_t outgoing_window; /** window available to announce to peer */ int64_t announce_incoming_window; /** how much window would we like to have for incoming_window */ @@ -194,8 +251,6 @@ typedef struct { /** have we sent a goaway */ uint8_t sent_goaway; - /** is this transport a client? */ - uint8_t is_client; /** are the local settings dirty and need to be sent? */ uint8_t dirtied_local_settings; /** have local settings been sent? */ @@ -212,49 +267,14 @@ typedef struct { /** how far to lookahead in a stream? */ uint32_t stream_lookahead; - /** last received stream id */ - uint32_t last_incoming_stream_id; + /** last new stream id */ + uint32_t last_new_stream_id; /** pings awaiting responses */ grpc_chttp2_outstanding_ping pings; /** next payload for an outgoing ping */ uint64_t ping_counter; - /** concurrent stream count: updated when not parsing, - so this is a strict over-estimation on the client */ - uint32_t concurrent_stream_count; -} grpc_chttp2_transport_global; - -typedef struct { - /** data to write now */ - gpr_slice_buffer outbuf; - /** hpack encoding */ - grpc_chttp2_hpack_compressor hpack_compressor; - int64_t outgoing_window; - /** is this a client? */ - uint8_t is_client; - /** callback for when writing is done */ - grpc_closure done_cb; - /** maximum frame size */ - uint32_t max_frame_size; -} grpc_chttp2_transport_writing; - -struct grpc_chttp2_transport_parsing { - /** is this transport a client? (boolean) */ - uint8_t is_client; - - /** were settings updated? */ - uint8_t settings_updated; - /** was a settings ack received? */ - uint8_t settings_ack_received; - /** was a goaway frame received? */ - uint8_t goaway_received; - - /** initial window change */ - int64_t initial_window_update; - - /** data to write later - after parsing */ - gpr_slice_buffer qbuf; /** parser for headers */ grpc_chttp2_hpack_parser hpack_parser; /** simple one shot parsers */ @@ -267,13 +287,12 @@ struct grpc_chttp2_transport_parsing { /** parser for goaway frames */ grpc_chttp2_goaway_parser goaway_parser; + /** initial window change */ + int64_t initial_window_update; + /** window available for peer to send to us */ int64_t incoming_window; - /** next stream id available at the time of beginning parsing */ - uint32_t next_stream_id; - uint32_t last_incoming_stream_id; - /* deframing */ grpc_chttp2_deframe_transport_state deframe_state; uint8_t incoming_frame_type; @@ -284,135 +303,42 @@ struct grpc_chttp2_transport_parsing { uint32_t incoming_frame_size; uint32_t incoming_stream_id; - /* current max frame size */ - uint32_t max_frame_size; - /* active parser */ void *parser_data; - grpc_chttp2_stream_parsing *incoming_stream; + grpc_chttp2_stream *incoming_stream; grpc_error *(*parser)(grpc_exec_ctx *exec_ctx, void *parser_user_data, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, + grpc_chttp2_transport *t, grpc_chttp2_stream *s, gpr_slice slice, int is_last); - /* received settings */ - uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS]; - /* last settings that were sent */ - uint32_t last_sent_settings[GRPC_CHTTP2_NUM_SETTINGS]; - /* goaway data */ grpc_status_code goaway_error; uint32_t goaway_last_stream_index; gpr_slice goaway_text; - int64_t outgoing_window; + grpc_chttp2_write_cb *write_cb_pool; + + /* if non-NULL, close the transport with this error when writes are finished + */ + grpc_error *close_transport_on_writes_finished; }; typedef enum { - /** no writing activity allowed */ - GRPC_CHTTP2_WRITES_CORKED, - /** no writing activity */ - GRPC_CHTTP2_WRITING_INACTIVE, - /** write has been requested and scheduled against the workqueue */ - GRPC_CHTTP2_WRITE_SCHEDULED, - /** write has been initiated after being reaped from the workqueue */ - GRPC_CHTTP2_WRITING, - /** write has been initiated, AND another write needs to be started once it's - done */ - GRPC_CHTTP2_WRITING_STALE_WITH_POLLER, - GRPC_CHTTP2_WRITING_STALE_NO_POLLER, -} grpc_chttp2_write_state; - -struct grpc_chttp2_transport { - grpc_transport base; /* must be first */ - gpr_refcount refs; - grpc_endpoint *ep; - char *peer_string; - - /** when this drops to zero it's safe to shutdown the endpoint */ - gpr_refcount shutdown_ep_refs; - - struct { - grpc_combiner *combiner; - - /** is a thread currently in the global lock */ - bool global_active; - /** is a thread currently parsing */ - bool parsing_active; - /** write execution state of the transport */ - grpc_chttp2_write_state write_state; - /** has a check_read_ops been scheduled */ - bool check_read_ops_scheduled; - } executor; - - /** is the transport destroying itself? */ - uint8_t destroying; - /** has the upper layer closed the transport? */ - uint8_t closed; + GRPC_METADATA_NOT_PUBLISHED, + GRPC_METADATA_SYNTHESIZED_FROM_FAKE, + GRPC_METADATA_PUBLISHED_FROM_WIRE, + GPRC_METADATA_PUBLISHED_AT_CLOSE +} grpc_published_metadata_method; - /** is there a read request to the endpoint outstanding? */ - uint8_t endpoint_reading; - - /** various lists of streams */ - grpc_chttp2_stream_list lists[STREAM_LIST_COUNT]; - - /** global state for reading/writing */ - grpc_chttp2_transport_global global; - /** state only accessible by the chain of execution that - set writing_state >= GRPC_WRITING, and only by the writing closure - chain. */ - grpc_chttp2_transport_writing writing; - /** state only accessible by the chain of execution that - set parsing_active=1 */ - grpc_chttp2_transport_parsing parsing; - - /** maps stream id to grpc_chttp2_stream objects; - owned by the parsing thread when parsing */ - grpc_chttp2_stream_map parsing_stream_map; - - /** streams created by the client (possibly during parsing); - merged with parsing_stream_map during unlock when no - parsing is occurring */ - grpc_chttp2_stream_map new_stream_map; - - /** closure to execute writing */ - grpc_closure writing_action; - /** closure to start reading from the endpoint */ - grpc_closure reading_action; - grpc_closure reading_action_locked; - grpc_closure post_parse_locked; - /** closure to actually do parsing */ - grpc_closure parsing_action; - /** closure to initiate writing */ - grpc_closure initiate_writing; - /** closure to finish writing */ - grpc_closure terminate_writing; - /** closure to flush read state up the stack */ - grpc_closure initiate_read_flush_locked; - - /** incoming read bytes */ - gpr_slice_buffer read_buffer; - - /** address to place a newly accepted stream - set and unset by - grpc_chttp2_parsing_accept_stream; used by init_stream to - publish the accepted server stream */ - grpc_chttp2_stream **accepting_stream; - - struct { - /* accept stream callback */ - void (*accept_stream)(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_transport *transport, const void *server_data); - void *accept_stream_user_data; +struct grpc_chttp2_stream { + grpc_chttp2_transport *t; + grpc_stream_refcount *refcount; - /** connectivity tracking */ - grpc_connectivity_state_tracker state_tracker; - } channel_callback; + grpc_closure destroy_stream; + void *destroy_stream_arg; - /** Transport op to be applied post-parsing */ - grpc_transport_op *post_parsing_op; -}; + grpc_chttp2_stream_link links[STREAM_LIST_COUNT]; + uint8_t included[STREAM_LIST_COUNT]; -typedef struct { /** HTTP2 stream id for this stream, or zero if one has not been assigned */ uint32_t id; @@ -422,20 +348,22 @@ typedef struct { As the upper layer offers more bytes, this value increases. As bytes are read, this value decreases. */ uint32_t max_recv_bytes; - /** The number of bytes the upper layer has offered to read but we have - not yet announced to HTTP2 flow control. - As the upper layers offer to read more bytes, this value increases. - As we advertise incoming flow control window, this value decreases. */ - uint32_t unannounced_incoming_window_for_parse; - uint32_t unannounced_incoming_window_for_writing; /** things the upper layers would like to send */ grpc_metadata_batch *send_initial_metadata; grpc_closure *send_initial_metadata_finished; - grpc_byte_stream *send_message; - grpc_closure *send_message_finished; grpc_metadata_batch *send_trailing_metadata; grpc_closure *send_trailing_metadata_finished; + grpc_byte_stream *fetching_send_message; + uint32_t fetched_send_message_length; + gpr_slice fetching_slice; + int64_t next_message_end_offset; + int64_t flow_controlled_bytes_written; + bool complete_fetch_covered_by_poller; + grpc_closure complete_fetch; + grpc_closure complete_fetch_locked; + grpc_closure *fetching_send_message_finished; + grpc_metadata_batch *recv_initial_metadata; grpc_closure *recv_initial_metadata_ready; grpc_byte_stream **recv_message; @@ -455,95 +383,44 @@ typedef struct { bool read_closed; /** Are all published incoming byte streams closed. */ bool all_incoming_byte_streams_finished; - /** Is this stream in the stream map. */ - bool in_stream_map; /** Has this stream seen an error. If true, then pending incoming frames can be thrown away. */ bool seen_error; - bool exceeded_metadata_size; /** the error that resulted in this stream being read-closed */ grpc_error *read_closed_error; /** the error that resulted in this stream being write-closed */ grpc_error *write_closed_error; - bool published_initial_metadata; - bool published_trailing_metadata; + grpc_published_metadata_method published_metadata[2]; bool final_metadata_requested; - grpc_chttp2_incoming_metadata_buffer received_initial_metadata; - grpc_chttp2_incoming_metadata_buffer received_trailing_metadata; + grpc_chttp2_incoming_metadata_buffer metadata_buffer[2]; grpc_chttp2_incoming_frame_queue incoming_frames; gpr_timespec deadline; -} grpc_chttp2_stream_global; - -typedef struct { - /** HTTP2 stream id for this stream, or zero if one has not been assigned */ - uint32_t id; - uint8_t fetching; - bool sent_initial_metadata; - uint8_t sent_message; - uint8_t sent_trailing_metadata; - uint8_t read_closed; - /** send this initial metadata */ - grpc_metadata_batch *send_initial_metadata; - grpc_byte_stream *send_message; - grpc_metadata_batch *send_trailing_metadata; - int64_t outgoing_window; - /** how much window should we announce? */ - uint32_t announce_window; - gpr_slice_buffer flow_controlled_buffer; - gpr_slice fetching_slice; - size_t stream_fetched; - grpc_closure finished_fetch; - /** stats gathered during the write */ - grpc_transport_one_way_stats stats; -} grpc_chttp2_stream_writing; -struct grpc_chttp2_stream_parsing { /** saw some stream level error */ grpc_error *forced_close_error; - /** HTTP2 stream id for this stream, or zero if one has not been assigned */ - uint32_t id; - /** has this stream received a close */ - uint8_t received_close; /** how many header frames have we received? */ uint8_t header_frames_received; - /** which metadata did we get (on this parse) */ - uint8_t got_metadata_on_parse[2]; - /** should we raise the seen_error flag in transport_global */ - bool seen_error; - bool exceeded_metadata_size; /** window available for peer to send to us */ int64_t incoming_window; /** parsing state for data frames */ grpc_chttp2_data_parser data_parser; - /** amount of window given */ - int64_t outgoing_window; /** number of bytes received - reset at end of parse thread execution */ int64_t received_bytes; - /** stats gathered during the parse */ - grpc_transport_stream_stats stats; - /** incoming metadata */ - grpc_chttp2_incoming_metadata_buffer metadata_buffer[2]; -}; - -struct grpc_chttp2_stream { - grpc_chttp2_transport *t; - grpc_stream_refcount *refcount; - grpc_chttp2_stream_global global; - grpc_chttp2_stream_writing writing; - grpc_chttp2_stream_parsing parsing; - - grpc_closure init_stream; - grpc_closure destroy_stream; - void *destroy_stream_arg; + bool sent_initial_metadata; + bool sent_trailing_metadata; + /** how much window should we announce? */ + uint32_t announce_window; + gpr_slice_buffer flow_controlled_buffer; - grpc_chttp2_stream_link links[STREAM_LIST_COUNT]; - uint8_t included[STREAM_LIST_COUNT]; + grpc_chttp2_write_cb *on_write_finished_cbs; + grpc_chttp2_write_cb *finish_after_write; + size_t sending_bytes; }; /** Transport writing call flow: @@ -559,162 +436,71 @@ struct grpc_chttp2_stream { The actual call chain is documented in the implementation of this function. */ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, + grpc_chttp2_transport *t, bool covered_by_poller, const char *reason); /** Someone is unlocking the transport mutex: check to see if writes - are required, and schedule them if so */ -int grpc_chttp2_unlocking_check_writes(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *global, - grpc_chttp2_transport_writing *writing); -void grpc_chttp2_perform_writes( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, - grpc_endpoint *endpoint); -void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, - void *transport_writing, grpc_error *error); -void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *global, - grpc_chttp2_transport_writing *writing); - -void grpc_chttp2_prepare_to_read(grpc_chttp2_transport_global *global, - grpc_chttp2_transport_parsing *parsing); + are required, and frame them if so */ +bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); +void grpc_chttp2_end_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_error *error); + /** Process one slice of incoming data; return 1 if the connection is still viable after reading, or 0 if the connection should be torn down */ -grpc_error *grpc_chttp2_perform_read( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice); -void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *global, - grpc_chttp2_transport_parsing *parsing); - -bool grpc_chttp2_list_add_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); +grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, gpr_slice slice); + +bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); /** Get a writable stream returns non-zero if there was a stream available */ -int grpc_chttp2_list_pop_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing); +int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); bool grpc_chttp2_list_remove_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) GRPC_MUST_USE_RESULT; - -void grpc_chttp2_list_add_writing_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing); -int grpc_chttp2_list_have_writing_streams( - grpc_chttp2_transport_writing *transport_writing); -int grpc_chttp2_list_pop_writing_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing **stream_writing); - -void grpc_chttp2_list_add_written_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing); -int grpc_chttp2_list_pop_written_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing); - -void grpc_chttp2_list_add_parsing_seen_stream( - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing); -int grpc_chttp2_list_pop_parsing_seen_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_parsing **stream_parsing); - -void grpc_chttp2_list_add_waiting_for_concurrency( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_waiting_for_concurrency( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); - -void grpc_chttp2_list_add_check_read_ops( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -bool grpc_chttp2_list_remove_check_read_ops( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_check_read_ops( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); - -void grpc_chttp2_list_add_writing_stalled_by_transport( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing); -bool grpc_chttp2_list_flush_writing_stalled_by_transport( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing); - -void grpc_chttp2_list_add_stalled_by_transport( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing); -int grpc_chttp2_list_pop_stalled_by_transport( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); -void grpc_chttp2_list_remove_stalled_by_transport( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); - -void grpc_chttp2_list_add_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -void grpc_chttp2_list_remove_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_parsing **stream_parsing); - -void grpc_chttp2_list_add_closed_waiting_for_parsing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_closed_waiting_for_parsing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); - -void grpc_chttp2_list_add_closed_waiting_for_writing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_closed_waiting_for_writing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global); - -grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream( - grpc_chttp2_transport_parsing *transport_parsing, uint32_t id); -grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - uint32_t id); - -void grpc_chttp2_add_incoming_goaway( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - uint32_t goaway_error, gpr_slice goaway_text); - -void grpc_chttp2_register_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream *s); -/* returns 1 if this is the last stream, 0 otherwise */ -int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT; -int grpc_chttp2_has_streams(grpc_chttp2_transport *t); -void grpc_chttp2_for_all_streams( - grpc_chttp2_transport_global *transport_global, void *user_data, - void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data, - grpc_chttp2_stream_global *stream_global)); - -void grpc_chttp2_parsing_become_skip_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); - -void grpc_chttp2_complete_closure_step( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure, - grpc_error *error); + grpc_chttp2_transport *t, grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT; + +bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t); +int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); + +void grpc_chttp2_list_add_written_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +int grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); + +void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); + +void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream **s); +void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream *s); + +grpc_chttp2_stream *grpc_chttp2_parsing_lookup_stream(grpc_chttp2_transport *t, + uint32_t id); +grpc_chttp2_stream *grpc_chttp2_parsing_accept_stream(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + uint32_t id); + +void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + uint32_t goaway_error, + gpr_slice goaway_text); + +void grpc_chttp2_parsing_become_skip_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); + +void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + grpc_closure **pclosure, + grpc_error *error, const char *desc); #define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" #define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \ @@ -805,57 +591,83 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase, const char *var2, int is_client, uint32_t stream_id, int64_t val1, int64_t val2); -void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream, +void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_stream *stream, grpc_status_code status, gpr_slice *details); -void grpc_chttp2_mark_stream_closed( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes, - grpc_error *error); +void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, int close_reads, + int close_writes, grpc_error *error); void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global); + grpc_chttp2_transport *t); #ifdef GRPC_STREAM_REFCOUNT_DEBUG -#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \ - grpc_chttp2_stream_ref(stream_global, reason) -#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \ - grpc_chttp2_stream_unref(exec_ctx, stream_global, reason) -void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global, - const char *reason); -void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global, +#define GRPC_CHTTP2_STREAM_REF(stream, reason) \ + grpc_chttp2_stream_ref(stream, reason) +#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream, reason) \ + grpc_chttp2_stream_unref(exec_ctx, stream, reason) +void grpc_chttp2_stream_ref(grpc_chttp2_stream *s, const char *reason); +void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s, const char *reason); #else -#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \ - grpc_chttp2_stream_ref(stream_global) -#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \ - grpc_chttp2_stream_unref(exec_ctx, stream_global) -void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global); -void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, - grpc_chttp2_stream_global *stream_global); +#define GRPC_CHTTP2_STREAM_REF(stream, reason) grpc_chttp2_stream_ref(stream) +#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream, reason) \ + grpc_chttp2_stream_unref(exec_ctx, stream) +void grpc_chttp2_stream_ref(grpc_chttp2_stream *s); +void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s); +#endif + +//#define GRPC_CHTTP2_REFCOUNTING_DEBUG 1 +#ifdef GRPC_CHTTP2_REFCOUNTING_DEBUG +#define GRPC_CHTTP2_REF_TRANSPORT(t, r) \ + grpc_chttp2_ref_transport(t, r, __FILE__, __LINE__) +#define GRPC_CHTTP2_UNREF_TRANSPORT(cl, t, r) \ + grpc_chttp2_unref_transport(cl, t, r, __FILE__, __LINE__) +void grpc_chttp2_unref_transport(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, const char *reason, + const char *file, int line); +void grpc_chttp2_ref_transport(grpc_chttp2_transport *t, const char *reason, + const char *file, int line); +#else +#define GRPC_CHTTP2_REF_TRANSPORT(t, r) grpc_chttp2_ref_transport(t) +#define GRPC_CHTTP2_UNREF_TRANSPORT(cl, t, r) grpc_chttp2_unref_transport(cl, t) +void grpc_chttp2_unref_transport(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); +void grpc_chttp2_ref_transport(grpc_chttp2_transport *t); #endif grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size, - uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue); + grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, + uint32_t frame_size, uint32_t flags); void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, gpr_slice slice); void grpc_chttp2_incoming_byte_stream_finished( grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, - grpc_error *error, int from_parsing_thread); + grpc_error *error); -void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_parsing *parsing, +void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, const uint8_t *opaque_8bytes); /** add a ref to the stream and add it to the writable list; ref will be dropped in writing.c */ void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global, - bool covered_by_poller, const char *reason); + grpc_chttp2_transport *t, + grpc_chttp2_stream *s, bool covered_by_poller, + const char *reason); + +void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, grpc_chttp2_stream *s, + grpc_error *due_to_error); + +void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s); +void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s); #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */ diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c index 0e6d579ba9..8005350ae7 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.c +++ b/src/core/ext/transport/chttp2/transport/parsing.c @@ -45,227 +45,34 @@ #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/timeout_encoding.h" -#define TRANSPORT_FROM_PARSING(tp) \ - ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \ - parsing))) - -static grpc_error *init_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static grpc_error *init_header_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_continuation); -static grpc_error *init_data_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static grpc_error *init_rst_stream_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static grpc_error *init_settings_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static grpc_error *init_window_update_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static grpc_error *init_ping_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static grpc_error *init_goaway_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); -static grpc_error *init_skip_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_header); - -static grpc_error *parse_frame_slice( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice, int is_last); - -void grpc_chttp2_prepare_to_read( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing) { - grpc_chttp2_stream_global *stream_global; - grpc_chttp2_stream_parsing *stream_parsing; - - GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0); - - transport_parsing->next_stream_id = transport_global->next_stream_id; - memcpy(transport_parsing->last_sent_settings, - transport_global->settings[GRPC_SENT_SETTINGS], - sizeof(transport_parsing->last_sent_settings)); - transport_parsing->max_frame_size = - transport_global->settings[GRPC_ACKED_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]; - - /* update the parsing view of incoming window */ - while (grpc_chttp2_list_pop_unannounced_incoming_window_available( - transport_global, transport_parsing, &stream_global, &stream_parsing)) { - GRPC_CHTTP2_FLOW_MOVE_STREAM("parse", transport_parsing, stream_parsing, - incoming_window, stream_global, - unannounced_incoming_window_for_parse); - } - - GPR_TIMER_END("grpc_chttp2_prepare_to_read", 0); -} - -void grpc_chttp2_publish_reads( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing) { - grpc_chttp2_stream_global *stream_global; - grpc_chttp2_stream_parsing *stream_parsing; - int was_zero; - int is_zero; - - /* transport_parsing->last_incoming_stream_id is used as - last-grpc_chttp2_stream-id when - sending GOAWAY frame. - https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8 - says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream - ID. So, - since we don't have server pushed streams, client should send - GOAWAY last-grpc_chttp2_stream-id=0 in this case. */ - if (!transport_parsing->is_client) { - transport_global->last_incoming_stream_id = - transport_parsing->last_incoming_stream_id; - } - - /* update global settings */ - if (transport_parsing->settings_updated) { - memcpy(transport_global->settings[GRPC_PEER_SETTINGS], - transport_parsing->settings, sizeof(transport_parsing->settings)); - transport_parsing->settings_updated = 0; - } - - /* update settings based on ack if received */ - if (transport_parsing->settings_ack_received) { - memcpy(transport_global->settings[GRPC_ACKED_SETTINGS], - transport_global->settings[GRPC_SENT_SETTINGS], - GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); - transport_parsing->settings_ack_received = 0; - transport_global->sent_local_settings = 0; - } - - /* move goaway to the global state if we received one (it will be - published later */ - if (transport_parsing->goaway_received) { - grpc_chttp2_add_incoming_goaway(exec_ctx, transport_global, - (uint32_t)transport_parsing->goaway_error, - transport_parsing->goaway_text); - transport_parsing->goaway_text = gpr_empty_slice(); - transport_parsing->goaway_received = 0; - } - - /* propagate flow control tokens to global state */ - was_zero = transport_global->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window, - transport_parsing, outgoing_window); - is_zero = transport_global->outgoing_window <= 0; - if (was_zero && !is_zero) { - grpc_chttp2_initiate_write(exec_ctx, transport_global, false, - "new_global_flow_control"); - } - - if (transport_parsing->incoming_window < - transport_global->connection_window_target * 3 / 4) { - int64_t announce_bytes = transport_global->connection_window_target - - transport_parsing->incoming_window; - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global, - announce_incoming_window, announce_bytes); - GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing, - incoming_window, announce_bytes); - grpc_chttp2_initiate_write(exec_ctx, transport_global, false, - "global incoming window"); - } - - /* for each stream that saw an update, fixup global state */ - while (grpc_chttp2_list_pop_parsing_seen_stream( - transport_global, transport_parsing, &stream_global, &stream_parsing)) { - if (stream_parsing->seen_error) { - stream_global->seen_error = true; - stream_global->exceeded_metadata_size = - stream_parsing->exceeded_metadata_size; - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); - } - - /* flush stats to global stream state */ - grpc_transport_move_stats(&stream_parsing->stats, &stream_global->stats); - - /* update outgoing flow control window */ - was_zero = stream_global->outgoing_window <= 0; - GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global, - outgoing_window, stream_parsing, - outgoing_window); - is_zero = stream_global->outgoing_window <= 0; - if (was_zero && !is_zero) { - grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, - false, "stream.read_flow_control"); - } - - stream_global->max_recv_bytes -= (uint32_t)GPR_MIN( - stream_global->max_recv_bytes, stream_parsing->received_bytes); - stream_parsing->received_bytes = 0; - - /* publish incoming stream ops */ - if (stream_global->incoming_frames.tail != NULL) { - stream_global->incoming_frames.tail->is_tail = 0; - } - if (stream_parsing->data_parser.incoming_frames.head != NULL) { - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); - } - grpc_chttp2_incoming_frame_queue_merge( - &stream_global->incoming_frames, - &stream_parsing->data_parser.incoming_frames); - if (stream_global->incoming_frames.tail != NULL) { - stream_global->incoming_frames.tail->is_tail = 1; - } - - if (!stream_global->published_initial_metadata && - stream_parsing->got_metadata_on_parse[0]) { - stream_parsing->got_metadata_on_parse[0] = 0; - stream_global->published_initial_metadata = 1; - GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, - stream_parsing->metadata_buffer[0], - stream_global->received_initial_metadata); - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); - } - if (!stream_global->published_trailing_metadata && - stream_parsing->got_metadata_on_parse[1]) { - stream_parsing->got_metadata_on_parse[1] = 0; - stream_global->published_trailing_metadata = 1; - GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, - stream_parsing->metadata_buffer[1], - stream_global->received_trailing_metadata); - grpc_chttp2_list_add_check_read_ops(exec_ctx, transport_global, - stream_global); - } - - if (stream_parsing->forced_close_error != GRPC_ERROR_NONE) { - intptr_t reason; - bool has_reason = grpc_error_get_int(stream_parsing->forced_close_error, - GRPC_ERROR_INT_HTTP2_ERROR, &reason); - if (has_reason && reason != GRPC_CHTTP2_NO_ERROR) { - grpc_status_code status_code = - has_reason - ? grpc_chttp2_http2_error_to_grpc_status( - (grpc_chttp2_error_code)reason, stream_global->deadline) - : GRPC_STATUS_INTERNAL; - const char *status_details = - grpc_error_string(stream_parsing->forced_close_error); - gpr_slice slice_details = gpr_slice_from_copied_string(status_details); - grpc_error_free_string(status_details); - grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, - status_code, &slice_details); - } - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, - 1, 1, stream_parsing->forced_close_error); - } - - if (stream_parsing->received_close) { - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, - 1, 0, GRPC_ERROR_NONE); - } - } -} - -grpc_error *grpc_chttp2_perform_read( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice) { +static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); +static grpc_error *init_header_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + int is_continuation); +static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); +static grpc_error *init_rst_stream_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); +static grpc_error *init_settings_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); +static grpc_error *init_window_update_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); +static grpc_error *init_ping_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); +static grpc_error *init_goaway_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t); +static grpc_error *init_skip_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + int is_header); + +static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, gpr_slice slice, + int is_last); + +grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + gpr_slice slice) { uint8_t *beg = GPR_SLICE_START_PTR(slice); uint8_t *end = GPR_SLICE_END_PTR(slice); uint8_t *cur = beg; @@ -273,7 +80,7 @@ grpc_error *grpc_chttp2_perform_read( if (cur == end) return GRPC_ERROR_NONE; - switch (transport_parsing->deframe_state) { + switch (t->deframe_state) { case GRPC_DTS_CLIENT_PREFIX_0: case GRPC_DTS_CLIENT_PREFIX_1: case GRPC_DTS_CLIENT_PREFIX_2: @@ -298,25 +105,22 @@ grpc_error *grpc_chttp2_perform_read( case GRPC_DTS_CLIENT_PREFIX_21: case GRPC_DTS_CLIENT_PREFIX_22: case GRPC_DTS_CLIENT_PREFIX_23: - while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) { - if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing - ->deframe_state]) { + while (cur != end && t->deframe_state != GRPC_DTS_FH_0) { + if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state]) { char *msg; gpr_asprintf( &msg, "Connect string mismatch: expected '%c' (%d) got '%c' (%d) " "at byte %d", - GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing - ->deframe_state], - (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING - [transport_parsing->deframe_state], - *cur, (int)*cur, transport_parsing->deframe_state); + GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state], + (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state], + *cur, (int)*cur, t->deframe_state); err = GRPC_ERROR_CREATE(msg); gpr_free(msg); return err; } ++cur; - ++transport_parsing->deframe_state; + ++t->deframe_state; } if (cur == end) { return GRPC_ERROR_NONE; @@ -325,100 +129,95 @@ grpc_error *grpc_chttp2_perform_read( dts_fh_0: case GRPC_DTS_FH_0: GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16; + t->incoming_frame_size = ((uint32_t)*cur) << 16; if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_1; + t->deframe_state = GRPC_DTS_FH_1; return GRPC_ERROR_NONE; } /* fallthrough */ case GRPC_DTS_FH_1: GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8; + t->incoming_frame_size |= ((uint32_t)*cur) << 8; if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_2; + t->deframe_state = GRPC_DTS_FH_2; return GRPC_ERROR_NONE; } /* fallthrough */ case GRPC_DTS_FH_2: GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_size |= *cur; + t->incoming_frame_size |= *cur; if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_3; + t->deframe_state = GRPC_DTS_FH_3; return GRPC_ERROR_NONE; } /* fallthrough */ case GRPC_DTS_FH_3: GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_type = *cur; + t->incoming_frame_type = *cur; if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_4; + t->deframe_state = GRPC_DTS_FH_4; return GRPC_ERROR_NONE; } /* fallthrough */ case GRPC_DTS_FH_4: GPR_ASSERT(cur < end); - transport_parsing->incoming_frame_flags = *cur; + t->incoming_frame_flags = *cur; if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_5; + t->deframe_state = GRPC_DTS_FH_5; return GRPC_ERROR_NONE; } /* fallthrough */ case GRPC_DTS_FH_5: GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24; + t->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24; if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_6; + t->deframe_state = GRPC_DTS_FH_6; return GRPC_ERROR_NONE; } /* fallthrough */ case GRPC_DTS_FH_6: GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16; + t->incoming_stream_id |= ((uint32_t)*cur) << 16; if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_7; + t->deframe_state = GRPC_DTS_FH_7; return GRPC_ERROR_NONE; } /* fallthrough */ case GRPC_DTS_FH_7: GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8; + t->incoming_stream_id |= ((uint32_t)*cur) << 8; if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_8; + t->deframe_state = GRPC_DTS_FH_8; return GRPC_ERROR_NONE; } /* fallthrough */ case GRPC_DTS_FH_8: GPR_ASSERT(cur < end); - transport_parsing->incoming_stream_id |= ((uint32_t)*cur); - transport_parsing->deframe_state = GRPC_DTS_FRAME; - err = init_frame_parser(exec_ctx, transport_parsing); + t->incoming_stream_id |= ((uint32_t)*cur); + t->deframe_state = GRPC_DTS_FRAME; + err = init_frame_parser(exec_ctx, t); if (err != GRPC_ERROR_NONE) { return err; } - if (transport_parsing->incoming_stream_id != 0 && - transport_parsing->incoming_stream_id > - transport_parsing->last_incoming_stream_id) { - transport_parsing->last_incoming_stream_id = - transport_parsing->incoming_stream_id; - } - if (transport_parsing->incoming_frame_size == 0) { - err = parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(), - 1); + if (t->incoming_frame_size == 0) { + err = parse_frame_slice(exec_ctx, t, gpr_empty_slice(), 1); if (err != GRPC_ERROR_NONE) { return err; } - transport_parsing->incoming_stream = NULL; + t->incoming_stream = NULL; if (++cur == end) { - transport_parsing->deframe_state = GRPC_DTS_FH_0; + t->deframe_state = GRPC_DTS_FH_0; return GRPC_ERROR_NONE; } goto dts_fh_0; /* loop */ - } else if (transport_parsing->incoming_frame_size > - transport_parsing->max_frame_size) { + } else if (t->incoming_frame_size > + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]) { char *msg; gpr_asprintf(&msg, "Frame size %d is larger than max frame size %d", - transport_parsing->incoming_frame_size, - transport_parsing->max_frame_size); + t->incoming_frame_size, + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]); err = GRPC_ERROR_CREATE(msg); gpr_free(msg); return err; @@ -429,41 +228,39 @@ grpc_error *grpc_chttp2_perform_read( /* fallthrough */ case GRPC_DTS_FRAME: GPR_ASSERT(cur < end); - if ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) { - err = parse_frame_slice(exec_ctx, transport_parsing, + if ((uint32_t)(end - cur) == t->incoming_frame_size) { + err = parse_frame_slice(exec_ctx, t, gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), (size_t)(end - beg)), 1); if (err != GRPC_ERROR_NONE) { return err; } - transport_parsing->deframe_state = GRPC_DTS_FH_0; - transport_parsing->incoming_stream = NULL; + t->deframe_state = GRPC_DTS_FH_0; + t->incoming_stream = NULL; return GRPC_ERROR_NONE; - } else if ((uint32_t)(end - cur) > - transport_parsing->incoming_frame_size) { + } else if ((uint32_t)(end - cur) > t->incoming_frame_size) { size_t cur_offset = (size_t)(cur - beg); err = parse_frame_slice( - exec_ctx, transport_parsing, - gpr_slice_sub_no_ref( - slice, cur_offset, - cur_offset + transport_parsing->incoming_frame_size), + exec_ctx, t, + gpr_slice_sub_no_ref(slice, cur_offset, + cur_offset + t->incoming_frame_size), 1); if (err != GRPC_ERROR_NONE) { return err; } - cur += transport_parsing->incoming_frame_size; - transport_parsing->incoming_stream = NULL; + cur += t->incoming_frame_size; + t->incoming_stream = NULL; goto dts_fh_0; /* loop */ } else { - err = parse_frame_slice(exec_ctx, transport_parsing, + err = parse_frame_slice(exec_ctx, t, gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), (size_t)(end - beg)), 0); if (err != GRPC_ERROR_NONE) { return err; } - transport_parsing->incoming_frame_size -= (uint32_t)(end - cur); + t->incoming_frame_size -= (uint32_t)(end - cur); return GRPC_ERROR_NONE; } GPR_UNREACHABLE_CODE(return 0); @@ -472,175 +269,172 @@ grpc_error *grpc_chttp2_perform_read( GPR_UNREACHABLE_CODE(return 0); } -static grpc_error *init_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - if (transport_parsing->is_first_frame && - transport_parsing->incoming_frame_type != GRPC_CHTTP2_FRAME_SETTINGS) { +static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + if (t->is_first_frame && + t->incoming_frame_type != GRPC_CHTTP2_FRAME_SETTINGS) { char *msg; gpr_asprintf( &msg, "Expected SETTINGS frame as the first frame, got frame type %d", - transport_parsing->incoming_frame_type); + t->incoming_frame_type); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); return err; } - transport_parsing->is_first_frame = false; - if (transport_parsing->expect_continuation_stream_id != 0) { - if (transport_parsing->incoming_frame_type != - GRPC_CHTTP2_FRAME_CONTINUATION) { + t->is_first_frame = false; + if (t->expect_continuation_stream_id != 0) { + if (t->incoming_frame_type != GRPC_CHTTP2_FRAME_CONTINUATION) { char *msg; gpr_asprintf(&msg, "Expected CONTINUATION frame, got frame type %02x", - transport_parsing->incoming_frame_type); + t->incoming_frame_type); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); return err; } - if (transport_parsing->expect_continuation_stream_id != - transport_parsing->incoming_stream_id) { + if (t->expect_continuation_stream_id != t->incoming_stream_id) { char *msg; gpr_asprintf( &msg, "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got " "grpc_chttp2_stream %08x", - transport_parsing->expect_continuation_stream_id, - transport_parsing->incoming_stream_id); + t->expect_continuation_stream_id, t->incoming_stream_id); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); return err; } - return init_header_frame_parser(exec_ctx, transport_parsing, 1); + return init_header_frame_parser(exec_ctx, t, 1); } - switch (transport_parsing->incoming_frame_type) { + switch (t->incoming_frame_type) { case GRPC_CHTTP2_FRAME_DATA: - return init_data_frame_parser(exec_ctx, transport_parsing); + return init_data_frame_parser(exec_ctx, t); case GRPC_CHTTP2_FRAME_HEADER: - return init_header_frame_parser(exec_ctx, transport_parsing, 0); + return init_header_frame_parser(exec_ctx, t, 0); case GRPC_CHTTP2_FRAME_CONTINUATION: return GRPC_ERROR_CREATE("Unexpected CONTINUATION frame"); case GRPC_CHTTP2_FRAME_RST_STREAM: - return init_rst_stream_parser(exec_ctx, transport_parsing); + return init_rst_stream_parser(exec_ctx, t); case GRPC_CHTTP2_FRAME_SETTINGS: - return init_settings_frame_parser(exec_ctx, transport_parsing); + return init_settings_frame_parser(exec_ctx, t); case GRPC_CHTTP2_FRAME_WINDOW_UPDATE: - return init_window_update_frame_parser(exec_ctx, transport_parsing); + return init_window_update_frame_parser(exec_ctx, t); case GRPC_CHTTP2_FRAME_PING: - return init_ping_parser(exec_ctx, transport_parsing); + return init_ping_parser(exec_ctx, t); case GRPC_CHTTP2_FRAME_GOAWAY: - return init_goaway_parser(exec_ctx, transport_parsing); + return init_goaway_parser(exec_ctx, t); default: if (grpc_http_trace) { - gpr_log(GPR_ERROR, "Unknown frame type %02x", - transport_parsing->incoming_frame_type); + gpr_log(GPR_ERROR, "Unknown frame type %02x", t->incoming_frame_type); } - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); + return init_skip_frame_parser(exec_ctx, t, 0); } } static grpc_error *skip_parser(grpc_exec_ctx *exec_ctx, void *parser, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing, + grpc_chttp2_transport *t, grpc_chttp2_stream *s, gpr_slice slice, int is_last) { return GRPC_ERROR_NONE; } -static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); } +static void skip_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem *md) { + GRPC_MDELEM_UNREF(md); +} -static grpc_error *init_skip_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_header) { +static grpc_error *init_skip_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + int is_header) { if (is_header) { - uint8_t is_eoh = transport_parsing->expect_continuation_stream_id != 0; - transport_parsing->parser = grpc_chttp2_header_parser_parse; - transport_parsing->parser_data = &transport_parsing->hpack_parser; - transport_parsing->hpack_parser.on_header = skip_header; - transport_parsing->hpack_parser.on_header_user_data = NULL; - transport_parsing->hpack_parser.is_boundary = is_eoh; - transport_parsing->hpack_parser.is_eof = - (uint8_t)(is_eoh ? transport_parsing->header_eof : 0); + uint8_t is_eoh = t->expect_continuation_stream_id != 0; + t->parser = grpc_chttp2_header_parser_parse; + t->parser_data = &t->hpack_parser; + t->hpack_parser.on_header = skip_header; + t->hpack_parser.on_header_user_data = NULL; + t->hpack_parser.is_boundary = is_eoh; + t->hpack_parser.is_eof = (uint8_t)(is_eoh ? t->header_eof : 0); } else { - transport_parsing->parser = skip_parser; + t->parser = skip_parser; } return GRPC_ERROR_NONE; } -void grpc_chttp2_parsing_become_skip_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - init_skip_frame_parser( - exec_ctx, transport_parsing, - transport_parsing->parser == grpc_chttp2_header_parser_parse); +void grpc_chttp2_parsing_become_skip_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + init_skip_frame_parser(exec_ctx, t, + t->parser == grpc_chttp2_header_parser_parse); } -static grpc_error *update_incoming_window( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing) { - uint32_t incoming_frame_size = transport_parsing->incoming_frame_size; - if (incoming_frame_size > transport_parsing->incoming_window) { - char *msg; - gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_window); - grpc_error *err = GRPC_ERROR_CREATE(msg); - gpr_free(msg); - return err; - } - - if (incoming_frame_size > stream_parsing->incoming_window) { +static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + uint32_t incoming_frame_size = t->incoming_frame_size; + if (incoming_frame_size > t->incoming_window) { char *msg; gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64, - transport_parsing->incoming_frame_size, - stream_parsing->incoming_window); + t->incoming_frame_size, t->incoming_window); grpc_error *err = GRPC_ERROR_CREATE(msg); gpr_free(msg); return err; } - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window, + GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", t, incoming_window, incoming_frame_size); - GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", transport_parsing, stream_parsing, - incoming_window, incoming_frame_size); - stream_parsing->received_bytes += incoming_frame_size; - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); + if (s != NULL) { + if (incoming_frame_size > s->incoming_window) { + char *msg; + gpr_asprintf(&msg, + "frame of size %d overflows incoming window of %" PRId64, + t->incoming_frame_size, s->incoming_window); + grpc_error *err = GRPC_ERROR_CREATE(msg); + gpr_free(msg); + return err; + } + + GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", t, s, incoming_window, + incoming_frame_size); + s->received_bytes += incoming_frame_size; + s->max_recv_bytes -= + (uint32_t)GPR_MIN(s->max_recv_bytes, incoming_frame_size); + } return GRPC_ERROR_NONE; } -static grpc_error *init_data_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - grpc_chttp2_stream_parsing *stream_parsing = - grpc_chttp2_parsing_lookup_stream(transport_parsing, - transport_parsing->incoming_stream_id); +static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + grpc_chttp2_stream *s = + grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id); grpc_error *err = GRPC_ERROR_NONE; - if (stream_parsing == NULL) { - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); + err = update_incoming_window(exec_ctx, t, s); + if (err != GRPC_ERROR_NONE) { + goto error_handler; } - stream_parsing->stats.incoming.framing_bytes += 9; - if (stream_parsing->received_close) { - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); + if (s == NULL) { + return init_skip_frame_parser(exec_ctx, t, 0); } - if (err == GRPC_ERROR_NONE) { - err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing); + s->stats.incoming.framing_bytes += 9; + if (err == GRPC_ERROR_NONE && s->read_closed) { + return init_skip_frame_parser(exec_ctx, t, 0); } if (err == GRPC_ERROR_NONE) { - err = grpc_chttp2_data_parser_begin_frame( - &stream_parsing->data_parser, transport_parsing->incoming_frame_flags, - stream_parsing->id); + err = grpc_chttp2_data_parser_begin_frame(&s->data_parser, + t->incoming_frame_flags, s->id); } +error_handler: if (err == GRPC_ERROR_NONE) { - transport_parsing->incoming_stream = stream_parsing; - transport_parsing->parser = grpc_chttp2_data_parser_parse; - transport_parsing->parser_data = &stream_parsing->data_parser; + t->incoming_stream = s; + t->parser = grpc_chttp2_data_parser_parse; + t->parser_data = &s->data_parser; return GRPC_ERROR_NONE; } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) { /* handle stream errors by closing the stream */ - stream_parsing->received_close = 1; - stream_parsing->forced_close_error = err; + if (s != NULL) { + grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false, err); + } gpr_slice_buffer_add( - &transport_parsing->qbuf, - grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, - GRPC_CHTTP2_PROTOCOL_ERROR, - &stream_parsing->stats.outgoing)); - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); + &t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id, + GRPC_CHTTP2_PROTOCOL_ERROR, + &s->stats.outgoing)); + return init_skip_frame_parser(exec_ctx, t, 0); } else { return err; } @@ -648,23 +442,22 @@ static grpc_error *init_data_frame_parser( static void free_timeout(void *p) { gpr_free(p); } -static void on_initial_header(void *tp, grpc_mdelem *md) { - grpc_chttp2_transport_parsing *transport_parsing = tp; - grpc_chttp2_stream_parsing *stream_parsing = - transport_parsing->incoming_stream; +static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp, + grpc_mdelem *md) { + grpc_chttp2_transport *t = tp; + grpc_chttp2_stream *s = t->incoming_stream; GPR_TIMER_BEGIN("on_initial_header", 0); - GPR_ASSERT(stream_parsing); + GPR_ASSERT(s != NULL); GRPC_CHTTP2_IF_TRACING(gpr_log( - GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", stream_parsing->id, - transport_parsing->is_client ? "CLI" : "SVR", + GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR", grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { /* TODO(ctiller): check for a status like " 0" */ - stream_parsing->seen_error = true; + s->seen_error = true; } if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) { @@ -681,306 +474,273 @@ static void on_initial_header(void *tp, grpc_mdelem *md) { grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); } grpc_chttp2_incoming_metadata_buffer_set_deadline( - &stream_parsing->metadata_buffer[0], + &s->metadata_buffer[0], gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout)); GRPC_MDELEM_UNREF(md); } else { - const size_t new_size = - stream_parsing->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); - grpc_chttp2_transport_global *transport_global = - &TRANSPORT_FROM_PARSING(transport_parsing)->global; + const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); const size_t metadata_size_limit = - transport_global->settings[GRPC_LOCAL_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; if (new_size > metadata_size_limit) { - if (!stream_parsing->exceeded_metadata_size) { - gpr_log(GPR_DEBUG, - "received initial metadata size exceeds limit (%" PRIuPTR - " vs. %" PRIuPTR ")", - new_size, metadata_size_limit); - stream_parsing->seen_error = true; - stream_parsing->exceeded_metadata_size = true; - } + gpr_log(GPR_DEBUG, + "received initial metadata size exceeds limit (%" PRIuPTR + " vs. %" PRIuPTR ")", + new_size, metadata_size_limit); + grpc_chttp2_cancel_stream( + exec_ctx, t, s, + grpc_error_set_int( + GRPC_ERROR_CREATE("received initial metadata size exceeds limit"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); + grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); + s->seen_error = true; GRPC_MDELEM_UNREF(md); } else { - grpc_chttp2_incoming_metadata_buffer_add( - &stream_parsing->metadata_buffer[0], md); + grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md); } } - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); - GPR_TIMER_END("on_initial_header", 0); } -static void on_trailing_header(void *tp, grpc_mdelem *md) { - grpc_chttp2_transport_parsing *transport_parsing = tp; - grpc_chttp2_stream_parsing *stream_parsing = - transport_parsing->incoming_stream; +static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp, + grpc_mdelem *md) { + grpc_chttp2_transport *t = tp; + grpc_chttp2_stream *s = t->incoming_stream; GPR_TIMER_BEGIN("on_trailing_header", 0); - GPR_ASSERT(stream_parsing); + GPR_ASSERT(s != NULL); GRPC_CHTTP2_IF_TRACING(gpr_log( - GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", stream_parsing->id, - transport_parsing->is_client ? "CLI" : "SVR", + GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR", grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value))); if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) { /* TODO(ctiller): check for a status like " 0" */ - stream_parsing->seen_error = true; + s->seen_error = true; } - const size_t new_size = - stream_parsing->metadata_buffer[1].size + GRPC_MDELEM_LENGTH(md); - grpc_chttp2_transport_global *transport_global = - &TRANSPORT_FROM_PARSING(transport_parsing)->global; + const size_t new_size = s->metadata_buffer[1].size + GRPC_MDELEM_LENGTH(md); const size_t metadata_size_limit = - transport_global->settings[GRPC_LOCAL_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE]; if (new_size > metadata_size_limit) { - if (!stream_parsing->exceeded_metadata_size) { - gpr_log(GPR_DEBUG, - "received trailing metadata size exceeds limit (%" PRIuPTR - " vs. %" PRIuPTR ")", - new_size, metadata_size_limit); - stream_parsing->seen_error = true; - stream_parsing->exceeded_metadata_size = true; - } + gpr_log(GPR_DEBUG, + "received trailing metadata size exceeds limit (%" PRIuPTR + " vs. %" PRIuPTR ")", + new_size, metadata_size_limit); + grpc_chttp2_cancel_stream( + exec_ctx, t, s, + grpc_error_set_int( + GRPC_ERROR_CREATE("received trailing metadata size exceeds limit"), + GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED)); + grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); + s->seen_error = true; GRPC_MDELEM_UNREF(md); } else { - grpc_chttp2_incoming_metadata_buffer_add( - &stream_parsing->metadata_buffer[1], md); + grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[1], md); } - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); - GPR_TIMER_END("on_trailing_header", 0); } -static grpc_error *init_header_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - int is_continuation) { - uint8_t is_eoh = (transport_parsing->incoming_frame_flags & - GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0; - int via_accept = 0; - grpc_chttp2_stream_parsing *stream_parsing; +static grpc_error *init_header_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, + int is_continuation) { + uint8_t is_eoh = + (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0; + grpc_chttp2_stream *s; /* TODO(ctiller): when to increment header_frames_received? */ if (is_eoh) { - transport_parsing->expect_continuation_stream_id = 0; + t->expect_continuation_stream_id = 0; } else { - transport_parsing->expect_continuation_stream_id = - transport_parsing->incoming_stream_id; + t->expect_continuation_stream_id = t->incoming_stream_id; } if (!is_continuation) { - transport_parsing->header_eof = (transport_parsing->incoming_frame_flags & - GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0; + t->header_eof = + (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0; } /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */ - stream_parsing = grpc_chttp2_parsing_lookup_stream( - transport_parsing, transport_parsing->incoming_stream_id); - if (stream_parsing == NULL) { + s = grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id); + if (s == NULL) { if (is_continuation) { - gpr_log(GPR_ERROR, - "grpc_chttp2_stream disbanded before CONTINUATION received"); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + GRPC_CHTTP2_IF_TRACING( + gpr_log(GPR_ERROR, + "grpc_chttp2_stream disbanded before CONTINUATION received")); + return init_skip_frame_parser(exec_ctx, t, 1); } - if (transport_parsing->is_client) { - if ((transport_parsing->incoming_stream_id & 1) && - transport_parsing->incoming_stream_id < - transport_parsing->next_stream_id) { + if (t->is_client) { + if ((t->incoming_stream_id & 1) && + t->incoming_stream_id < t->next_stream_id) { /* this is an old (probably cancelled) grpc_chttp2_stream */ } else { - gpr_log(GPR_ERROR, - "ignoring new grpc_chttp2_stream creation on client"); + GRPC_CHTTP2_IF_TRACING(gpr_log( + GPR_ERROR, "ignoring new grpc_chttp2_stream creation on client")); } - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } else if (transport_parsing->last_incoming_stream_id > - transport_parsing->incoming_stream_id) { - gpr_log(GPR_ERROR, - "ignoring out of order new grpc_chttp2_stream request on server; " - "last grpc_chttp2_stream " - "id=%d, new grpc_chttp2_stream id=%d", - transport_parsing->last_incoming_stream_id, - transport_parsing->incoming_stream_id); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } else if ((transport_parsing->incoming_stream_id & 1) == 0) { - gpr_log(GPR_ERROR, - "ignoring grpc_chttp2_stream with non-client generated index %d", - transport_parsing->incoming_stream_id); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + return init_skip_frame_parser(exec_ctx, t, 1); + } else if (t->last_new_stream_id >= t->incoming_stream_id) { + GRPC_CHTTP2_IF_TRACING(gpr_log( + GPR_ERROR, + "ignoring out of order new grpc_chttp2_stream request on server; " + "last grpc_chttp2_stream " + "id=%d, new grpc_chttp2_stream id=%d", + t->last_new_stream_id, t->incoming_stream_id)); + return init_skip_frame_parser(exec_ctx, t, 1); + } else if ((t->incoming_stream_id & 1) == 0) { + GRPC_CHTTP2_IF_TRACING(gpr_log( + GPR_ERROR, + "ignoring grpc_chttp2_stream with non-client generated index %d", + t->incoming_stream_id)); + return init_skip_frame_parser(exec_ctx, t, 1); } - stream_parsing = transport_parsing->incoming_stream = - grpc_chttp2_parsing_accept_stream( - exec_ctx, transport_parsing, transport_parsing->incoming_stream_id); - if (stream_parsing == NULL) { - gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted"); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + t->last_new_stream_id = t->incoming_stream_id; + s = t->incoming_stream = + grpc_chttp2_parsing_accept_stream(exec_ctx, t, t->incoming_stream_id); + if (s == NULL) { + GRPC_CHTTP2_IF_TRACING( + gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted")); + return init_skip_frame_parser(exec_ctx, t, 1); } - via_accept = 1; } else { - transport_parsing->incoming_stream = stream_parsing; - } - GPR_ASSERT(stream_parsing != NULL && (via_accept == 0 || via_accept == 1)); - stream_parsing->stats.incoming.framing_bytes += 9; - if (stream_parsing->received_close) { - gpr_log(GPR_ERROR, "skipping already closed grpc_chttp2_stream header"); - transport_parsing->incoming_stream = NULL; - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); - } - transport_parsing->parser = grpc_chttp2_header_parser_parse; - transport_parsing->parser_data = &transport_parsing->hpack_parser; - switch (stream_parsing->header_frames_received) { + t->incoming_stream = s; + } + GPR_ASSERT(s != NULL); + s->stats.incoming.framing_bytes += 9; + if (s->read_closed) { + GRPC_CHTTP2_IF_TRACING(gpr_log( + GPR_ERROR, "skipping already closed grpc_chttp2_stream header")); + t->incoming_stream = NULL; + return init_skip_frame_parser(exec_ctx, t, 1); + } + t->parser = grpc_chttp2_header_parser_parse; + t->parser_data = &t->hpack_parser; + switch (s->header_frames_received) { case 0: - transport_parsing->hpack_parser.on_header = on_initial_header; + t->hpack_parser.on_header = on_initial_header; break; case 1: - transport_parsing->hpack_parser.on_header = on_trailing_header; + t->hpack_parser.on_header = on_trailing_header; break; case 2: gpr_log(GPR_ERROR, "too many header frames received"); - return init_skip_frame_parser(exec_ctx, transport_parsing, 1); + return init_skip_frame_parser(exec_ctx, t, 1); } - transport_parsing->hpack_parser.on_header_user_data = transport_parsing; - transport_parsing->hpack_parser.is_boundary = is_eoh; - transport_parsing->hpack_parser.is_eof = - (uint8_t)(is_eoh ? transport_parsing->header_eof : 0); - if (!is_continuation && (transport_parsing->incoming_frame_flags & - GRPC_CHTTP2_FLAG_HAS_PRIORITY)) { - grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser); + t->hpack_parser.on_header_user_data = t; + t->hpack_parser.is_boundary = is_eoh; + t->hpack_parser.is_eof = (uint8_t)(is_eoh ? t->header_eof : 0); + if (!is_continuation && + (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_HAS_PRIORITY)) { + grpc_chttp2_hpack_parser_set_has_priority(&t->hpack_parser); } return GRPC_ERROR_NONE; } -static grpc_error *init_window_update_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { +static grpc_error *init_window_update_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { grpc_error *err = grpc_chttp2_window_update_parser_begin_frame( - &transport_parsing->simple.window_update, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags); + &t->simple.window_update, t->incoming_frame_size, + t->incoming_frame_flags); if (err != GRPC_ERROR_NONE) return err; - if (transport_parsing->incoming_stream_id != 0) { - grpc_chttp2_stream_parsing *stream_parsing = - transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( - transport_parsing, transport_parsing->incoming_stream_id); - if (stream_parsing == NULL) { - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); + if (t->incoming_stream_id != 0) { + grpc_chttp2_stream *s = t->incoming_stream = + grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id); + if (s == NULL) { + return init_skip_frame_parser(exec_ctx, t, 0); } - stream_parsing->stats.incoming.framing_bytes += 9; + s->stats.incoming.framing_bytes += 9; } - transport_parsing->parser = grpc_chttp2_window_update_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.window_update; + t->parser = grpc_chttp2_window_update_parser_parse; + t->parser_data = &t->simple.window_update; return GRPC_ERROR_NONE; } -static grpc_error *init_ping_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { +static grpc_error *init_ping_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { grpc_error *err = grpc_chttp2_ping_parser_begin_frame( - &transport_parsing->simple.ping, transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags); + &t->simple.ping, t->incoming_frame_size, t->incoming_frame_flags); if (err != GRPC_ERROR_NONE) return err; - transport_parsing->parser = grpc_chttp2_ping_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.ping; + t->parser = grpc_chttp2_ping_parser_parse; + t->parser_data = &t->simple.ping; return GRPC_ERROR_NONE; } -static grpc_error *init_rst_stream_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { +static grpc_error *init_rst_stream_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { grpc_error *err = grpc_chttp2_rst_stream_parser_begin_frame( - &transport_parsing->simple.rst_stream, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags); + &t->simple.rst_stream, t->incoming_frame_size, t->incoming_frame_flags); if (err != GRPC_ERROR_NONE) return err; - grpc_chttp2_stream_parsing *stream_parsing = - transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( - transport_parsing, transport_parsing->incoming_stream_id); - if (!transport_parsing->incoming_stream) { - return init_skip_frame_parser(exec_ctx, transport_parsing, 0); - } - stream_parsing->stats.incoming.framing_bytes += 9; - transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.rst_stream; + grpc_chttp2_stream *s = t->incoming_stream = + grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id); + if (!t->incoming_stream) { + return init_skip_frame_parser(exec_ctx, t, 0); + } + s->stats.incoming.framing_bytes += 9; + t->parser = grpc_chttp2_rst_stream_parser_parse; + t->parser_data = &t->simple.rst_stream; return GRPC_ERROR_NONE; } -static grpc_error *init_goaway_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { +static grpc_error *init_goaway_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { grpc_error *err = grpc_chttp2_goaway_parser_begin_frame( - &transport_parsing->goaway_parser, transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags); + &t->goaway_parser, t->incoming_frame_size, t->incoming_frame_flags); if (err != GRPC_ERROR_NONE) return err; - transport_parsing->parser = grpc_chttp2_goaway_parser_parse; - transport_parsing->parser_data = &transport_parsing->goaway_parser; + t->parser = grpc_chttp2_goaway_parser_parse; + t->parser_data = &t->goaway_parser; return GRPC_ERROR_NONE; } -static grpc_error *init_settings_frame_parser( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { - if (transport_parsing->incoming_stream_id != 0) { +static grpc_error *init_settings_frame_parser(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + if (t->incoming_stream_id != 0) { return GRPC_ERROR_CREATE("Settings frame received for grpc_chttp2_stream"); } grpc_error *err = grpc_chttp2_settings_parser_begin_frame( - &transport_parsing->simple.settings, - transport_parsing->incoming_frame_size, - transport_parsing->incoming_frame_flags, transport_parsing->settings); + &t->simple.settings, t->incoming_frame_size, t->incoming_frame_flags, + t->settings[GRPC_PEER_SETTINGS]); if (err != GRPC_ERROR_NONE) { return err; } - if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) { - transport_parsing->settings_ack_received = 1; + if (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) { + memcpy(t->settings[GRPC_ACKED_SETTINGS], t->settings[GRPC_SENT_SETTINGS], + GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); grpc_chttp2_hptbl_set_max_bytes( - &transport_parsing->hpack_parser.table, - transport_parsing - ->last_sent_settings[GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); - transport_parsing->max_frame_size = - transport_parsing - ->last_sent_settings[GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]; + &t->hpack_parser.table, + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); + t->sent_local_settings = 0; } - transport_parsing->parser = grpc_chttp2_settings_parser_parse; - transport_parsing->parser_data = &transport_parsing->simple.settings; + t->parser = grpc_chttp2_settings_parser_parse; + t->parser_data = &t->simple.settings; return GRPC_ERROR_NONE; } -/* -static int is_window_update_legal(int64_t window_update, int64_t window) { - return window + window_update < MAX_WINDOW; -} -*/ - -static grpc_error *parse_frame_slice( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, - gpr_slice slice, int is_last) { - grpc_chttp2_stream_parsing *stream_parsing = - transport_parsing->incoming_stream; - grpc_error *err = transport_parsing->parser( - exec_ctx, transport_parsing->parser_data, transport_parsing, - stream_parsing, slice, is_last); +static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t, gpr_slice slice, + int is_last) { + grpc_chttp2_stream *s = t->incoming_stream; + grpc_error *err = t->parser(exec_ctx, t->parser_data, t, s, slice, is_last); if (err == GRPC_ERROR_NONE) { - if (stream_parsing) { - grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, - stream_parsing); - } - return GRPC_ERROR_NONE; + return err; } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) { if (grpc_http_trace) { const char *msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); grpc_error_free_string(msg); } - grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing); - if (stream_parsing) { - stream_parsing->forced_close_error = err; + grpc_chttp2_parsing_become_skip_parser(exec_ctx, t); + if (s) { + s->forced_close_error = err; gpr_slice_buffer_add( - &transport_parsing->qbuf, - grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, - GRPC_CHTTP2_PROTOCOL_ERROR, - &stream_parsing->stats.outgoing)); + &t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id, + GRPC_CHTTP2_PROTOCOL_ERROR, + &s->stats.outgoing)); } else { GRPC_ERROR_UNREF(err); } diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.c b/src/core/ext/transport/chttp2/transport/stream_lists.c index 4dc4968248..6d25b3ae57 100644 --- a/src/core/ext/transport/chttp2/transport/stream_lists.c +++ b/src/core/ext/transport/chttp2/transport/stream_lists.c @@ -35,27 +35,6 @@ #include <grpc/support/log.h> -#define TRANSPORT_FROM_GLOBAL(tg) \ - ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \ - global))) - -#define STREAM_FROM_GLOBAL(sg) \ - ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global))) - -#define TRANSPORT_FROM_WRITING(tw) \ - ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ - writing))) - -#define STREAM_FROM_WRITING(sw) \ - ((grpc_chttp2_stream *)((char *)(sw)-offsetof(grpc_chttp2_stream, writing))) - -#define TRANSPORT_FROM_PARSING(tp) \ - ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \ - parsing))) - -#define STREAM_FROM_PARSING(sp) \ - ((grpc_chttp2_stream *)((char *)(sp)-offsetof(grpc_chttp2_stream, parsing))) - /* core list management */ static int stream_list_empty(grpc_chttp2_transport *t, @@ -139,321 +118,57 @@ static bool stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s, /* wrappers for specializations */ -bool grpc_chttp2_list_add_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - GPR_ASSERT(stream_global->id != 0); - return stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_WRITABLE); -} - -int grpc_chttp2_list_pop_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_WRITABLE); - if (r != 0) { - *stream_global = &stream->global; - *stream_writing = &stream->writing; - } - return r; -} - -bool grpc_chttp2_list_remove_writable_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_WRITABLE); -} - -void grpc_chttp2_list_add_writing_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing) { - GPR_ASSERT(stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), - STREAM_FROM_WRITING(stream_writing), - GRPC_CHTTP2_LIST_WRITING)); -} - -int grpc_chttp2_list_have_writing_streams( - grpc_chttp2_transport_writing *transport_writing) { - return !stream_list_empty(TRANSPORT_FROM_WRITING(transport_writing), - GRPC_CHTTP2_LIST_WRITING); -} - -int grpc_chttp2_list_pop_writing_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing **stream_writing) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, - GRPC_CHTTP2_LIST_WRITING); - if (r != 0) { - *stream_writing = &stream->writing; - } - return r; -} - -void grpc_chttp2_list_add_written_stream( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing) { - stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), - STREAM_FROM_WRITING(stream_writing), - GRPC_CHTTP2_LIST_WRITTEN); -} - -int grpc_chttp2_list_pop_written_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, - GRPC_CHTTP2_LIST_WRITTEN); - if (r != 0) { - *stream_global = &stream->global; - *stream_writing = &stream->writing; - } - return r; -} - -void grpc_chttp2_list_add_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - GPR_ASSERT(stream_global->id != 0); - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE); -} - -void grpc_chttp2_list_remove_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_maybe_remove( - TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE); -} - -int grpc_chttp2_list_pop_unannounced_incoming_window_available( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_parsing **stream_parsing) { - grpc_chttp2_stream *stream; - int r = - stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE); - if (r != 0) { - *stream_global = &stream->global; - *stream_parsing = &stream->parsing; - } - return r; -} - -void grpc_chttp2_list_add_parsing_seen_stream( - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_parsing *stream_parsing) { - stream_list_add(TRANSPORT_FROM_PARSING(transport_parsing), - STREAM_FROM_PARSING(stream_parsing), - GRPC_CHTTP2_LIST_PARSING_SEEN); -} - -int grpc_chttp2_list_pop_parsing_seen_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_parsing *transport_parsing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_parsing **stream_parsing) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_PARSING(transport_parsing), &stream, - GRPC_CHTTP2_LIST_PARSING_SEEN); - if (r != 0) { - *stream_global = &stream->global; - *stream_parsing = &stream->parsing; - } - return r; -} - -void grpc_chttp2_list_add_waiting_for_concurrency( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); -} - -int grpc_chttp2_list_pop_waiting_for_concurrency( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); - if (r != 0) { - *stream_global = &stream->global; - } - return r; -} - -void grpc_chttp2_list_add_check_read_ops( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global); - if (!t->executor.check_read_ops_scheduled) { - grpc_combiner_execute_finally(exec_ctx, t->executor.combiner, - &t->initiate_read_flush_locked, - GRPC_ERROR_NONE, false); - t->executor.check_read_ops_scheduled = true; - } - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_CHECK_READ_OPS); -} - -bool grpc_chttp2_list_remove_check_read_ops( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_CHECK_READ_OPS); +bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + GPR_ASSERT(s->id != 0); + return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITABLE); } -int grpc_chttp2_list_pop_check_read_ops( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_CHECK_READ_OPS); - if (r != 0) { - *stream_global = &stream->global; - } - return r; -} - -void grpc_chttp2_list_add_writing_stalled_by_transport( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing) { - grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing); - gpr_log(GPR_DEBUG, "writing stalled %d", stream->global.id); - if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) { - GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled"); - } - stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), stream, - GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT); +int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { + return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITABLE); } -bool grpc_chttp2_list_flush_writing_stalled_by_transport( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing) { - grpc_chttp2_stream *stream; - bool out = false; - grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing); - while (stream_list_pop(transport, &stream, - GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) { - gpr_log(GPR_DEBUG, "move %d from writing stalled to just stalled", - stream->global.id); - grpc_chttp2_list_add_stalled_by_transport(transport_writing, - &stream->writing); - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global, - "chttp2_writing_stalled"); - out = true; - } - return out; +bool grpc_chttp2_list_remove_writable_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + return stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_WRITABLE); } -void grpc_chttp2_list_add_stalled_by_transport( - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_writing *stream_writing) { - gpr_log(GPR_DEBUG, "stalled %d", stream_writing->id); - stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), - STREAM_FROM_WRITING(stream_writing), - GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); +bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITING); } -int grpc_chttp2_list_pop_stalled_by_transport( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); - if (r != 0) { - *stream_global = &stream->global; - } - return r; +int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t) { + return !stream_list_empty(t, GRPC_CHTTP2_LIST_WRITING); } -void grpc_chttp2_list_remove_stalled_by_transport( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); +int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { + return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITING); } -void grpc_chttp2_list_add_closed_waiting_for_parsing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING); +void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + stream_list_add(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); } -int grpc_chttp2_list_pop_closed_waiting_for_parsing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING); - if (r != 0) { - *stream_global = &stream->global; - } - return r; +int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { + return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); } -void grpc_chttp2_list_add_closed_waiting_for_writing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING); +void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); } -int grpc_chttp2_list_pop_closed_waiting_for_writing( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global **stream_global) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING); - if (r != 0) { - *stream_global = &stream->global; - } - return r; +int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream **s) { + return stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); } -void grpc_chttp2_register_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream *s) { - stream_list_add_tail(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS); -} - -int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t, - grpc_chttp2_stream *s) { - stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS); - return stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS); -} - -int grpc_chttp2_has_streams(grpc_chttp2_transport *t) { - return !stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS); -} - -void grpc_chttp2_for_all_streams( - grpc_chttp2_transport_global *transport_global, void *user_data, - void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data, - grpc_chttp2_stream_global *stream_global)) { - grpc_chttp2_stream *s; - grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global); - for (s = t->lists[GRPC_CHTTP2_LIST_ALL_STREAMS].head; s != NULL; - s = s->links[GRPC_CHTTP2_LIST_ALL_STREAMS].next) { - cb(transport_global, user_data, &s->global); - } +void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t, + grpc_chttp2_stream *s) { + stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); } diff --git a/src/core/ext/transport/chttp2/transport/stream_map.c b/src/core/ext/transport/chttp2/transport/stream_map.c index f70791c422..59b3a14e0a 100644 --- a/src/core/ext/transport/chttp2/transport/stream_map.c +++ b/src/core/ext/transport/chttp2/transport/stream_map.c @@ -77,6 +77,7 @@ void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key, GPR_ASSERT(count == 0 || keys[count - 1] < key); GPR_ASSERT(value); + GPR_ASSERT(grpc_chttp2_stream_map_find(map, key) == NULL); if (count == capacity) { if (map->free > capacity / 4) { @@ -96,40 +97,6 @@ void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key, map->count = count + 1; } -void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src, - grpc_chttp2_stream_map *dst) { - /* if src is empty we dont need to do anything */ - if (src->count == src->free) { - return; - } - /* if dst is empty we simply need to swap */ - if (dst->count == dst->free) { - GPR_SWAP(grpc_chttp2_stream_map, *src, *dst); - return; - } - /* the first element of src must be greater than the last of dst... - * however the maps may need compacting for this property to hold */ - if (src->keys[0] <= dst->keys[dst->count - 1]) { - src->count = compact(src->keys, src->values, src->count); - src->free = 0; - dst->count = compact(dst->keys, dst->values, dst->count); - dst->free = 0; - } - GPR_ASSERT(src->keys[0] > dst->keys[dst->count - 1]); - /* if dst doesn't have capacity, resize */ - if (dst->count + src->count > dst->capacity) { - dst->capacity = GPR_MAX(dst->capacity * 3 / 2, dst->count + src->count); - dst->keys = gpr_realloc(dst->keys, dst->capacity * sizeof(uint32_t)); - dst->values = gpr_realloc(dst->values, dst->capacity * sizeof(void *)); - } - memcpy(dst->keys + dst->count, src->keys, src->count * sizeof(uint32_t)); - memcpy(dst->values + dst->count, src->values, src->count * sizeof(void *)); - dst->count += src->count; - dst->free += src->free; - src->count = 0; - src->free = 0; -} - static void **find(grpc_chttp2_stream_map *map, uint32_t key) { size_t min_idx = 0; size_t max_idx = map->count; @@ -170,6 +137,7 @@ void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t key) { if (map->free == map->count) { map->free = map->count = 0; } + GPR_ASSERT(grpc_chttp2_stream_map_find(map, key) == NULL); } return out; } diff --git a/src/core/ext/transport/chttp2/transport/stream_map.h b/src/core/ext/transport/chttp2/transport/stream_map.h index b1d59ca6a3..e76312dd1a 100644 --- a/src/core/ext/transport/chttp2/transport/stream_map.h +++ b/src/core/ext/transport/chttp2/transport/stream_map.h @@ -65,10 +65,6 @@ void grpc_chttp2_stream_map_add(grpc_chttp2_stream_map *map, uint32_t key, or NULL otherwise */ void *grpc_chttp2_stream_map_delete(grpc_chttp2_stream_map *map, uint32_t key); -/* Move all elements of src into dst */ -void grpc_chttp2_stream_map_move_into(grpc_chttp2_stream_map *src, - grpc_chttp2_stream_map *dst); - /* Return an existing key, or NULL if it does not exist */ void *grpc_chttp2_stream_map_find(grpc_chttp2_stream_map *map, uint32_t key); diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index 979515bd54..b39695a1a5 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -40,349 +40,221 @@ #include "src/core/ext/transport/chttp2/transport/http2_errors.h" #include "src/core/lib/profiling/timers.h" -static void finalize_outbuf(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_writing *transport_writing); +static void add_to_write_list(grpc_chttp2_write_cb **list, + grpc_chttp2_write_cb *cb) { + cb->next = *list; + *list = cb; +} + +static void finish_write_cb(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_stream *s, grpc_chttp2_write_cb *cb, + grpc_error *error) { + grpc_chttp2_complete_closure_step(exec_ctx, t, s, &cb->closure, error, + "finish_write_cb"); + cb->next = t->write_cb_pool; + t->write_cb_pool = cb; +} -int grpc_chttp2_unlocking_check_writes( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing) { - grpc_chttp2_stream_global *stream_global; - grpc_chttp2_stream_writing *stream_writing; +static void update_list(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_chttp2_stream *s, int64_t send_bytes, + grpc_chttp2_write_cb **list, grpc_error *error) { + grpc_chttp2_write_cb *cb = *list; + *list = NULL; + s->flow_controlled_bytes_written += send_bytes; + while (cb) { + grpc_chttp2_write_cb *next = cb->next; + if (cb->call_at_byte <= s->flow_controlled_bytes_written) { + finish_write_cb(exec_ctx, t, s, cb, GRPC_ERROR_REF(error)); + } else { + add_to_write_list(list, cb); + } + cb = next; + } + GRPC_ERROR_UNREF(error); +} - GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0); +bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, + grpc_chttp2_transport *t) { + grpc_chttp2_stream *s; - transport_writing->max_frame_size = - transport_global->settings[GRPC_ACKED_SETTINGS] - [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]; + GPR_TIMER_BEGIN("grpc_chttp2_begin_write", 0); - if (transport_global->dirtied_local_settings && - !transport_global->sent_local_settings) { + if (t->dirtied_local_settings && !t->sent_local_settings) { gpr_slice_buffer_add( - &transport_writing->outbuf, + &t->outbuf, grpc_chttp2_settings_create( - transport_global->settings[GRPC_SENT_SETTINGS], - transport_global->settings[GRPC_LOCAL_SETTINGS], - transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS)); - transport_global->force_send_settings = 0; - transport_global->dirtied_local_settings = 0; - transport_global->sent_local_settings = 1; + t->settings[GRPC_SENT_SETTINGS], t->settings[GRPC_LOCAL_SETTINGS], + t->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS)); + t->force_send_settings = 0; + t->dirtied_local_settings = 0; + t->sent_local_settings = 1; } /* simple writes are queued to qbuf, and flushed here */ - gpr_slice_buffer_move_into(&transport_global->qbuf, - &transport_writing->outbuf); - GPR_ASSERT(transport_global->qbuf.count == 0); + gpr_slice_buffer_move_into(&t->qbuf, &t->outbuf); + GPR_ASSERT(t->qbuf.count == 0); grpc_chttp2_hpack_compressor_set_max_table_size( - &transport_writing->hpack_compressor, - transport_global->settings[GRPC_PEER_SETTINGS] - [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); + &t->hpack_compressor, + t->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]); - GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window, - transport_global, outgoing_window); - if (transport_writing->outgoing_window > 0) { - while (grpc_chttp2_list_pop_stalled_by_transport(transport_global, - &stream_global)) { - grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, - false, "transport.read_flow_control"); + if (t->outgoing_window > 0) { + while (grpc_chttp2_list_pop_stalled_by_transport(t, &s)) { + grpc_chttp2_become_writable(exec_ctx, t, s, false, + "transport.read_flow_control"); } } /* for each grpc_chttp2_stream that's become writable, frame it's data (according to available window sizes) and add to the output buffer */ - while (grpc_chttp2_list_pop_writable_stream( - transport_global, transport_writing, &stream_global, &stream_writing)) { - bool sent_initial_metadata = stream_writing->sent_initial_metadata; - bool become_writable = false; + while (grpc_chttp2_list_pop_writable_stream(t, &s)) { + bool sent_initial_metadata = s->sent_initial_metadata; + bool now_writing = false; - stream_writing->id = stream_global->id; - stream_writing->read_closed = stream_global->read_closed; + GRPC_CHTTP2_IF_TRACING(gpr_log( + GPR_DEBUG, "W:%p %s[%d] im-(sent,send)=(%d,%d) announce=%d", t, + t->is_client ? "CLIENT" : "SERVER", s->id, sent_initial_metadata, + s->send_initial_metadata != NULL, s->announce_window)); - GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing, - outgoing_window, stream_global, - outgoing_window); - - if (!sent_initial_metadata && stream_global->send_initial_metadata) { - stream_writing->send_initial_metadata = - stream_global->send_initial_metadata; - stream_global->send_initial_metadata = NULL; - become_writable = true; + /* send initial metadata if it's available */ + if (!sent_initial_metadata && s->send_initial_metadata) { + grpc_chttp2_encode_header( + &t->hpack_compressor, s->id, s->send_initial_metadata, 0, + t->settings[GRPC_ACKED_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], + &s->stats.outgoing, &t->outbuf); + s->send_initial_metadata = NULL; + s->sent_initial_metadata = true; sent_initial_metadata = true; + now_writing = true; + } + /* send any window updates */ + if (s->announce_window > 0) { + uint32_t announce = s->announce_window; + gpr_slice_buffer_add(&t->outbuf, + grpc_chttp2_window_update_create( + s->id, s->announce_window, &s->stats.outgoing)); + GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, announce_window, announce); } if (sent_initial_metadata) { - if (stream_global->send_message != NULL) { - gpr_slice hdr = gpr_slice_malloc(5); - uint8_t *p = GPR_SLICE_START_PTR(hdr); - uint32_t len = stream_global->send_message->length; - GPR_ASSERT(stream_writing->send_message == NULL); - p[0] = (stream_global->send_message->flags & - GRPC_WRITE_INTERNAL_COMPRESS) != 0; - p[1] = (uint8_t)(len >> 24); - p[2] = (uint8_t)(len >> 16); - p[3] = (uint8_t)(len >> 8); - p[4] = (uint8_t)(len); - gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr); - if (stream_global->send_message->length > 0) { - stream_writing->send_message = stream_global->send_message; - } else { - stream_writing->send_message = NULL; + /* send any body bytes, if allowed by flow control */ + if (s->flow_controlled_buffer.length > 0) { + uint32_t max_outgoing = + (uint32_t)GPR_MIN(t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], + GPR_MIN(s->outgoing_window, t->outgoing_window)); + if (max_outgoing > 0) { + uint32_t send_bytes = + (uint32_t)GPR_MIN(max_outgoing, s->flow_controlled_buffer.length); + bool is_last_data_frame = + s->fetching_send_message == NULL && + send_bytes == s->flow_controlled_buffer.length; + bool is_last_frame = + is_last_data_frame && s->send_trailing_metadata != NULL && + grpc_metadata_batch_is_empty(s->send_trailing_metadata); + grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, send_bytes, + is_last_frame, &s->stats.outgoing, + &t->outbuf); + GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window, + send_bytes); + GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window, + send_bytes); + if (is_last_frame) { + s->send_trailing_metadata = NULL; + s->sent_trailing_metadata = true; + if (!t->is_client && !s->read_closed) { + gpr_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create( + s->id, GRPC_CHTTP2_NO_ERROR, + &s->stats.outgoing)); + } + } + s->sending_bytes += send_bytes; + now_writing = true; + if (s->flow_controlled_buffer.length > 0) { + GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:fork"); + grpc_chttp2_list_add_writable_stream(t, s); + } + } else if (t->outgoing_window == 0) { + grpc_chttp2_list_add_stalled_by_transport(t, s); + now_writing = true; } - stream_writing->stream_fetched = 0; - stream_global->send_message = NULL; } - if ((stream_writing->send_message != NULL || - stream_writing->flow_controlled_buffer.length > 0) && - stream_writing->outgoing_window > 0) { - if (transport_writing->outgoing_window > 0) { - become_writable = true; + if (s->send_trailing_metadata != NULL && + s->fetching_send_message == NULL && + s->flow_controlled_buffer.length == 0) { + if (grpc_metadata_batch_is_empty(s->send_trailing_metadata)) { + grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, 0, true, + &s->stats.outgoing, &t->outbuf); } else { - grpc_chttp2_list_add_stalled_by_transport(transport_writing, - stream_writing); + grpc_chttp2_encode_header( + &t->hpack_compressor, s->id, s->send_trailing_metadata, true, + t->settings[GRPC_ACKED_SETTINGS] + [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE], + &s->stats.outgoing, &t->outbuf); } + s->send_trailing_metadata = NULL; + s->sent_trailing_metadata = true; + if (!t->is_client && !s->read_closed) { + gpr_slice_buffer_add( + &t->outbuf, grpc_chttp2_rst_stream_create( + s->id, GRPC_CHTTP2_NO_ERROR, &s->stats.outgoing)); + } + now_writing = true; } - if (stream_global->send_trailing_metadata) { - stream_writing->send_trailing_metadata = - stream_global->send_trailing_metadata; - stream_global->send_trailing_metadata = NULL; - become_writable = true; - } - } - - if (!stream_global->read_closed && - stream_global->unannounced_incoming_window_for_writing > 1024) { - GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing, - announce_window, stream_global, - unannounced_incoming_window_for_writing); - become_writable = true; } - if (become_writable) { - grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); + if (now_writing) { + if (!grpc_chttp2_list_add_writing_stream(t, s)) { + /* already in writing list: drop ref */ + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:already_writing"); + } } else { - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:no_write"); } } /* if the grpc_chttp2_transport is ready to send a window update, do so here also; 3/4 is a magic number that will likely get tuned soon */ - if (transport_global->announce_incoming_window > 0) { - uint32_t announced = (uint32_t)GPR_MIN( - transport_global->announce_incoming_window, UINT32_MAX); - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_global, - announce_incoming_window, announced); + if (t->announce_incoming_window > 0) { + uint32_t announced = + (uint32_t)GPR_MIN(t->announce_incoming_window, UINT32_MAX); + GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, announce_incoming_window, + announced); grpc_transport_one_way_stats throwaway_stats; - gpr_slice_buffer_add( - &transport_writing->outbuf, - grpc_chttp2_window_update_create(0, announced, &throwaway_stats)); - } - - GPR_TIMER_END("grpc_chttp2_unlocking_check_writes", 0); - - return transport_writing->outbuf.count > 0 || - grpc_chttp2_list_have_writing_streams(transport_writing); -} - -void grpc_chttp2_perform_writes( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, - grpc_endpoint *endpoint) { - GPR_ASSERT(transport_writing->outbuf.count > 0 || - grpc_chttp2_list_have_writing_streams(transport_writing)); - - finalize_outbuf(exec_ctx, transport_writing); - - GPR_ASSERT(endpoint); - - if (transport_writing->outbuf.count > 0) { - grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf, - &transport_writing->done_cb); - } else { - grpc_exec_ctx_sched(exec_ctx, &transport_writing->done_cb, GRPC_ERROR_NONE, - NULL); + gpr_slice_buffer_add(&t->outbuf, grpc_chttp2_window_update_create( + 0, announced, &throwaway_stats)); } -} - -static void finalize_outbuf(grpc_exec_ctx *exec_ctx, - grpc_chttp2_transport_writing *transport_writing) { - grpc_chttp2_stream_writing *stream_writing; - GPR_TIMER_BEGIN("finalize_outbuf", 0); + GPR_TIMER_END("grpc_chttp2_begin_write", 0); - bool is_first_data_frame = true; - while ( - grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) { - uint32_t max_outgoing = - (uint32_t)GPR_MIN(transport_writing->max_frame_size, - GPR_MIN(stream_writing->outgoing_window, - transport_writing->outgoing_window)); - /* send initial metadata if it's available */ - if (stream_writing->send_initial_metadata != NULL) { - grpc_chttp2_encode_header( - &transport_writing->hpack_compressor, stream_writing->id, - stream_writing->send_initial_metadata, 0, - transport_writing->max_frame_size, &stream_writing->stats, - &transport_writing->outbuf); - stream_writing->send_initial_metadata = NULL; - stream_writing->sent_initial_metadata = 1; - } - /* send any window updates */ - if (stream_writing->announce_window > 0 && - stream_writing->send_initial_metadata == NULL) { - uint32_t announce = stream_writing->announce_window; - gpr_slice_buffer_add( - &transport_writing->outbuf, - grpc_chttp2_window_update_create(stream_writing->id, - stream_writing->announce_window, - &stream_writing->stats)); - GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, stream_writing, - announce_window, announce); - stream_writing->announce_window = 0; - } - /* fetch any body bytes */ - while (!stream_writing->fetching && stream_writing->send_message && - stream_writing->flow_controlled_buffer.length < max_outgoing && - stream_writing->stream_fetched < - stream_writing->send_message->length) { - if (grpc_byte_stream_next(exec_ctx, stream_writing->send_message, - &stream_writing->fetching_slice, max_outgoing, - &stream_writing->finished_fetch)) { - stream_writing->stream_fetched += - GPR_SLICE_LENGTH(stream_writing->fetching_slice); - if (stream_writing->stream_fetched == - stream_writing->send_message->length) { - stream_writing->send_message = NULL; - } - gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, - stream_writing->fetching_slice); - } else { - stream_writing->fetching = 1; - } - } - /* send any body bytes */ - if (stream_writing->flow_controlled_buffer.length > 0) { - if (max_outgoing > 0) { - uint32_t send_bytes = (uint32_t)GPR_MIN( - max_outgoing, stream_writing->flow_controlled_buffer.length); - int is_last_data_frame = - stream_writing->send_message == NULL && - send_bytes == stream_writing->flow_controlled_buffer.length; - int is_last_frame = is_last_data_frame && - stream_writing->send_trailing_metadata != NULL && - grpc_metadata_batch_is_empty( - stream_writing->send_trailing_metadata); - grpc_chttp2_encode_data( - stream_writing->id, &stream_writing->flow_controlled_buffer, - send_bytes, is_last_frame, &stream_writing->stats, - &transport_writing->outbuf); - if (is_first_data_frame) { - /* TODO(dgq): this is a hack. It'll be fix in a future refactoring */ - stream_writing->stats.data_bytes -= 5; /* discount grpc framing */ - is_first_data_frame = false; - } - GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, - stream_writing, outgoing_window, - send_bytes); - GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_writing, - outgoing_window, send_bytes); - if (is_last_frame) { - stream_writing->send_trailing_metadata = NULL; - stream_writing->sent_trailing_metadata = 1; - } - if (is_last_data_frame) { - GPR_ASSERT(stream_writing->send_message == NULL); - stream_writing->sent_message = 1; - } - } else if (transport_writing->outgoing_window == 0) { - grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing, - stream_writing); - grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); - } - } - /* send trailing metadata if it's available and we're ready for it */ - if (stream_writing->send_message == NULL && - stream_writing->flow_controlled_buffer.length == 0 && - stream_writing->send_trailing_metadata != NULL) { - if (grpc_metadata_batch_is_empty( - stream_writing->send_trailing_metadata)) { - grpc_chttp2_encode_data( - stream_writing->id, &stream_writing->flow_controlled_buffer, 0, 1, - &stream_writing->stats, &transport_writing->outbuf); - } else { - grpc_chttp2_encode_header( - &transport_writing->hpack_compressor, stream_writing->id, - stream_writing->send_trailing_metadata, 1, - transport_writing->max_frame_size, &stream_writing->stats, - &transport_writing->outbuf); - } - if (!transport_writing->is_client && !stream_writing->read_closed) { - gpr_slice_buffer_add(&transport_writing->outbuf, - grpc_chttp2_rst_stream_create( - stream_writing->id, GRPC_CHTTP2_NO_ERROR, - &stream_writing->stats)); - } - stream_writing->send_trailing_metadata = NULL; - stream_writing->sent_trailing_metadata = 1; - } - /* if there's more to write, then loop, otherwise prepare to finish the - * write */ - if ((stream_writing->flow_controlled_buffer.length > 0 || - (stream_writing->send_message && !stream_writing->fetching)) && - stream_writing->outgoing_window > 0) { - if (transport_writing->outgoing_window > 0) { - grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); - } else { - grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing, - stream_writing); - grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); - } - } else { - grpc_chttp2_list_add_written_stream(transport_writing, stream_writing); - } - } - - GPR_TIMER_END("finalize_outbuf", 0); + return t->outbuf.count > 0; } -void grpc_chttp2_cleanup_writing( - grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing) { - GPR_TIMER_BEGIN("grpc_chttp2_cleanup_writing", 0); - grpc_chttp2_stream_writing *stream_writing; - grpc_chttp2_stream_global *stream_global; - - if (grpc_chttp2_list_flush_writing_stalled_by_transport(exec_ctx, - transport_writing)) { - grpc_chttp2_initiate_write(exec_ctx, transport_global, false, - "resume_stalled_stream"); - } +void grpc_chttp2_end_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, + grpc_error *error) { + GPR_TIMER_BEGIN("grpc_chttp2_end_write", 0); + grpc_chttp2_stream *s; - while (grpc_chttp2_list_pop_written_stream( - transport_global, transport_writing, &stream_global, &stream_writing)) { - if (stream_writing->sent_initial_metadata) { + while (grpc_chttp2_list_pop_writing_stream(t, &s)) { + if (s->sent_initial_metadata) { grpc_chttp2_complete_closure_step( - exec_ctx, transport_global, stream_global, - &stream_global->send_initial_metadata_finished, GRPC_ERROR_NONE); + exec_ctx, t, s, &s->send_initial_metadata_finished, + GRPC_ERROR_REF(error), "send_initial_metadata_finished"); } - grpc_transport_move_one_way_stats(&stream_writing->stats, - &stream_global->stats.outgoing); - if (stream_writing->sent_message) { - GPR_ASSERT(stream_writing->send_message == NULL); - grpc_chttp2_complete_closure_step( - exec_ctx, transport_global, stream_global, - &stream_global->send_message_finished, GRPC_ERROR_NONE); - stream_writing->sent_message = 0; + if (s->sending_bytes != 0) { + update_list(exec_ctx, t, s, (int64_t)s->sending_bytes, + &s->on_write_finished_cbs, GRPC_ERROR_REF(error)); + s->sending_bytes = 0; } - if (stream_writing->sent_trailing_metadata) { + if (s->sent_trailing_metadata) { grpc_chttp2_complete_closure_step( - exec_ctx, transport_global, stream_global, - &stream_global->send_trailing_metadata_finished, GRPC_ERROR_NONE); - } - if (stream_writing->sent_trailing_metadata) { - grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, - !transport_global->is_client, 1, - GRPC_ERROR_NONE); + exec_ctx, t, s, &s->send_trailing_metadata_finished, + GRPC_ERROR_REF(error), "send_trailing_metadata_finished"); + grpc_chttp2_mark_stream_closed(exec_ctx, t, s, !t->is_client, 1, + GRPC_ERROR_REF(error)); } - GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); + GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:end"); } - gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf); - GPR_TIMER_END("grpc_chttp2_cleanup_writing", 0); + gpr_slice_buffer_reset_and_unref(&t->outbuf); + GRPC_ERROR_UNREF(error); + GPR_TIMER_END("grpc_chttp2_end_write", 0); } diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c index 00a5be419e..25ad40b935 100644 --- a/src/core/ext/transport/cronet/transport/cronet_transport.c +++ b/src/core/ext/transport/cronet/transport/cronet_transport.c @@ -543,7 +543,7 @@ static void create_grpc_frame(gpr_slice_buffer *write_slice_buffer, static void convert_metadata_to_cronet_headers( grpc_linked_mdelem *head, const char *host, char **pp_url, cronet_bidirectional_stream_header **pp_headers, size_t *p_num_headers, - const char ** method) { + const char **method) { grpc_linked_mdelem *curr = head; /* Walk the linked list and get number of header fields */ size_t num_headers_available = 0; diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c index 3a56b1ff20..2957d2c818 100644 --- a/src/core/lib/channel/channel_args.c +++ b/src/core/lib/channel/channel_args.c @@ -272,6 +272,18 @@ int grpc_channel_args_compare(const grpc_channel_args *a, return 0; } +const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args, + const char *name) { + if (args != NULL) { + for (size_t i = 0; i < args->num_args; ++i) { + if (strcmp(args->args[i].key, name) == 0) { + return &args->args[i]; + } + } + } + return NULL; +} + int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options) { if (arg->type != GRPC_ARG_INTEGER) { gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key); diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h index 586a296d1f..a80340c0fa 100644 --- a/src/core/lib/channel/channel_args.h +++ b/src/core/lib/channel/channel_args.h @@ -89,6 +89,10 @@ uint32_t grpc_channel_args_compression_algorithm_get_states( int grpc_channel_args_compare(const grpc_channel_args *a, const grpc_channel_args *b); +/** Returns the value of argument \a name from \a args, or NULL if not found. */ +const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args, + const char *name); + typedef struct grpc_integer_options { int default_value; // Return this if value is outside of expected bounds. int min_value; diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c index 57d34d9e9a..2c5367901d 100644 --- a/src/core/lib/channel/channel_stack.c +++ b/src/core/lib/channel/channel_stack.c @@ -162,7 +162,7 @@ grpc_error *grpc_call_stack_init( grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack, int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg, grpc_call_context_element *context, const void *transport_server_data, - gpr_timespec deadline, grpc_call_stack *call_stack) { + grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack) { grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack); grpc_call_element_args args; size_t count = channel_stack->count; @@ -179,10 +179,12 @@ grpc_error *grpc_call_stack_init( /* init per-filter data */ grpc_error *first_error = GRPC_ERROR_NONE; + args.start_time = gpr_now(GPR_CLOCK_MONOTONIC); for (i = 0; i < count; i++) { args.call_stack = call_stack; args.server_transport_data = transport_server_data; args.context = context; + args.path = path; args.deadline = deadline; call_elems[i].filter = channel_elems[i].filter; call_elems[i].channel_data = channel_elems[i].channel_data; diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index 1cfe2885d8..27f3be7b29 100644 --- a/src/core/lib/channel/channel_stack.h +++ b/src/core/lib/channel/channel_stack.h @@ -74,6 +74,8 @@ typedef struct { grpc_call_stack *call_stack; const void *server_transport_data; grpc_call_context_element *context; + grpc_mdstr *path; + gpr_timespec start_time; gpr_timespec deadline; } grpc_call_element_args; @@ -225,7 +227,7 @@ grpc_error *grpc_call_stack_init( grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack, int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg, grpc_call_context_element *context, const void *transport_server_data, - gpr_timespec deadline, grpc_call_stack *call_stack); + grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack); /* Set a pollset or a pollset_set for a call stack: must occur before the first * op is started */ void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx, diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c index 079b98a2f8..d2ea5250f6 100644 --- a/src/core/lib/channel/deadline_filter.c +++ b/src/core/lib/channel/deadline_filter.c @@ -64,30 +64,49 @@ static void timer_callback(grpc_exec_ctx* exec_ctx, void* arg, } // Starts the deadline timer. -static void start_timer_if_needed(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem, - gpr_timespec deadline) { +static void start_timer_if_needed_locked(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem, + gpr_timespec deadline) { grpc_deadline_state* deadline_state = elem->call_data; deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); - if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) { + // Note: We do not start the timer if there is already a timer + // pending. This should be okay, because this is only called from two + // functions exported by this module: grpc_deadline_state_start(), which + // starts the initial timer, and grpc_deadline_state_reset(), which + // cancels any pre-existing timer before starting a new one. In + // particular, we want to ensure that if grpc_deadline_state_start() + // winds up trying to start the timer after grpc_deadline_state_reset() + // has already done so, we ignore the value from the former. + if (!deadline_state->timer_pending && + gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) { // Take a reference to the call stack, to be owned by the timer. GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer"); - gpr_mu_lock(&deadline_state->timer_mu); deadline_state->timer_pending = true; grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, timer_callback, elem, gpr_now(GPR_CLOCK_MONOTONIC)); - gpr_mu_unlock(&deadline_state->timer_mu); } } +static void start_timer_if_needed(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem, + gpr_timespec deadline) { + grpc_deadline_state* deadline_state = elem->call_data; + gpr_mu_lock(&deadline_state->timer_mu); + start_timer_if_needed_locked(exec_ctx, elem, deadline); + gpr_mu_unlock(&deadline_state->timer_mu); +} // Cancels the deadline timer. -static void cancel_timer_if_needed(grpc_exec_ctx* exec_ctx, - grpc_deadline_state* deadline_state) { - gpr_mu_lock(&deadline_state->timer_mu); +static void cancel_timer_if_needed_locked(grpc_exec_ctx* exec_ctx, + grpc_deadline_state* deadline_state) { if (deadline_state->timer_pending) { grpc_timer_cancel(exec_ctx, &deadline_state->timer); deadline_state->timer_pending = false; } +} +static void cancel_timer_if_needed(grpc_exec_ctx* exec_ctx, + grpc_deadline_state* deadline_state) { + gpr_mu_lock(&deadline_state->timer_mu); + cancel_timer_if_needed_locked(exec_ctx, deadline_state); gpr_mu_unlock(&deadline_state->timer_mu); } @@ -108,6 +127,21 @@ static void inject_on_complete_cb(grpc_deadline_state* deadline_state, op->on_complete = &deadline_state->on_complete; } +void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + grpc_call_stack* call_stack) { + grpc_deadline_state* deadline_state = elem->call_data; + memset(deadline_state, 0, sizeof(*deadline_state)); + deadline_state->call_stack = call_stack; + gpr_mu_init(&deadline_state->timer_mu); +} + +void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, + grpc_call_element* elem) { + grpc_deadline_state* deadline_state = elem->call_data; + cancel_timer_if_needed(exec_ctx, deadline_state); + gpr_mu_destroy(&deadline_state->timer_mu); +} + // Callback and associated state for starting the timer after call stack // initialization has been completed. struct start_timer_after_init_state { @@ -122,16 +156,11 @@ static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, gpr_free(state); } -void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_call_element_args* args) { - grpc_deadline_state* deadline_state = elem->call_data; - memset(deadline_state, 0, sizeof(*deadline_state)); - deadline_state->call_stack = args->call_stack; - gpr_mu_init(&deadline_state->timer_mu); +void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + gpr_timespec deadline) { // Deadline will always be infinite on servers, so the timer will only be // set on clients with a finite deadline. - const gpr_timespec deadline = - gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC); + deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) { // When the deadline passes, we indicate the failure by sending down // an op with cancel_error set. However, we can't send down any ops @@ -148,11 +177,13 @@ void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, } } -void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, - grpc_call_element* elem) { +void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + gpr_timespec new_deadline) { grpc_deadline_state* deadline_state = elem->call_data; - cancel_timer_if_needed(exec_ctx, deadline_state); - gpr_mu_destroy(&deadline_state->timer_mu); + gpr_mu_lock(&deadline_state->timer_mu); + cancel_timer_if_needed_locked(exec_ctx, deadline_state); + start_timer_if_needed_locked(exec_ctx, elem, new_deadline); + gpr_mu_unlock(&deadline_state->timer_mu); } void grpc_deadline_state_client_start_transport_stream_op( @@ -209,7 +240,8 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element_args* args) { // Note: size of call data is different between client and server. memset(elem->call_data, 0, elem->filter->sizeof_call_data); - grpc_deadline_state_init(exec_ctx, elem, args); + grpc_deadline_state_init(exec_ctx, elem, args->call_stack); + grpc_deadline_state_start(exec_ctx, elem, args->deadline); return GRPC_ERROR_NONE; } diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h index 685df87761..716a852565 100644 --- a/src/core/lib/channel/deadline_filter.h +++ b/src/core/lib/channel/deadline_filter.h @@ -54,18 +54,37 @@ typedef struct grpc_deadline_state { grpc_closure* next_on_complete; } grpc_deadline_state; -// To be used in a filter's init_call_elem(), destroy_call_elem(), and -// start_transport_stream_op() methods to enforce call deadlines. // -// REQUIRES: The first field in elem->call_data is a grpc_deadline_state. +// NOTE: All of these functions require that the first field in +// elem->call_data is a grpc_deadline_state. // -// For grpc_deadline_state_client_start_transport_stream_op(), it is the -// caller's responsibility to chain to the next filter if necessary -// after the function returns. + void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, - grpc_call_element_args* args); + grpc_call_stack* call_stack); void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx, grpc_call_element* elem); + +// Starts the timer with the specified deadline. +// Should be called from the filter's init_call_elem() method. +void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + gpr_timespec deadline); + +// Cancels the existing timer and starts a new one with new_deadline. +// +// Note: It is generally safe to call this with an earlier deadline +// value than the current one, but not the reverse. No checks are done +// to ensure that the timer callback is not invoked while it is in the +// process of being reset, which means that attempting to increase the +// deadline may result in the timer being called twice. +void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, + gpr_timespec new_deadline); + +// To be called from the client-side filter's start_transport_stream_op() +// method. Ensures that the deadline timer is cancelled when the call +// is completed. +// +// Note: It is the caller's responsibility to chain to the next filter if +// necessary after this function returns. void grpc_deadline_state_client_start_transport_stream_op( grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_transport_stream_op* op); diff --git a/src/core/lib/channel/handshaker.c b/src/core/lib/channel/handshaker.c index 8f9fb17a31..0d759887bc 100644 --- a/src/core/lib/channel/handshaker.c +++ b/src/core/lib/channel/handshaker.c @@ -183,7 +183,7 @@ void grpc_handshake_manager_do_handshake( gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor, grpc_handshaker_done_cb cb, void* user_data) { grpc_channel_args* args_copy = grpc_channel_args_copy(args); - gpr_slice_buffer* read_buffer = malloc(sizeof(*read_buffer)); + gpr_slice_buffer* read_buffer = gpr_malloc(sizeof(*read_buffer)); gpr_slice_buffer_init(read_buffer); if (mgr->count == 0) { // No handshakers registered, so we just immediately call the done diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c index f067a3a51c..69fb3819ff 100644 --- a/src/core/lib/channel/message_size_filter.c +++ b/src/core/lib/channel/message_size_filter.c @@ -38,6 +38,7 @@ #include <grpc/support/log.h> #include <grpc/support/string_util.h> +#include "src/core/ext/client_channel/method_config.h" #include "src/core/lib/channel/channel_args.h" #define DEFAULT_MAX_SEND_MESSAGE_LENGTH -1 // Unlimited. @@ -45,6 +46,8 @@ #define DEFAULT_MAX_RECV_MESSAGE_LENGTH (4 * 1024 * 1024) typedef struct call_data { + int max_send_size; + int max_recv_size; // Receive closures are chained: we inject this closure as the // recv_message_ready up-call on transport_stream_op, and remember to // call our next_recv_message_ready member after handling it. @@ -58,6 +61,8 @@ typedef struct call_data { typedef struct channel_data { int max_send_size; int max_recv_size; + // Method config table. + grpc_method_config_table* method_config_table; } channel_data; // Callback invoked when we receive a message. Here we check the max @@ -66,13 +71,12 @@ static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data, grpc_error* error) { grpc_call_element* elem = user_data; call_data* calld = elem->call_data; - channel_data* chand = elem->channel_data; - if (*calld->recv_message != NULL && chand->max_recv_size >= 0 && - (*calld->recv_message)->length > (size_t)chand->max_recv_size) { + if (*calld->recv_message != NULL && calld->max_recv_size >= 0 && + (*calld->recv_message)->length > (size_t)calld->max_recv_size) { char* message_string; gpr_asprintf(&message_string, "Received message larger than max (%u vs. %d)", - (*calld->recv_message)->length, chand->max_recv_size); + (*calld->recv_message)->length, calld->max_recv_size); grpc_error* new_error = grpc_error_set_int( GRPC_ERROR_CREATE(message_string), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INVALID_ARGUMENT); @@ -93,13 +97,12 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_transport_stream_op* op) { call_data* calld = elem->call_data; - channel_data* chand = elem->channel_data; // Check max send message size. - if (op->send_message != NULL && chand->max_send_size >= 0 && - op->send_message->length > (size_t)chand->max_send_size) { + if (op->send_message != NULL && calld->max_send_size >= 0 && + op->send_message->length > (size_t)calld->max_send_size) { char* message_string; gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)", - op->send_message->length, chand->max_send_size); + op->send_message->length, calld->max_send_size); gpr_slice message = gpr_slice_from_copied_string(message_string); gpr_free(message_string); grpc_call_element_send_close_with_message( @@ -119,9 +122,37 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx, static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_call_element_args* args) { + channel_data* chand = elem->channel_data; call_data* calld = elem->call_data; calld->next_recv_message_ready = NULL; grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem); + // Get max sizes from channel data, then merge in per-method config values. + // Note: Per-method config is only available on the client, so we + // apply the max request size to the send limit and the max response + // size to the receive limit. + calld->max_send_size = chand->max_send_size; + calld->max_recv_size = chand->max_recv_size; + if (chand->method_config_table != NULL) { + grpc_method_config* method_config = + grpc_method_config_table_get_method_config(chand->method_config_table, + args->path); + if (method_config != NULL) { + const int32_t* max_request_message_bytes = + grpc_method_config_get_max_request_message_bytes(method_config); + if (max_request_message_bytes != NULL && + (*max_request_message_bytes < calld->max_send_size || + calld->max_send_size < 0)) { + calld->max_send_size = *max_request_message_bytes; + } + const int32_t* max_response_message_bytes = + grpc_method_config_get_max_response_message_bytes(method_config); + if (max_response_message_bytes != NULL && + (*max_response_message_bytes < calld->max_recv_size || + calld->max_recv_size < 0)) { + calld->max_recv_size = *max_response_message_bytes; + } + } + } return GRPC_ERROR_NONE; } @@ -155,11 +186,22 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx, grpc_channel_arg_get_integer(&args->channel_args->args[i], options); } } + // Get method config table from channel args. + const grpc_arg* channel_arg = + grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG); + if (channel_arg != NULL) { + GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER); + chand->method_config_table = grpc_method_config_table_ref( + (grpc_method_config_table*)channel_arg->value.pointer.p); + } } // Destructor for channel_data. static void destroy_channel_elem(grpc_exec_ctx* exec_ctx, - grpc_channel_element* elem) {} + grpc_channel_element* elem) { + channel_data* chand = elem->channel_data; + grpc_method_config_table_unref(chand->method_config_table); +} const grpc_channel_filter grpc_message_size_filter = { start_transport_stream_op, diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c index 1ba0a5c141..c6ddc76732 100644 --- a/src/core/lib/iomgr/closure.c +++ b/src/core/lib/iomgr/closure.c @@ -35,6 +35,8 @@ #include <grpc/support/alloc.h> +#include "src/core/lib/profiling/timers.h" + void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb, void *cb_arg) { closure->cb = cb; @@ -51,7 +53,7 @@ void grpc_closure_list_append(grpc_closure_list *closure_list, GRPC_ERROR_UNREF(error); return; } - closure->error = error; + closure->error_data.error = error; closure->next_data.next = NULL; if (closure_list->head == NULL) { closure_list->head = closure; @@ -64,8 +66,8 @@ void grpc_closure_list_append(grpc_closure_list *closure_list, void grpc_closure_list_fail_all(grpc_closure_list *list, grpc_error *forced_failure) { for (grpc_closure *c = list->head; c != NULL; c = c->next_data.next) { - if (c->error == GRPC_ERROR_NONE) { - c->error = GRPC_ERROR_REF(forced_failure); + if (c->error_data.error == GRPC_ERROR_NONE) { + c->error_data.error = GRPC_ERROR_REF(forced_failure); } } GRPC_ERROR_UNREF(forced_failure); @@ -110,3 +112,13 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) { grpc_closure_init(&wc->wrapper, closure_wrapper, wc); return &wc->wrapper; } + +void grpc_closure_run(grpc_exec_ctx *exec_ctx, grpc_closure *c, + grpc_error *error) { + GPR_TIMER_BEGIN("grpc_closure_run", 0); + if (c != NULL) { + c->cb(exec_ctx, c->cb_arg, error); + } + GRPC_ERROR_UNREF(error); + GPR_TIMER_END("grpc_closure_run", 0); +} diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h index c1a22b6021..2b4b271eaa 100644 --- a/src/core/lib/iomgr/closure.h +++ b/src/core/lib/iomgr/closure.h @@ -76,7 +76,10 @@ struct grpc_closure { void *cb_arg; /** Once queued, the result of the closure. Before then: scratch space */ - grpc_error *error; + union { + grpc_error *error; + uintptr_t scratch; + } error_data; }; /** Initializes \a closure with \a cb and \a cb_arg. */ @@ -106,4 +109,10 @@ void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst); /** return whether \a list is empty. */ bool grpc_closure_list_empty(grpc_closure_list list); +/** Run a closure directly. Caller ensures that no locks are being held above. + * Note that calling this at the end of a closure callback function itself is + * by definition safe. */ +void grpc_closure_run(grpc_exec_ctx *exec_ctx, grpc_closure *closure, + grpc_error *error); + #endif /* GRPC_CORE_LIB_IOMGR_CLOSURE_H */ diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c index 831bdb4aff..60ee14eb23 100644 --- a/src/core/lib/iomgr/combiner.c +++ b/src/core/lib/iomgr/combiner.c @@ -50,25 +50,57 @@ int grpc_combiner_trace = 0; } \ } while (0) +#define STATE_UNORPHANED 1 +#define STATE_ELEM_COUNT_LOW_BIT 2 + struct grpc_combiner { + grpc_combiner *next_combiner_on_this_exec_ctx; grpc_workqueue *optional_workqueue; gpr_mpscq queue; // state is: - // lower bit - zero if orphaned - // other bits - number of items queued on the lock + // lower bit - zero if orphaned (STATE_UNORPHANED) + // other bits - number of items queued on the lock (STATE_ELEM_COUNT_LOW_BIT) gpr_atm state; - bool take_async_break_before_final_list; + // number of elements in the list that are covered by a poller: if >0, we can + // offload safely + gpr_atm elements_covered_by_poller; + bool time_to_execute_final_list; + bool final_list_covered_by_poller; grpc_closure_list final_list; - grpc_closure continue_finishing; + grpc_closure offload; }; +static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); + +typedef struct { + grpc_error *error; + bool covered_by_poller; +} error_data; + +static uintptr_t pack_error_data(error_data d) { + return ((uintptr_t)d.error) | (d.covered_by_poller ? 1 : 0); +} + +static error_data unpack_error_data(uintptr_t p) { + return (error_data){(grpc_error *)(p & ~(uintptr_t)1), p & 1}; +} + +static bool is_covered_by_poller(grpc_combiner *lock) { + return lock->final_list_covered_by_poller || + gpr_atm_acq_load(&lock->elements_covered_by_poller) > 0; +} + grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { grpc_combiner *lock = gpr_malloc(sizeof(*lock)); + lock->next_combiner_on_this_exec_ctx = NULL; + lock->time_to_execute_final_list = false; lock->optional_workqueue = optional_workqueue; - gpr_atm_no_barrier_store(&lock->state, 1); + lock->final_list_covered_by_poller = false; + gpr_atm_no_barrier_store(&lock->state, STATE_UNORPHANED); + gpr_atm_no_barrier_store(&lock->elements_covered_by_poller, 0); gpr_mpscq_init(&lock->queue); - lock->take_async_break_before_final_list = false; grpc_closure_list_init(&lock->final_list); + grpc_closure_init(&lock->offload, offload, lock); GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p create", lock)); return lock; } @@ -82,7 +114,7 @@ static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { } void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { - gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -1); + gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -STATE_UNORPHANED); GRPC_COMBINER_TRACE(gpr_log( GPR_DEBUG, "C:%p really_destroy old_state=%" PRIdPTR, lock, old_state)); if (old_state == 1) { @@ -90,170 +122,186 @@ void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { } } -static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); -static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); +static void push_last_on_exec_ctx(grpc_exec_ctx *exec_ctx, + grpc_combiner *lock) { + lock->next_combiner_on_this_exec_ctx = NULL; + if (exec_ctx->active_combiner == NULL) { + exec_ctx->active_combiner = exec_ctx->last_combiner = lock; + } else { + exec_ctx->last_combiner->next_combiner_on_this_exec_ctx = lock; + exec_ctx->last_combiner = lock; + } +} -static void continue_finishing_mainline(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - GPR_TIMER_BEGIN("combiner.continue_executing_mainline", 0); - grpc_combiner *lock = arg; - GRPC_COMBINER_TRACE( - gpr_log(GPR_DEBUG, "C:%p continue_finishing_mainline", lock)); - GPR_ASSERT(exec_ctx->active_combiner == NULL); +static void push_first_on_exec_ctx(grpc_exec_ctx *exec_ctx, + grpc_combiner *lock) { + lock->next_combiner_on_this_exec_ctx = exec_ctx->active_combiner; exec_ctx->active_combiner = lock; - if (maybe_finish_one(exec_ctx, lock)) finish(exec_ctx, lock); - GPR_ASSERT(exec_ctx->active_combiner == lock); - exec_ctx->active_combiner = NULL; - GPR_TIMER_END("combiner.continue_executing_mainline", 0); + if (lock->next_combiner_on_this_exec_ctx == NULL) { + exec_ctx->last_combiner = lock; + } } -static void execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { - GPR_TIMER_BEGIN("combiner.execute_final", 0); - grpc_closure *c = lock->final_list.head; - GPR_ASSERT(c != NULL); - grpc_closure_list_init(&lock->final_list); - lock->take_async_break_before_final_list = false; - int loops = 0; - while (c != NULL) { - GRPC_COMBINER_TRACE( - gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c)); - grpc_closure *next = c->next_data.next; - grpc_error *error = c->error; - c->cb(exec_ctx, c->cb_arg, error); - GRPC_ERROR_UNREF(error); - c = next; - loops++; +void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, + grpc_closure *cl, grpc_error *error, + bool covered_by_poller) { + GPR_TIMER_BEGIN("combiner.execute", 0); + gpr_atm last = gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT); + GRPC_COMBINER_TRACE(gpr_log( + GPR_DEBUG, "C:%p grpc_combiner_execute c=%p cov=%d last=%" PRIdPTR, lock, + cl, covered_by_poller, last)); + GPR_ASSERT(last & STATE_UNORPHANED); // ensure lock has not been destroyed + cl->error_data.scratch = + pack_error_data((error_data){error, covered_by_poller}); + if (covered_by_poller) { + gpr_atm_no_barrier_fetch_add(&lock->elements_covered_by_poller, 1); + } + gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); + if (last == 1) { + // first element on this list: add it to the list of combiner locks + // executing within this exec_ctx + push_last_on_exec_ctx(exec_ctx, lock); } - GPR_TIMER_END("combiner.execute_final", 0); + GPR_TIMER_END("combiner.execute", 0); } -static void continue_executing_final(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error) { - GPR_TIMER_BEGIN("combiner.continue_executing_final", 0); - grpc_combiner *lock = arg; - GRPC_COMBINER_TRACE( - gpr_log(GPR_DEBUG, "C:%p continue_executing_final", lock)); - GPR_ASSERT(exec_ctx->active_combiner == NULL); - exec_ctx->active_combiner = lock; - // quick peek to see if new things have turned up on the queue: if so, go back - // to executing them before the final list - if ((gpr_atm_acq_load(&lock->state) >> 1) > 1) { - if (maybe_finish_one(exec_ctx, lock)) finish(exec_ctx, lock); - } else { - execute_final(exec_ctx, lock); - finish(exec_ctx, lock); +static void move_next(grpc_exec_ctx *exec_ctx) { + exec_ctx->active_combiner = + exec_ctx->active_combiner->next_combiner_on_this_exec_ctx; + if (exec_ctx->active_combiner == NULL) { + exec_ctx->last_combiner = NULL; } - GPR_ASSERT(exec_ctx->active_combiner == lock); - exec_ctx->active_combiner = NULL; - GPR_TIMER_END("combiner.continue_executing_final", 0); } -static bool start_execute_final(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { - GPR_TIMER_BEGIN("combiner.start_execute_final", 0); - GPR_ASSERT(exec_ctx->active_combiner == lock); - GRPC_COMBINER_TRACE( - gpr_log(GPR_DEBUG, - "C:%p start_execute_final take_async_break_before_final_list=%d", - lock, lock->take_async_break_before_final_list)); - if (lock->take_async_break_before_final_list) { - grpc_closure_init(&lock->continue_finishing, continue_executing_final, - lock); - grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, - GRPC_WORKQUEUE_REF(lock->optional_workqueue, "sched")); - GPR_TIMER_END("combiner.start_execute_final", 0); +static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { + grpc_combiner *lock = arg; + push_last_on_exec_ctx(exec_ctx, lock); +} + +static void queue_offload(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { + move_next(exec_ctx); + GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p queue_offload --> %p", lock, + lock->optional_workqueue)); + grpc_workqueue_enqueue(exec_ctx, lock->optional_workqueue, &lock->offload, + GRPC_ERROR_NONE); +} + +bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) { + GPR_TIMER_BEGIN("combiner.continue_exec_ctx", 0); + grpc_combiner *lock = exec_ctx->active_combiner; + if (lock == NULL) { + GPR_TIMER_END("combiner.continue_exec_ctx", 0); return false; - } else { - execute_final(exec_ctx, lock); - GPR_TIMER_END("combiner.start_execute_final", 0); - return true; } -} -static bool maybe_finish_one(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { - GPR_TIMER_BEGIN("combiner.maybe_finish_one", 0); - gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); GRPC_COMBINER_TRACE( - gpr_log(GPR_DEBUG, "C:%p maybe_finish_one n=%p", lock, n)); - GPR_ASSERT(exec_ctx->active_combiner == lock); - if (n == NULL) { - // Queue is in an transiently inconsistent state: a new item is being queued - // but is not visible to this thread yet. - // Use this as a cue that we should go off and do something else for a while - // (and come back later) - grpc_closure_init(&lock->continue_finishing, continue_finishing_mainline, - lock); - grpc_exec_ctx_sched(exec_ctx, &lock->continue_finishing, GRPC_ERROR_NONE, - GRPC_WORKQUEUE_REF(lock->optional_workqueue, "sched")); - GPR_TIMER_END("combiner.maybe_finish_one", 0); - return false; + gpr_log(GPR_DEBUG, + "C:%p grpc_combiner_continue_exec_ctx workqueue=%p " + "is_covered_by_poller=%d exec_ctx_ready_to_finish=%d " + "time_to_execute_final_list=%d", + lock, lock->optional_workqueue, is_covered_by_poller(lock), + grpc_exec_ctx_ready_to_finish(exec_ctx), + lock->time_to_execute_final_list)); + + if (lock->optional_workqueue != NULL && is_covered_by_poller(lock) && + grpc_exec_ctx_ready_to_finish(exec_ctx)) { + GPR_TIMER_MARK("offload_from_finished_exec_ctx", 0); + // this execution context wants to move on, and we have a workqueue (and + // so can help the execution context out): schedule remaining work to be + // picked up on the workqueue + queue_offload(exec_ctx, lock); + GPR_TIMER_END("combiner.continue_exec_ctx", 0); + return true; } - grpc_closure *cl = (grpc_closure *)n; - grpc_error *error = cl->error; - cl->cb(exec_ctx, cl->cb_arg, error); - GRPC_ERROR_UNREF(error); - GPR_TIMER_END("combiner.maybe_finish_one", 0); - return true; -} -static void finish(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { - bool (*executor)(grpc_exec_ctx * exec_ctx, grpc_combiner * lock); - GPR_TIMER_BEGIN("combiner.finish", 0); - int loops = 0; - do { - executor = maybe_finish_one; - gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -2); - GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, - "C:%p finish[%d] old_state=%" PRIdPTR, lock, - loops, old_state)); - switch (old_state) { - default: - // we have multiple queued work items: just continue executing them - break; - case 5: // we're down to one queued item: if it's the final list we - case 4: // should do that - if (!grpc_closure_list_empty(lock->final_list)) { - executor = start_execute_final; - } - break; - case 3: // had one count, one unorphaned --> unlocked unorphaned - GPR_TIMER_END("combiner.finish", 0); - return; - case 2: // and one count, one orphaned --> unlocked and orphaned - really_destroy(exec_ctx, lock); - GPR_TIMER_END("combiner.finish", 0); - return; - case 1: - case 0: - // these values are illegal - representing an already unlocked or - // deleted lock - GPR_UNREACHABLE_CODE(return ); + if (!lock->time_to_execute_final_list || + // peek to see if something new has shown up, and execute that with + // priority + (gpr_atm_acq_load(&lock->state) >> 1) > 1) { + gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); + GRPC_COMBINER_TRACE( + gpr_log(GPR_DEBUG, "C:%p maybe_finish_one n=%p", lock, n)); + if (n == NULL) { + // queue is in an inconsistent state: use this as a cue that we should + // go off and do something else for a while (and come back later) + GPR_TIMER_MARK("delay_busy", 0); + if (lock->optional_workqueue != NULL && is_covered_by_poller(lock)) { + queue_offload(exec_ctx, lock); + } + GPR_TIMER_END("combiner.continue_exec_ctx", 0); + return true; } - loops++; - } while (executor(exec_ctx, lock)); - GPR_TIMER_END("combiner.finish", 0); -} + GPR_TIMER_BEGIN("combiner.exec1", 0); + grpc_closure *cl = (grpc_closure *)n; + error_data err = unpack_error_data(cl->error_data.scratch); + cl->cb(exec_ctx, cl->cb_arg, err.error); + if (err.covered_by_poller) { + gpr_atm_no_barrier_fetch_add(&lock->elements_covered_by_poller, -1); + } + GRPC_ERROR_UNREF(err.error); + GPR_TIMER_END("combiner.exec1", 0); + } else { + grpc_closure *c = lock->final_list.head; + GPR_ASSERT(c != NULL); + grpc_closure_list_init(&lock->final_list); + lock->final_list_covered_by_poller = false; + int loops = 0; + while (c != NULL) { + GPR_TIMER_BEGIN("combiner.exec_1final", 0); + GRPC_COMBINER_TRACE( + gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c)); + grpc_closure *next = c->next_data.next; + grpc_error *error = c->error_data.error; + c->cb(exec_ctx, c->cb_arg, error); + GRPC_ERROR_UNREF(error); + c = next; + GPR_TIMER_END("combiner.exec_1final", 0); + } + } -void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, - grpc_closure *cl, grpc_error *error) { + GPR_TIMER_MARK("unref", 0); + move_next(exec_ctx); + lock->time_to_execute_final_list = false; + gpr_atm old_state = + gpr_atm_full_fetch_add(&lock->state, -STATE_ELEM_COUNT_LOW_BIT); GRPC_COMBINER_TRACE( - gpr_log(GPR_DEBUG, "C:%p grpc_combiner_execute c=%p", lock, cl)); - GPR_TIMER_BEGIN("combiner.execute", 0); - gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); - GPR_ASSERT(last & 1); // ensure lock has not been destroyed - if (last == 1) { - exec_ctx->active_combiner = lock; - GPR_TIMER_BEGIN("combiner.execute_first_cb", 0); - cl->cb(exec_ctx, cl->cb_arg, error); - GPR_TIMER_END("combiner.execute_first_cb", 0); - GRPC_ERROR_UNREF(error); - finish(exec_ctx, lock); - GPR_ASSERT(exec_ctx->active_combiner == lock); - exec_ctx->active_combiner = NULL; - } else { - cl->error = error; - gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); + gpr_log(GPR_DEBUG, "C:%p finish old_state=%" PRIdPTR, lock, old_state)); +// Define a macro to ease readability of the following switch statement. +#define OLD_STATE_WAS(orphaned, elem_count) \ + (((orphaned) ? 0 : STATE_UNORPHANED) | \ + ((elem_count)*STATE_ELEM_COUNT_LOW_BIT)) + // Depending on what the previous state was, we need to perform different + // actions. + switch (old_state) { + default: + // we have multiple queued work items: just continue executing them + break; + case OLD_STATE_WAS(false, 2): + case OLD_STATE_WAS(true, 2): + // we're down to one queued item: if it's the final list we should do that + if (!grpc_closure_list_empty(lock->final_list)) { + lock->time_to_execute_final_list = true; + } + break; + case OLD_STATE_WAS(false, 1): + // had one count, one unorphaned --> unlocked unorphaned + GPR_TIMER_END("combiner.continue_exec_ctx", 0); + return true; + case OLD_STATE_WAS(true, 1): + // and one count, one orphaned --> unlocked and orphaned + really_destroy(exec_ctx, lock); + GPR_TIMER_END("combiner.continue_exec_ctx", 0); + return true; + case OLD_STATE_WAS(false, 0): + case OLD_STATE_WAS(true, 0): + // these values are illegal - representing an already unlocked or + // deleted lock + GPR_TIMER_END("combiner.continue_exec_ctx", 0); + GPR_UNREACHABLE_CODE(return true); } - GPR_TIMER_END("combiner.execute", 0); + push_first_on_exec_ctx(exec_ctx, lock); + GPR_TIMER_END("combiner.continue_exec_ctx", 0); + return true; } static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, @@ -264,30 +312,26 @@ static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error, - bool force_async_break) { + bool covered_by_poller) { GRPC_COMBINER_TRACE(gpr_log( - GPR_DEBUG, - "C:%p grpc_combiner_execute_finally c=%p force_async_break=%d; ac=%p", - lock, closure, force_async_break, exec_ctx->active_combiner)); + GPR_DEBUG, "C:%p grpc_combiner_execute_finally c=%p; ac=%p; cov=%d", lock, + closure, exec_ctx->active_combiner, covered_by_poller)); GPR_TIMER_BEGIN("combiner.execute_finally", 0); if (exec_ctx->active_combiner != lock) { GPR_TIMER_MARK("slowpath", 0); grpc_combiner_execute(exec_ctx, lock, - grpc_closure_create(enqueue_finally, closure), error); + grpc_closure_create(enqueue_finally, closure), error, + false); GPR_TIMER_END("combiner.execute_finally", 0); return; } - if (force_async_break) { - lock->take_async_break_before_final_list = true; - } if (grpc_closure_list_empty(lock->final_list)) { - gpr_atm_full_fetch_add(&lock->state, 2); + gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT); + } + if (covered_by_poller) { + lock->final_list_covered_by_poller = true; } grpc_closure_list_append(&lock->final_list, closure, error); GPR_TIMER_END("combiner.execute_finally", 0); } - -void grpc_combiner_force_async_finally(grpc_combiner *lock) { - lock->take_async_break_before_final_list = true; -} diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index 1409db24b9..d04eeed83a 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -52,19 +52,14 @@ grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue); void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); // Execute \a action within the lock. void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, - grpc_closure *closure, grpc_error *error); + grpc_closure *closure, grpc_error *error, + bool covered_by_poller); // Execute \a action within the lock just prior to unlocking. -// if \a hint_async_break is true, the combiner tries to hand execution to -// another thread before finishing the primary queue of combined closures and -// executing the finally list. -// Deprecation warning: \a hint_async_break will be removed in a future version -// Takes a very slow and round-about path if not called from a -// grpc_combiner_execute closure. void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, grpc_closure *closure, grpc_error *error, - bool hint_async_break); -// Deprecated: force the finally list execution onto another thread -void grpc_combiner_force_async_finally(grpc_combiner *lock); + bool covered_by_poller); + +bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx); extern int grpc_combiner_trace; diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c index 31c80260f8..f6bb3a0477 100644 --- a/src/core/lib/iomgr/error.c +++ b/src/core/lib/iomgr/error.c @@ -120,6 +120,8 @@ static const char *error_int_name(grpc_error_ints key) { return "http_status"; case GRPC_ERROR_INT_LIMIT: return "limit"; + case GRPC_ERROR_INT_OCCURRED_DURING_WRITE: + return "occurred_during_write"; } GPR_UNREACHABLE_CODE(return "unknown"); } @@ -144,6 +146,8 @@ static const char *error_str_name(grpc_error_strs key) { return "tsi_error"; case GRPC_ERROR_STR_FILENAME: return "filename"; + case GRPC_ERROR_STR_QUEUED_BUFFERS: + return "queued_buffers"; } GPR_UNREACHABLE_CODE(return "unknown"); } @@ -265,7 +269,7 @@ static grpc_error *copy_error_and_unref(grpc_error *in) { } else { out = gpr_malloc(sizeof(*out)); #ifdef GRPC_ERROR_REFCOUNT_DEBUG - gpr_log(GPR_DEBUG, "%p create copying", out); + gpr_log(GPR_DEBUG, "%p create copying %p", out, in); #endif out->ints = gpr_avl_ref(in->ints); out->strs = gpr_avl_ref(in->strs); @@ -523,21 +527,25 @@ static char *fmt_time(void *p) { return out; } -static void add_errs(gpr_avl_node *n, char **s, size_t *sz, size_t *cap) { +static void add_errs(gpr_avl_node *n, char **s, size_t *sz, size_t *cap, + bool *first) { if (n == NULL) return; - add_errs(n->left, s, sz, cap); + add_errs(n->left, s, sz, cap, first); + if (!*first) append_chr(',', s, sz, cap); + *first = false; const char *e = grpc_error_string(n->value); append_str(e, s, sz, cap); grpc_error_free_string(e); - add_errs(n->right, s, sz, cap); + add_errs(n->right, s, sz, cap, first); } static char *errs_string(grpc_error *err) { char *s = NULL; size_t sz = 0; size_t cap = 0; + bool first = true; append_chr('[', &s, &sz, &cap); - add_errs(err->errs.root, &s, &sz, &cap); + add_errs(err->errs.root, &s, &sz, &cap, &first); append_chr(']', &s, &sz, &cap); append_chr(0, &s, &sz, &cap); return s; diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h index 00ace8a7a9..f3f3b80a09 100644 --- a/src/core/lib/iomgr/error.h +++ b/src/core/lib/iomgr/error.h @@ -100,6 +100,8 @@ typedef enum { GRPC_ERROR_INT_HTTP_STATUS, /// context sensitive limit associated with the error GRPC_ERROR_INT_LIMIT, + /// chttp2: did the error occur while a write was in progress + GRPC_ERROR_INT_OCCURRED_DURING_WRITE, } grpc_error_ints; typedef enum { @@ -121,6 +123,8 @@ typedef enum { GRPC_ERROR_STR_TSI_ERROR, /// filename that we were trying to read/write when this error occurred GRPC_ERROR_STR_FILENAME, + /// which data was queued for writing when the error occurred + GRPC_ERROR_STR_QUEUED_BUFFERS } grpc_error_strs; typedef enum { @@ -128,9 +132,13 @@ typedef enum { GRPC_ERROR_TIME_CREATED, } grpc_error_times; +/// The following "special" errors can be propagated without allocating memory. +/// They are always even so that other code (particularly combiner locks) can +/// safely use the lower bit for themselves. + #define GRPC_ERROR_NONE ((grpc_error *)NULL) -#define GRPC_ERROR_OOM ((grpc_error *)1) -#define GRPC_ERROR_CANCELLED ((grpc_error *)2) +#define GRPC_ERROR_OOM ((grpc_error *)2) +#define GRPC_ERROR_CANCELLED ((grpc_error *)4) const char *grpc_error_string(grpc_error *error); void grpc_error_free_string(const char *str); diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c index ab77ebc78b..e5909d9380 100644 --- a/src/core/lib/iomgr/ev_epoll_linux.c +++ b/src/core/lib/iomgr/ev_epoll_linux.c @@ -152,20 +152,20 @@ static void fd_global_shutdown(void); * Polling island Declarations */ -//#define GRPC_PI_REF_COUNT_DEBUG -#ifdef GRPC_PI_REF_COUNT_DEBUG +#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG #define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__) #define PI_UNREF(exec_ctx, p, r) \ pi_unref_dbg((exec_ctx), (p), (r), __FILE__, __LINE__) -#else /* defined(GRPC_PI_REF_COUNT_DEBUG) */ +#else /* defined(GRPC_WORKQUEUE_REFCOUNT_DEBUG) */ #define PI_ADD_REF(p, r) pi_add_ref((p)) #define PI_UNREF(exec_ctx, p, r) pi_unref((exec_ctx), (p)) #endif /* !defined(GPRC_PI_REF_COUNT_DEBUG) */ +/* This is also used as grpc_workqueue (by directly casing it) */ typedef struct polling_island { gpr_mu mu; /* Ref count. Use PI_ADD_REF() and PI_UNREF() macros to increment/decrement @@ -185,8 +185,17 @@ typedef struct polling_island { * (except mu and ref_count) are invalid and must be ignored. */ gpr_atm merged_to; - /* The workqueue associated with this polling island */ - grpc_workqueue *workqueue; + /* Number of threads currently polling on this island */ + gpr_atm poller_count; + /* Mutex guarding the read end of the workqueue (must be held to pop from + * workqueue_items) */ + gpr_mu workqueue_read_mu; + /* Queue of closures to be executed */ + gpr_mpscq workqueue_items; + /* Count of items in workqueue_items */ + gpr_atm workqueue_item_count; + /* Wakeup fd used to wake pollers to check the contents of workqueue_items */ + grpc_wakeup_fd workqueue_wakeup_fd; /* The fd of the underlying epoll set */ int epoll_fd; @@ -275,6 +284,10 @@ static bool append_error(grpc_error **composite, grpc_error *error, threads that woke up MUST NOT call grpc_wakeup_fd_consume_wakeup() */ static grpc_wakeup_fd polling_island_wakeup_fd; +/* The polling island being polled right now. + See comments in workqueue_maybe_wakeup for why this is tracked. */ +static __thread polling_island *g_current_thread_polling_island; + /* Forward declaration */ static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi); @@ -289,12 +302,12 @@ static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi); gpr_atm g_epoll_sync; #endif /* defined(GRPC_TSAN) */ -#ifdef GRPC_PI_REF_COUNT_DEBUG static void pi_add_ref(polling_island *pi); static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi); -static void pi_add_ref_dbg(polling_island *pi, char *reason, char *file, - int line) { +#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG +static void pi_add_ref_dbg(polling_island *pi, const char *reason, + const char *file, int line) { long old_cnt = gpr_atm_acq_load(&pi->ref_count); pi_add_ref(pi); gpr_log(GPR_DEBUG, "Add ref pi: %p, old: %ld -> new:%ld (%s) - (%s, %d)", @@ -302,12 +315,42 @@ static void pi_add_ref_dbg(polling_island *pi, char *reason, char *file, } static void pi_unref_dbg(grpc_exec_ctx *exec_ctx, polling_island *pi, - char *reason, char *file, int line) { + const char *reason, const char *file, int line) { long old_cnt = gpr_atm_acq_load(&pi->ref_count); pi_unref(exec_ctx, pi); gpr_log(GPR_DEBUG, "Unref pi: %p, old:%ld -> new:%ld (%s) - (%s, %d)", (void *)pi, old_cnt, (old_cnt - 1), reason, file, line); } + +static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue, + const char *file, int line, + const char *reason) { + if (workqueue != NULL) { + pi_add_ref_dbg((polling_island *)workqueue, reason, file, line); + } + return workqueue; +} + +static void workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, + const char *file, int line, const char *reason) { + if (workqueue != NULL) { + pi_unref_dbg(exec_ctx, (polling_island *)workqueue, reason, file, line); + } +} +#else +static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue) { + if (workqueue != NULL) { + pi_add_ref((polling_island *)workqueue); + } + return workqueue; +} + +static void workqueue_unref(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue) { + if (workqueue != NULL) { + pi_unref(exec_ctx, (polling_island *)workqueue); + } +} #endif static void pi_add_ref(polling_island *pi) { @@ -315,10 +358,7 @@ static void pi_add_ref(polling_island *pi) { } static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi) { - /* If ref count went to one, we're back to just the workqueue owning a ref. - Unref the workqueue to break the loop. - - If ref count went to zero, delete the polling island. + /* If ref count went to zero, delete the polling island. Note that this deletion not be done under a lock. Once the ref count goes to zero, we are guaranteed that no one else holds a reference to the polling island (and that there is no racing pi_add_ref() call either). @@ -326,20 +366,12 @@ static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi) { Also, if we are deleting the polling island and the merged_to field is non-empty, we should remove a ref to the merged_to polling island */ - switch (gpr_atm_full_fetch_add(&pi->ref_count, -1)) { - case 2: /* last external ref: the only one now owned is by the workqueue */ - GRPC_WORKQUEUE_UNREF(exec_ctx, pi->workqueue, "polling_island"); - break; - case 1: { - polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to); - polling_island_delete(exec_ctx, pi); - if (next != NULL) { - PI_UNREF(exec_ctx, next, "pi_delete"); /* Recursive call */ - } - break; + if (1 == gpr_atm_full_fetch_add(&pi->ref_count, -1)) { + polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to); + polling_island_delete(exec_ctx, pi); + if (next != NULL) { + PI_UNREF(exec_ctx, next, "pi_delete"); /* Recursive call */ } - case 0: - GPR_UNREACHABLE_CODE(return ); } } @@ -488,11 +520,20 @@ static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx, pi->fd_capacity = 0; pi->fds = NULL; pi->epoll_fd = -1; - pi->workqueue = NULL; + + gpr_mu_init(&pi->workqueue_read_mu); + gpr_mpscq_init(&pi->workqueue_items); + gpr_atm_rel_store(&pi->workqueue_item_count, 0); gpr_atm_rel_store(&pi->ref_count, 0); + gpr_atm_rel_store(&pi->poller_count, 0); gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL); + if (!append_error(error, grpc_wakeup_fd_init(&pi->workqueue_wakeup_fd), + err_desc)) { + goto done; + } + pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (pi->epoll_fd < 0) { @@ -501,26 +542,14 @@ static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx, } polling_island_add_wakeup_fd_locked(pi, &grpc_global_wakeup_fd, error); + polling_island_add_wakeup_fd_locked(pi, &pi->workqueue_wakeup_fd, error); if (initial_fd != NULL) { polling_island_add_fds_locked(pi, &initial_fd, 1, true, error); } - if (append_error(error, grpc_workqueue_create(exec_ctx, &pi->workqueue), - err_desc) && - *error == GRPC_ERROR_NONE) { - polling_island_add_fds_locked(pi, &pi->workqueue->wakeup_read_fd, 1, true, - error); - GPR_ASSERT(pi->workqueue->wakeup_read_fd->polling_island == NULL); - pi->workqueue->wakeup_read_fd->polling_island = pi; - PI_ADD_REF(pi, "fd"); - } - done: if (*error != GRPC_ERROR_NONE) { - if (pi->workqueue != NULL) { - GRPC_WORKQUEUE_UNREF(exec_ctx, pi->workqueue, "polling_island"); - } polling_island_delete(exec_ctx, pi); pi = NULL; } @@ -533,7 +562,11 @@ static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi) { if (pi->epoll_fd >= 0) { close(pi->epoll_fd); } + GPR_ASSERT(gpr_atm_no_barrier_load(&pi->workqueue_item_count) == 0); + gpr_mu_destroy(&pi->workqueue_read_mu); + gpr_mpscq_destroy(&pi->workqueue_items); gpr_mu_destroy(&pi->mu); + grpc_wakeup_fd_destroy(&pi->workqueue_wakeup_fd); gpr_free(pi->fds); gpr_free(pi); } @@ -678,6 +711,45 @@ static void polling_island_unlock_pair(polling_island *p, polling_island *q) { } } +static void workqueue_maybe_wakeup(polling_island *pi) { + /* If this thread is the current poller, then it may be that it's about to + decrement the current poller count, so we need to look past this thread */ + bool is_current_poller = (g_current_thread_polling_island == pi); + gpr_atm min_current_pollers_for_wakeup = is_current_poller ? 1 : 0; + gpr_atm current_pollers = gpr_atm_no_barrier_load(&pi->poller_count); + /* Only issue a wakeup if it's likely that some poller could come in and take + it right now. Note that since we do an anticipatory mpscq_pop every poll + loop, it's ok if we miss the wakeup here, as we'll get the work item when + the next poller enters anyway. */ + if (current_pollers > min_current_pollers_for_wakeup) { + GRPC_LOG_IF_ERROR("workqueue_wakeup_fd", + grpc_wakeup_fd_wakeup(&pi->workqueue_wakeup_fd)); + } +} + +static void workqueue_move_items_to_parent(polling_island *q) { + polling_island *p = (polling_island *)gpr_atm_no_barrier_load(&q->merged_to); + if (p == NULL) { + return; + } + gpr_mu_lock(&q->workqueue_read_mu); + int num_added = 0; + while (gpr_atm_no_barrier_load(&q->workqueue_item_count) > 0) { + gpr_mpscq_node *n = gpr_mpscq_pop(&q->workqueue_items); + if (n != NULL) { + gpr_atm_no_barrier_fetch_add(&q->workqueue_item_count, -1); + gpr_atm_no_barrier_fetch_add(&p->workqueue_item_count, 1); + gpr_mpscq_push(&p->workqueue_items, n); + num_added++; + } + } + gpr_mu_unlock(&q->workqueue_read_mu); + if (num_added > 0) { + workqueue_maybe_wakeup(p); + } + workqueue_move_items_to_parent(p); +} + static polling_island *polling_island_merge(polling_island *p, polling_island *q, grpc_error **error) { @@ -702,6 +774,8 @@ static polling_island *polling_island_merge(polling_island *p, /* Add the 'merged_to' link from p --> q */ gpr_atm_rel_store(&p->merged_to, (gpr_atm)q); PI_ADD_REF(q, "pi_merge"); /* To account for the new incoming ref from p */ + + workqueue_move_items_to_parent(q); } /* else if p == q, nothing needs to be done */ @@ -712,6 +786,26 @@ static polling_island *polling_island_merge(polling_island *p, return q; } +static void workqueue_enqueue(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue, grpc_closure *closure, + grpc_error *error) { + GPR_TIMER_BEGIN("workqueue.enqueue", 0); + /* take a ref to the workqueue: otherwise it can happen that whatever events + * this kicks off ends up destroying the workqueue before this function + * completes */ + GRPC_WORKQUEUE_REF(workqueue, "enqueue"); + polling_island *pi = (polling_island *)workqueue; + gpr_atm last = gpr_atm_no_barrier_fetch_add(&pi->workqueue_item_count, 1); + closure->error_data.error = error; + gpr_mpscq_push(&pi->workqueue_items, &closure->next_data.atm_next); + if (last == 0) { + workqueue_maybe_wakeup(pi); + } + workqueue_move_items_to_parent(pi); + GRPC_WORKQUEUE_UNREF(exec_ctx, workqueue, "enqueue"); + GPR_TIMER_END("workqueue.enqueue", 0); +} + static grpc_error *polling_island_global_init() { grpc_error *error = GRPC_ERROR_NONE; @@ -1042,11 +1136,8 @@ static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd, static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { gpr_mu_lock(&fd->mu); - grpc_workqueue *workqueue = NULL; - if (fd->polling_island != NULL) { - workqueue = - GRPC_WORKQUEUE_REF(fd->polling_island->workqueue, "get_workqueue"); - } + grpc_workqueue *workqueue = GRPC_WORKQUEUE_REF( + (grpc_workqueue *)fd->polling_island, "fd_get_workqueue"); gpr_mu_unlock(&fd->mu); return workqueue; } @@ -1299,7 +1390,29 @@ static void pollset_reset(grpc_pollset *pollset) { GPR_ASSERT(pollset->polling_island == NULL); } -#define GRPC_EPOLL_MAX_EVENTS 1000 +static bool maybe_do_workqueue_work(grpc_exec_ctx *exec_ctx, + polling_island *pi) { + if (gpr_mu_trylock(&pi->workqueue_read_mu)) { + gpr_mpscq_node *n = gpr_mpscq_pop(&pi->workqueue_items); + gpr_mu_unlock(&pi->workqueue_read_mu); + if (n != NULL) { + if (gpr_atm_full_fetch_add(&pi->workqueue_item_count, -1) > 1) { + workqueue_maybe_wakeup(pi); + } + grpc_closure *c = (grpc_closure *)n; + grpc_closure_run(exec_ctx, c, c->error_data.error); + return true; + } else if (gpr_atm_no_barrier_load(&pi->workqueue_item_count) > 0) { + /* n == NULL might mean there's work but it's not available to be popped + * yet - try to ensure another workqueue wakes up to check shortly if so + */ + workqueue_maybe_wakeup(pi); + } + } + return false; +} + +#define GRPC_EPOLL_MAX_EVENTS 100 /* Note: sig_mask contains the signal mask to use *during* epoll_wait() */ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, @@ -1354,7 +1467,13 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx, PI_ADD_REF(pi, "ps_work"); gpr_mu_unlock(&pollset->mu); - do { + /* If we get some workqueue work to do, it might end up completing an item on + the completion queue, so there's no need to poll... so we skip that and + redo the complete loop to verify */ + if (!maybe_do_workqueue_work(exec_ctx, pi)) { + gpr_atm_no_barrier_fetch_add(&pi->poller_count, 1); + g_current_thread_polling_island = pi; + GRPC_SCHEDULING_START_BLOCKING_REGION; ep_rv = epoll_pwait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms, sig_mask); @@ -1386,6 +1505,11 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx, append_error(error, grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd), err_desc); + } else if (data_ptr == &pi->workqueue_wakeup_fd) { + append_error(error, + grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd), + err_desc); + maybe_do_workqueue_work(exec_ctx, pi); } else if (data_ptr == &polling_island_wakeup_fd) { GRPC_POLLING_TRACE( "pollset_work: pollset: %p, worker: %p polling island (epoll_fd: " @@ -1408,7 +1532,10 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx, } } } - } while (ep_rv == GRPC_EPOLL_MAX_EVENTS); + + g_current_thread_polling_island = NULL; + gpr_atm_no_barrier_fetch_add(&pi->poller_count, -1); + } GPR_ASSERT(pi != NULL); @@ -1868,6 +1995,10 @@ static const grpc_event_engine_vtable vtable = { .kick_poller = kick_poller, + .workqueue_ref = workqueue_ref, + .workqueue_unref = workqueue_unref, + .workqueue_enqueue = workqueue_enqueue, + .shutdown_engine = shutdown_engine, }; @@ -1892,6 +2023,10 @@ const grpc_event_engine_vtable *grpc_init_epoll_linux(void) { return NULL; } + if (!grpc_has_wakeup_fd()) { + return NULL; + } + if (!is_epoll_available()) { return NULL; } diff --git a/src/core/lib/iomgr/ev_poll_and_epoll_posix.c b/src/core/lib/iomgr/ev_poll_and_epoll_posix.c index c2107e5e39..1829440a6e 100644 --- a/src/core/lib/iomgr/ev_poll_and_epoll_posix.c +++ b/src/core/lib/iomgr/ev_poll_and_epoll_posix.c @@ -1989,6 +1989,32 @@ static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, } /******************************************************************************* + * workqueue stubs + */ + +#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG +static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue, + const char *file, int line, + const char *reason) { + return workqueue; +} +static void workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, + const char *file, int line, const char *reason) {} +#else +static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue) { + return workqueue; +} +static void workqueue_unref(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue) {} +#endif + +static void workqueue_enqueue(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue, grpc_closure *closure, + grpc_error *error) { + grpc_exec_ctx_sched(exec_ctx, closure, error, NULL); +} + +/******************************************************************************* * event engine binding */ @@ -2029,6 +2055,10 @@ static const grpc_event_engine_vtable vtable = { .kick_poller = kick_poller, + .workqueue_ref = workqueue_ref, + .workqueue_unref = workqueue_unref, + .workqueue_enqueue = workqueue_enqueue, + .shutdown_engine = shutdown_engine, }; diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c index 16a5e3083e..27e966c18c 100644 --- a/src/core/lib/iomgr/ev_poll_posix.c +++ b/src/core/lib/iomgr/ev_poll_posix.c @@ -47,10 +47,12 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include <grpc/support/string_util.h> +#include <grpc/support/thd.h> #include <grpc/support/tls.h> #include <grpc/support/useful.h> #include "src/core/lib/iomgr/iomgr_internal.h" +#include "src/core/lib/iomgr/wakeup_fd_cv.h" #include "src/core/lib/iomgr/wakeup_fd_posix.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/support/block_annotate.h" @@ -246,6 +248,28 @@ struct grpc_pollset_set { }; /******************************************************************************* + * condition variable polling definitions + */ + +#define CV_POLL_PERIOD_MS 1000 +#define CV_DEFAULT_TABLE_SIZE 16 + +typedef enum poll_status_t { INPROGRESS, COMPLETED, CANCELLED } poll_status_t; + +typedef struct poll_args { + gpr_refcount refcount; + gpr_cv *cv; + struct pollfd *fds; + nfds_t nfds; + int timeout; + int retval; + int err; + gpr_atm status; +} poll_args; + +cv_fd_table g_cvfds; + +/******************************************************************************* * fd_posix.c */ @@ -961,8 +985,15 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, if (errno != EINTR) { work_combine_error(&error, GRPC_OS_ERROR(errno, "poll")); } + for (i = 2; i < pfd_count; i++) { - fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL); + if (watchers[i].fd == NULL) { + fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL); + } else { + // Wake up all the file descriptors, if we have an invalid one + // we can identify it on the next pollset_work() + fd_end_poll(exec_ctx, &watchers[i], 1, 1, pollset); + } } } else if (r == 0) { for (i = 2; i < pfd_count; i++) { @@ -1236,10 +1267,237 @@ static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx, } /******************************************************************************* + * workqueue stubs + */ + +#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG +static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue, + const char *file, int line, + const char *reason) { + return workqueue; +} +static void workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, + const char *file, int line, const char *reason) {} +#else +static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue) { + return workqueue; +} +static void workqueue_unref(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue) {} +#endif + +static void workqueue_enqueue(grpc_exec_ctx *exec_ctx, + grpc_workqueue *workqueue, grpc_closure *closure, + grpc_error *error) { + grpc_exec_ctx_sched(exec_ctx, closure, error, NULL); +} + +/******************************************************************************* + * Condition Variable polling extensions + */ + +static void decref_poll_args(poll_args *args) { + if (gpr_unref(&args->refcount)) { + gpr_free(args->fds); + gpr_cv_destroy(args->cv); + gpr_free(args->cv); + gpr_free(args); + } +} + +// Poll in a background thread +static void run_poll(void *arg) { + int timeout, retval; + poll_args *pargs = (poll_args *)arg; + while (gpr_atm_no_barrier_load(&pargs->status) == INPROGRESS) { + if (pargs->timeout < 0) { + timeout = CV_POLL_PERIOD_MS; + } else { + timeout = GPR_MIN(CV_POLL_PERIOD_MS, pargs->timeout); + pargs->timeout -= timeout; + } + retval = g_cvfds.poll(pargs->fds, pargs->nfds, timeout); + if (retval != 0 || pargs->timeout == 0) { + pargs->retval = retval; + pargs->err = errno; + break; + } + } + gpr_mu_lock(&g_cvfds.mu); + if (gpr_atm_no_barrier_load(&pargs->status) == INPROGRESS) { + // Signal main thread that the poll completed + gpr_atm_no_barrier_store(&pargs->status, COMPLETED); + gpr_cv_signal(pargs->cv); + } + decref_poll_args(pargs); + g_cvfds.pollcount--; + if (g_cvfds.shutdown && g_cvfds.pollcount == 0) { + gpr_cv_signal(&g_cvfds.shutdown_complete); + } + gpr_mu_unlock(&g_cvfds.mu); +} + +// This function overrides poll() to handle condition variable wakeup fds +static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) { + unsigned int i; + int res, idx; + gpr_cv *pollcv; + cv_node *cvn, *prev; + nfds_t nsockfds = 0; + gpr_thd_id t_id; + gpr_thd_options opt; + poll_args *pargs = NULL; + gpr_mu_lock(&g_cvfds.mu); + pollcv = gpr_malloc(sizeof(gpr_cv)); + gpr_cv_init(pollcv); + for (i = 0; i < nfds; i++) { + fds[i].revents = 0; + if (fds[i].fd < 0 && (fds[i].events & POLLIN)) { + idx = FD_TO_IDX(fds[i].fd); + cvn = gpr_malloc(sizeof(cv_node)); + cvn->cv = pollcv; + cvn->next = g_cvfds.cvfds[idx].cvs; + g_cvfds.cvfds[idx].cvs = cvn; + // We should return immediately if there are pending events, + // but we still need to call poll() to check for socket events + if (g_cvfds.cvfds[idx].is_set) { + timeout = 0; + } + } else if (fds[i].fd >= 0) { + nsockfds++; + } + } + + if (nsockfds > 0) { + pargs = gpr_malloc(sizeof(struct poll_args)); + // Both the main thread and calling thread get a reference + gpr_ref_init(&pargs->refcount, 2); + pargs->cv = pollcv; + pargs->fds = gpr_malloc(sizeof(struct pollfd) * nsockfds); + pargs->nfds = nsockfds; + pargs->timeout = timeout; + pargs->retval = 0; + pargs->err = 0; + gpr_atm_no_barrier_store(&pargs->status, INPROGRESS); + idx = 0; + for (i = 0; i < nfds; i++) { + if (fds[i].fd >= 0) { + pargs->fds[idx].fd = fds[i].fd; + pargs->fds[idx].events = fds[i].events; + pargs->fds[idx].revents = 0; + idx++; + } + } + g_cvfds.pollcount++; + opt = gpr_thd_options_default(); + gpr_thd_options_set_detached(&opt); + gpr_thd_new(&t_id, &run_poll, pargs, &opt); + // We want the poll() thread to trigger the deadline, so wait forever here + gpr_cv_wait(pollcv, &g_cvfds.mu, gpr_inf_future(GPR_CLOCK_MONOTONIC)); + if (gpr_atm_no_barrier_load(&pargs->status) == COMPLETED) { + res = pargs->retval; + errno = pargs->err; + } else { + res = 0; + errno = 0; + gpr_atm_no_barrier_store(&pargs->status, CANCELLED); + } + } else { + gpr_timespec deadline = gpr_now(GPR_CLOCK_REALTIME); + deadline = + gpr_time_add(deadline, gpr_time_from_millis(timeout, GPR_TIMESPAN)); + gpr_cv_wait(pollcv, &g_cvfds.mu, deadline); + res = 0; + } + + idx = 0; + for (i = 0; i < nfds; i++) { + if (fds[i].fd < 0 && (fds[i].events & POLLIN)) { + cvn = g_cvfds.cvfds[FD_TO_IDX(fds[i].fd)].cvs; + prev = NULL; + while (cvn->cv != pollcv) { + prev = cvn; + cvn = cvn->next; + GPR_ASSERT(cvn); + } + if (!prev) { + g_cvfds.cvfds[FD_TO_IDX(fds[i].fd)].cvs = cvn->next; + } else { + prev->next = cvn->next; + } + gpr_free(cvn); + + if (g_cvfds.cvfds[FD_TO_IDX(fds[i].fd)].is_set) { + fds[i].revents = POLLIN; + if (res >= 0) res++; + } + } else if (fds[i].fd >= 0 && + gpr_atm_no_barrier_load(&pargs->status) == COMPLETED) { + fds[i].revents = pargs->fds[idx].revents; + idx++; + } + } + + if (pargs) { + decref_poll_args(pargs); + } else { + gpr_cv_destroy(pollcv); + gpr_free(pollcv); + } + gpr_mu_unlock(&g_cvfds.mu); + + return res; +} + +static void global_cv_fd_table_init() { + gpr_mu_init(&g_cvfds.mu); + gpr_mu_lock(&g_cvfds.mu); + gpr_cv_init(&g_cvfds.shutdown_complete); + g_cvfds.shutdown = 0; + g_cvfds.pollcount = 0; + g_cvfds.size = CV_DEFAULT_TABLE_SIZE; + g_cvfds.cvfds = gpr_malloc(sizeof(fd_node) * CV_DEFAULT_TABLE_SIZE); + g_cvfds.free_fds = NULL; + for (int i = 0; i < CV_DEFAULT_TABLE_SIZE; i++) { + g_cvfds.cvfds[i].is_set = 0; + g_cvfds.cvfds[i].cvs = NULL; + g_cvfds.cvfds[i].next_free = g_cvfds.free_fds; + g_cvfds.free_fds = &g_cvfds.cvfds[i]; + } + // Override the poll function with one that supports cvfds + g_cvfds.poll = grpc_poll_function; + grpc_poll_function = &cvfd_poll; + gpr_mu_unlock(&g_cvfds.mu); +} + +static void global_cv_fd_table_shutdown() { + gpr_mu_lock(&g_cvfds.mu); + g_cvfds.shutdown = 1; + // Attempt to wait for all abandoned poll() threads to terminate + // Not doing so will result in reported memory leaks + if (g_cvfds.pollcount > 0) { + int res = gpr_cv_wait(&g_cvfds.shutdown_complete, &g_cvfds.mu, + gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_seconds(3, GPR_TIMESPAN))); + GPR_ASSERT(res == 0); + } + gpr_cv_destroy(&g_cvfds.shutdown_complete); + grpc_poll_function = g_cvfds.poll; + gpr_free(g_cvfds.cvfds); + gpr_mu_unlock(&g_cvfds.mu); + gpr_mu_destroy(&g_cvfds.mu); +} + +/******************************************************************************* * event engine binding */ -static void shutdown_engine(void) { pollset_global_shutdown(); } +static void shutdown_engine(void) { + pollset_global_shutdown(); + if (grpc_cv_wakeup_fds_enabled()) { + global_cv_fd_table_shutdown(); + } +} static const grpc_event_engine_vtable vtable = { .pollset_size = sizeof(grpc_pollset), @@ -1273,11 +1531,29 @@ static const grpc_event_engine_vtable vtable = { .kick_poller = kick_poller, + .workqueue_ref = workqueue_ref, + .workqueue_unref = workqueue_unref, + .workqueue_enqueue = workqueue_enqueue, + .shutdown_engine = shutdown_engine, }; const grpc_event_engine_vtable *grpc_init_poll_posix(void) { + if (!grpc_has_wakeup_fd()) { + return NULL; + } + if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { + return NULL; + } + return &vtable; +} + +const grpc_event_engine_vtable *grpc_init_poll_cv_posix(void) { + global_cv_fd_table_init(); + grpc_enable_cv_wakeup_fds(1); if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) { + global_cv_fd_table_shutdown(); + grpc_enable_cv_wakeup_fds(0); return NULL; } return &vtable; diff --git a/src/core/lib/iomgr/ev_poll_posix.h b/src/core/lib/iomgr/ev_poll_posix.h index 291736a2db..202ffca14c 100644 --- a/src/core/lib/iomgr/ev_poll_posix.h +++ b/src/core/lib/iomgr/ev_poll_posix.h @@ -37,5 +37,6 @@ #include "src/core/lib/iomgr/ev_posix.h" const grpc_event_engine_vtable *grpc_init_poll_posix(void); +const grpc_event_engine_vtable *grpc_init_poll_cv_posix(void); #endif /* GRPC_CORE_LIB_IOMGR_EV_POLL_POSIX_H */ diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c index 6536672685..9857b0bce9 100644 --- a/src/core/lib/iomgr/ev_posix.c +++ b/src/core/lib/iomgr/ev_posix.c @@ -66,6 +66,7 @@ typedef struct { static const event_engine_factory g_factories[] = { {"epoll", grpc_init_epoll_linux}, {"poll", grpc_init_poll_posix}, + {"poll-cv", grpc_init_poll_cv_posix}, {"legacy", grpc_init_poll_and_epoll_posix}, }; @@ -258,4 +259,27 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx, grpc_error *grpc_kick_poller(void) { return g_event_engine->kick_poller(); } +#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG +grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, + int line, const char *reason) { + return g_event_engine->workqueue_ref(workqueue, file, line, reason); +} +void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, + const char *file, int line, const char *reason) { + g_event_engine->workqueue_unref(exec_ctx, workqueue, file, line, reason); +} +#else +grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue) { + return g_event_engine->workqueue_ref(workqueue); +} +void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { + g_event_engine->workqueue_unref(exec_ctx, workqueue); +} +#endif + +void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, + grpc_closure *closure, grpc_error *error) { + g_event_engine->workqueue_enqueue(exec_ctx, workqueue, closure, error); +} + #endif // GPR_POSIX_SOCKET diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h index c2aa1756ea..2fdef06838 100644 --- a/src/core/lib/iomgr/ev_posix.h +++ b/src/core/lib/iomgr/ev_posix.h @@ -40,6 +40,7 @@ #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/pollset_set.h" #include "src/core/lib/iomgr/wakeup_fd_posix.h" +#include "src/core/lib/iomgr/workqueue.h" typedef struct grpc_fd grpc_fd; @@ -95,6 +96,18 @@ typedef struct grpc_event_engine_vtable { grpc_error *(*kick_poller)(void); void (*shutdown_engine)(void); + +#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG + grpc_workqueue *(*workqueue_ref)(grpc_workqueue *workqueue, const char *file, + int line, const char *reason); + void (*workqueue_unref)(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, + const char *file, int line, const char *reason); +#else + grpc_workqueue *(*workqueue_ref)(grpc_workqueue *workqueue); + void (*workqueue_unref)(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); +#endif + void (*workqueue_enqueue)(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, + grpc_closure *closure, grpc_error *error); } grpc_event_engine_vtable; void grpc_event_engine_init(void); diff --git a/src/core/lib/iomgr/exec_ctx.c b/src/core/lib/iomgr/exec_ctx.c index ac7785ec13..604713e578 100644 --- a/src/core/lib/iomgr/exec_ctx.c +++ b/src/core/lib/iomgr/exec_ctx.c @@ -37,6 +37,7 @@ #include <grpc/support/sync.h> #include <grpc/support/thd.h> +#include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/workqueue.h" #include "src/core/lib/profiling/timers.h" @@ -60,18 +61,43 @@ bool grpc_always_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored) { bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { bool did_something = 0; GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0); - while (!grpc_closure_list_empty(exec_ctx->closure_list)) { - grpc_closure *c = exec_ctx->closure_list.head; - exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL; - while (c != NULL) { - grpc_closure *next = c->next_data.next; - grpc_error *error = c->error; - did_something = true; - GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0); + for (;;) { + if (!grpc_closure_list_empty(exec_ctx->closure_list)) { + grpc_closure *c = exec_ctx->closure_list.head; + exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL; + while (c != NULL) { + grpc_closure *next = c->next_data.next; + did_something = true; + grpc_closure_run(exec_ctx, c, c->error_data.error); + c = next; + } + } else if (!grpc_combiner_continue_exec_ctx(exec_ctx)) { + break; + } + } + GPR_ASSERT(exec_ctx->active_combiner == NULL); + if (exec_ctx->stealing_from_workqueue != NULL) { + if (grpc_exec_ctx_ready_to_finish(exec_ctx)) { + grpc_workqueue_enqueue(exec_ctx, exec_ctx->stealing_from_workqueue, + exec_ctx->stolen_closure, + exec_ctx->stolen_closure->error_data.error); + GRPC_WORKQUEUE_UNREF(exec_ctx, exec_ctx->stealing_from_workqueue, + "exec_ctx_sched"); + exec_ctx->stealing_from_workqueue = NULL; + exec_ctx->stolen_closure = NULL; + } else { + grpc_closure *c = exec_ctx->stolen_closure; + GRPC_WORKQUEUE_UNREF(exec_ctx, exec_ctx->stealing_from_workqueue, + "exec_ctx_sched"); + exec_ctx->stealing_from_workqueue = NULL; + exec_ctx->stolen_closure = NULL; + grpc_error *error = c->error_data.error; + GPR_TIMER_BEGIN("grpc_exec_ctx_flush.stolen_cb", 0); c->cb(exec_ctx, c->cb_arg, error); GRPC_ERROR_UNREF(error); - GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0); - c = next; + GPR_TIMER_END("grpc_exec_ctx_flush.stolen_cb", 0); + grpc_exec_ctx_flush(exec_ctx); + did_something = true; } } GPR_TIMER_END("grpc_exec_ctx_flush", 0); @@ -86,12 +112,25 @@ void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) { void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_error *error, grpc_workqueue *offload_target_or_null) { + GPR_TIMER_BEGIN("grpc_exec_ctx_sched", 0); if (offload_target_or_null == NULL) { grpc_closure_list_append(&exec_ctx->closure_list, closure, error); - } else { + } else if (exec_ctx->stealing_from_workqueue == NULL) { + exec_ctx->stealing_from_workqueue = offload_target_or_null; + closure->error_data.error = error; + exec_ctx->stolen_closure = closure; + } else if (exec_ctx->stealing_from_workqueue != offload_target_or_null) { grpc_workqueue_enqueue(exec_ctx, offload_target_or_null, closure, error); GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched"); + } else { /* stealing_from_workqueue == offload_target_or_null */ + grpc_workqueue_enqueue(exec_ctx, offload_target_or_null, + exec_ctx->stolen_closure, + exec_ctx->stolen_closure->error_data.error); + closure->error_data.error = error; + exec_ctx->stolen_closure = closure; + GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched"); } + GPR_TIMER_END("grpc_exec_ctx_sched", 0); } void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h index 4d20ecf922..7e50cb9825 100644 --- a/src/core/lib/iomgr/exec_ctx.h +++ b/src/core/lib/iomgr/exec_ctx.h @@ -66,15 +66,33 @@ typedef struct grpc_combiner grpc_combiner; #ifndef GRPC_EXECUTION_CONTEXT_SANITIZER struct grpc_exec_ctx { grpc_closure_list closure_list; + /** The workqueue we're stealing work from. + As items are queued to the execution context, we try to steal one + workqueue item and execute it inline (assuming the exec_ctx is not + finished) - doing so does not invalidate the workqueue's contract, and + provides a small latency win in cases where we get a hit */ + grpc_workqueue *stealing_from_workqueue; + /** The workqueue item that was stolen from the workqueue above. When new + items are scheduled to be offloaded to that workqueue, we need to update + this like a 1-deep fifo to maintain the invariant that workqueue items + queued by one thread are started in order */ + grpc_closure *stolen_closure; /** currently active combiner: updated only via combiner.c */ grpc_combiner *active_combiner; + /** last active combiner in the active combiner list */ + grpc_combiner *last_combiner; bool cached_ready_to_finish; void *check_ready_to_finish_arg; bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg); }; +/* initializer for grpc_exec_ctx: + prefer to use GRPC_EXEC_CTX_INIT whenever possible */ #define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \ - { GRPC_CLOSURE_LIST_INIT, NULL, false, finish_check_arg, finish_check } + { \ + GRPC_CLOSURE_LIST_INIT, NULL, NULL, NULL, NULL, false, finish_check_arg, \ + finish_check \ + } #else struct grpc_exec_ctx { bool cached_ready_to_finish; @@ -85,8 +103,10 @@ struct grpc_exec_ctx { { false, finish_check_arg, finish_check } #endif +/* initialize an execution context at the top level of an API call into grpc + (this is safe to use elsewhere, though possibly not as efficient) */ #define GRPC_EXEC_CTX_INIT \ - GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(grpc_never_ready_to_finish, NULL) + GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(grpc_always_ready_to_finish, NULL) /** Flush any work that has been enqueued onto this grpc_exec_ctx. * Caller must guarantee that no interfering locks are held. diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c index d67d388b8c..4fd83e0b22 100644 --- a/src/core/lib/iomgr/iomgr.c +++ b/src/core/lib/iomgr/iomgr.c @@ -112,6 +112,14 @@ void grpc_iomgr_shutdown(void) { continue; } if (g_root_object.next != &g_root_object) { + if (grpc_iomgr_abort_on_leaks()) { + gpr_log(GPR_DEBUG, "Failed to free %" PRIuPTR + " iomgr objects before shutdown deadline: " + "memory leaks are likely", + count_objects()); + dump_objects("LEAKED"); + abort(); + } gpr_timespec short_deadline = gpr_time_add( gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN)); if (gpr_cv_wait(&g_rcv, &g_mu, short_deadline)) { @@ -122,9 +130,6 @@ void grpc_iomgr_shutdown(void) { "memory leaks are likely", count_objects()); dump_objects("LEAKED"); - if (grpc_iomgr_abort_on_leaks()) { - abort(); - } } break; } diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c index 92767721d5..00fd77679a 100644 --- a/src/core/lib/iomgr/tcp_posix.c +++ b/src/core/lib/iomgr/tcp_posix.c @@ -177,7 +177,7 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, tcp->read_cb = NULL; tcp->incoming_buffer = NULL; - grpc_exec_ctx_sched(exec_ctx, cb, error, NULL); + grpc_closure_run(exec_ctx, cb, error); } #define MAX_READ_IOVEC 4 @@ -209,11 +209,11 @@ static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) { msg.msg_controllen = 0; msg.msg_flags = 0; - GPR_TIMER_BEGIN("recvmsg", 1); + GPR_TIMER_BEGIN("recvmsg", 0); do { read_bytes = recvmsg(tcp->fd, &msg, 0); } while (read_bytes < 0 && errno == EINTR); - GPR_TIMER_END("recvmsg", 0); + GPR_TIMER_END("recvmsg", read_bytes >= 0); if (read_bytes < 0) { /* NB: After calling call_read_cb a parallel call of the read handler may @@ -392,11 +392,8 @@ static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */, grpc_error_free_string(str); } - GPR_TIMER_BEGIN("tcp_handle_write.cb", 0); - cb->cb(exec_ctx, cb->cb_arg, error); - GPR_TIMER_END("tcp_handle_write.cb", 0); + grpc_closure_run(exec_ctx, cb, error); TCP_UNREF(exec_ctx, tcp, "write"); - GRPC_ERROR_UNREF(error); } } diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h index 5a25d39a0c..9a390699b4 100644 --- a/src/core/lib/iomgr/tcp_server.h +++ b/src/core/lib/iomgr/tcp_server.h @@ -101,8 +101,8 @@ grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s); void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, grpc_closure *shutdown_starting); -/* If the refcount drops to zero, delete s, and call (exec_ctx==NULL) or enqueue - a call (exec_ctx!=NULL) to shutdown_complete. */ +/* If the refcount drops to zero, enqueue calls on exec_ctx to + shutdown_listeners and delete s. */ void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s); /* Shutdown the fds of listeners. */ diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c index 2d3f6cf9a7..73df5477e6 100644 --- a/src/core/lib/iomgr/tcp_server_posix.c +++ b/src/core/lib/iomgr/tcp_server_posix.c @@ -191,6 +191,9 @@ grpc_error *grpc_tcp_server_create(grpc_closure *shutdown_complete, } static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { + gpr_mu_lock(&s->mu); + GPR_ASSERT(s->shutdown); + gpr_mu_unlock(&s->mu); if (s->shutdown_complete != NULL) { grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL); } @@ -652,6 +655,7 @@ unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, unsigned port_index) { unsigned num_fds = 0; grpc_tcp_listener *sp; + gpr_mu_lock(&s->mu); for (sp = s->head; sp && port_index != 0; sp = sp->next) { if (!sp->is_sibling) { --port_index; @@ -659,12 +663,15 @@ unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s, } for (; sp; sp = sp->sibling, ++num_fds) ; + gpr_mu_unlock(&s->mu); return num_fds; } int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index, unsigned fd_index) { grpc_tcp_listener *sp; + int fd; + gpr_mu_lock(&s->mu); for (sp = s->head; sp && port_index != 0; sp = sp->next) { if (!sp->is_sibling) { --port_index; @@ -673,10 +680,12 @@ int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index, for (; sp && fd_index != 0; sp = sp->sibling, --fd_index) ; if (sp) { - return sp->fd; + fd = sp->fd; } else { - return -1; + fd = -1; } + gpr_mu_unlock(&s->mu); + return fd; } void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, @@ -722,7 +731,7 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s, } grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { - gpr_ref(&s->refs); + gpr_ref_non_zero(&s->refs); return s; } @@ -736,19 +745,11 @@ void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s, void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { if (gpr_unref(&s->refs)) { - /* Complete shutdown_starting work before destroying. */ - grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_tcp_server_shutdown_listeners(exec_ctx, s); gpr_mu_lock(&s->mu); - grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL); + grpc_exec_ctx_enqueue_list(exec_ctx, &s->shutdown_starting, NULL); gpr_mu_unlock(&s->mu); - if (exec_ctx == NULL) { - grpc_exec_ctx_flush(&local_exec_ctx); - tcp_server_destroy(&local_exec_ctx, s); - grpc_exec_ctx_finish(&local_exec_ctx); - } else { - grpc_exec_ctx_finish(&local_exec_ctx); - tcp_server_destroy(exec_ctx, s); - } + tcp_server_destroy(exec_ctx, s); } } diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c index 1b125e7005..4ff05601fa 100644 --- a/src/core/lib/iomgr/tcp_server_windows.c +++ b/src/core/lib/iomgr/tcp_server_windows.c @@ -139,7 +139,7 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { } grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) { - gpr_ref(&s->refs); + gpr_ref_non_zero(&s->refs); return s; } @@ -174,19 +174,11 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) { if (gpr_unref(&s->refs)) { - /* Complete shutdown_starting work before destroying. */ - grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_tcp_server_shutdown_listeners(exec_ctx, s); gpr_mu_lock(&s->mu); - grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL); + grpc_exec_ctx_enqueue_list(exec_ctx, &s->shutdown_starting, NULL); gpr_mu_unlock(&s->mu); - if (exec_ctx == NULL) { - grpc_exec_ctx_flush(&local_exec_ctx); - tcp_server_destroy(&local_exec_ctx, s); - grpc_exec_ctx_finish(&local_exec_ctx); - } else { - grpc_exec_ctx_finish(&local_exec_ctx); - tcp_server_destroy(exec_ctx, s); - } + tcp_server_destroy(exec_ctx, s); } } diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h index a825d2a28b..5a9a177963 100644 --- a/src/core/lib/iomgr/timer.h +++ b/src/core/lib/iomgr/timer.h @@ -49,11 +49,11 @@ typedef struct grpc_timer { } grpc_timer; /* Initialize *timer. When expired or canceled, timer_cb will be called with - *timer_cb_arg and status to indicate if it expired (SUCCESS) or was - canceled (CANCELLED). timer_cb is guaranteed to be called exactly once, - and application code should check the status to determine how it was - invoked. The application callback is also responsible for maintaining - information about when to free up any user-level state. */ + *timer_cb_arg and error set to indicate if it expired (GRPC_ERROR_NONE) or + was canceled (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called + exactly once, and application code should check the error to determine + how it was invoked. The application callback is also responsible for + maintaining information about when to free up any user-level state. */ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, gpr_timespec deadline, grpc_iomgr_cb_func timer_cb, void *timer_cb_arg, gpr_timespec now); @@ -74,8 +74,8 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, In all of these cases, the cancellation is still considered successful. They are essentially distinguished in that the timer_cb will be run - exactly once from either the cancellation (with status CANCELLED) - or from the activation (with status SUCCESS) + exactly once from either the cancellation (with error GRPC_ERROR_CANCELLED) + or from the activation (with error GRPC_ERROR_NONE). Note carefully that the callback function MAY occur in the same callstack as grpc_timer_cancel. It's expected that most timers will be cancelled (their @@ -83,14 +83,13 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer, that cancellation costs as little as possible. Making callbacks run inline matches this aim. - Requires: cancel() must happen after add() on a given timer */ + Requires: cancel() must happen after init() on a given timer */ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer); /* iomgr internal api for dealing with timers */ /* Check for timers to be run, and run them. Return true if timer callbacks were executed. - Drops drop_mu if it is non-null before executing callbacks. If next is non-null, TRY to update *next with the next running timer IF that timer occurs before *next current value. *next is never guaranteed to be updated on any given execution; however, diff --git a/src/core/lib/iomgr/wakeup_fd_cv.c b/src/core/lib/iomgr/wakeup_fd_cv.c new file mode 100644 index 0000000000..b4165208ed --- /dev/null +++ b/src/core/lib/iomgr/wakeup_fd_cv.c @@ -0,0 +1,118 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/port_platform.h> + +#ifdef GPR_POSIX_WAKEUP_FD + +#include "src/core/lib/iomgr/wakeup_fd_cv.h" + +#include <errno.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/sync.h> +#include <grpc/support/thd.h> +#include <grpc/support/time.h> +#include <grpc/support/useful.h> + +#define MAX_TABLE_RESIZE 256 + +extern cv_fd_table g_cvfds; + +static grpc_error* cv_fd_init(grpc_wakeup_fd* fd_info) { + unsigned int i, newsize; + int idx; + gpr_mu_lock(&g_cvfds.mu); + if (!g_cvfds.free_fds) { + newsize = GPR_MIN(g_cvfds.size * 2, g_cvfds.size + MAX_TABLE_RESIZE); + g_cvfds.cvfds = gpr_realloc(g_cvfds.cvfds, sizeof(fd_node) * newsize); + for (i = g_cvfds.size; i < newsize; i++) { + g_cvfds.cvfds[i].is_set = 0; + g_cvfds.cvfds[i].cvs = NULL; + g_cvfds.cvfds[i].next_free = g_cvfds.free_fds; + g_cvfds.free_fds = &g_cvfds.cvfds[i]; + } + g_cvfds.size = newsize; + } + + idx = (int)(g_cvfds.free_fds - g_cvfds.cvfds); + g_cvfds.free_fds = g_cvfds.free_fds->next_free; + g_cvfds.cvfds[idx].cvs = NULL; + g_cvfds.cvfds[idx].is_set = 0; + fd_info->read_fd = IDX_TO_FD(idx); + fd_info->write_fd = -1; + gpr_mu_unlock(&g_cvfds.mu); + return GRPC_ERROR_NONE; +} + +static grpc_error* cv_fd_wakeup(grpc_wakeup_fd* fd_info) { + cv_node* cvn; + gpr_mu_lock(&g_cvfds.mu); + g_cvfds.cvfds[FD_TO_IDX(fd_info->read_fd)].is_set = 1; + cvn = g_cvfds.cvfds[FD_TO_IDX(fd_info->read_fd)].cvs; + while (cvn) { + gpr_cv_signal(cvn->cv); + cvn = cvn->next; + } + gpr_mu_unlock(&g_cvfds.mu); + return GRPC_ERROR_NONE; +} + +static grpc_error* cv_fd_consume(grpc_wakeup_fd* fd_info) { + gpr_mu_lock(&g_cvfds.mu); + g_cvfds.cvfds[FD_TO_IDX(fd_info->read_fd)].is_set = 0; + gpr_mu_unlock(&g_cvfds.mu); + return GRPC_ERROR_NONE; +} + +static void cv_fd_destroy(grpc_wakeup_fd* fd_info) { + if (fd_info->read_fd == 0) { + return; + } + gpr_mu_lock(&g_cvfds.mu); + // Assert that there are no active pollers + GPR_ASSERT(!g_cvfds.cvfds[FD_TO_IDX(fd_info->read_fd)].cvs); + g_cvfds.cvfds[FD_TO_IDX(fd_info->read_fd)].next_free = g_cvfds.free_fds; + g_cvfds.free_fds = &g_cvfds.cvfds[FD_TO_IDX(fd_info->read_fd)]; + gpr_mu_unlock(&g_cvfds.mu); +} + +static int cv_check_availability(void) { return 1; } + +const grpc_wakeup_fd_vtable grpc_cv_wakeup_fd_vtable = { + cv_fd_init, cv_fd_consume, cv_fd_wakeup, cv_fd_destroy, + cv_check_availability}; + +#endif /* GPR_POSIX_WAKUP_FD */ diff --git a/src/core/lib/iomgr/wakeup_fd_cv.h b/src/core/lib/iomgr/wakeup_fd_cv.h new file mode 100644 index 0000000000..ac16be1750 --- /dev/null +++ b/src/core/lib/iomgr/wakeup_fd_cv.h @@ -0,0 +1,80 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * wakeup_fd_cv uses condition variables to implement wakeup fds. + * + * It is intended for use only in cases when eventfd() and pipe() are not + * available. It can only be used with the "poll" engine. + * + * Implementation: + * A global table of cv wakeup fds is mantained. A cv wakeup fd is a negative + * file descriptor. poll() is then run in a background thread with only the + * real socket fds while we wait on a condition variable trigged by either the + * poll() completion or a wakeup_fd() call. + * + */ + +#ifndef GRPC_CORE_LIB_IOMGR_WAKEUP_FD_CV_H +#define GRPC_CORE_LIB_IOMGR_WAKEUP_FD_CV_H + +#include <grpc/support/sync.h> + +#include "src/core/lib/iomgr/ev_posix.h" + +#define FD_TO_IDX(fd) (-(fd)-1) +#define IDX_TO_FD(idx) (-(idx)-1) + +typedef struct cv_node { + gpr_cv* cv; + struct cv_node* next; +} cv_node; + +typedef struct fd_node { + int is_set; + cv_node* cvs; + struct fd_node* next_free; +} fd_node; + +typedef struct cv_fd_table { + gpr_mu mu; + int pollcount; + int shutdown; + gpr_cv shutdown_complete; + fd_node* cvfds; + fd_node* free_fds; + unsigned int size; + grpc_poll_function_type poll; +} cv_fd_table; + +#endif /* GRPC_CORE_LIB_IOMGR_WAKEUP_FD_CV_H */ diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.c b/src/core/lib/iomgr/wakeup_fd_pipe.c index 4e5dbdcb73..d0ea216aa0 100644 --- a/src/core/lib/iomgr/wakeup_fd_pipe.c +++ b/src/core/lib/iomgr/wakeup_fd_pipe.c @@ -47,11 +47,10 @@ static grpc_error* pipe_init(grpc_wakeup_fd* fd_info) { int pipefd[2]; - /* TODO(klempner): Make this nonfatal */ int r = pipe(pipefd); if (0 != r) { gpr_log(GPR_ERROR, "pipe creation failed (%d): %s", errno, strerror(errno)); - abort(); + return GRPC_OS_ERROR(errno, "pipe"); } grpc_error* err; err = grpc_set_socket_nonblocking(pipefd[0], 1); @@ -95,8 +94,13 @@ static void pipe_destroy(grpc_wakeup_fd* fd_info) { } static int pipe_check_availability(void) { - /* Assume that pipes are always available. */ - return 1; + grpc_wakeup_fd fd; + if (pipe_init(&fd) == GRPC_ERROR_NONE) { + pipe_destroy(&fd); + return 1; + } else { + return 0; + } } const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable = { diff --git a/src/core/lib/iomgr/wakeup_fd_posix.c b/src/core/lib/iomgr/wakeup_fd_posix.c index 046208abc8..5c894bef37 100644 --- a/src/core/lib/iomgr/wakeup_fd_posix.c +++ b/src/core/lib/iomgr/wakeup_fd_posix.c @@ -36,37 +36,66 @@ #ifdef GPR_POSIX_WAKEUP_FD #include <stddef.h> +#include "src/core/lib/iomgr/wakeup_fd_cv.h" #include "src/core/lib/iomgr/wakeup_fd_pipe.h" #include "src/core/lib/iomgr/wakeup_fd_posix.h" +extern grpc_wakeup_fd_vtable grpc_cv_wakeup_fd_vtable; static const grpc_wakeup_fd_vtable *wakeup_fd_vtable = NULL; + int grpc_allow_specialized_wakeup_fd = 1; +int grpc_allow_pipe_wakeup_fd = 1; + +int has_real_wakeup_fd = 1; +int cv_wakeup_fds_enabled = 0; void grpc_wakeup_fd_global_init(void) { if (grpc_allow_specialized_wakeup_fd && grpc_specialized_wakeup_fd_vtable.check_availability()) { wakeup_fd_vtable = &grpc_specialized_wakeup_fd_vtable; - } else { + } else if (grpc_allow_pipe_wakeup_fd && + grpc_pipe_wakeup_fd_vtable.check_availability()) { wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable; + } else { + has_real_wakeup_fd = 0; } } void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; } +int grpc_has_wakeup_fd(void) { return has_real_wakeup_fd; } + +int grpc_cv_wakeup_fds_enabled(void) { return cv_wakeup_fds_enabled; } + +void grpc_enable_cv_wakeup_fds(int enable) { cv_wakeup_fds_enabled = enable; } + grpc_error *grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) { + if (cv_wakeup_fds_enabled) { + return grpc_cv_wakeup_fd_vtable.init(fd_info); + } return wakeup_fd_vtable->init(fd_info); } grpc_error *grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd *fd_info) { + if (cv_wakeup_fds_enabled) { + return grpc_cv_wakeup_fd_vtable.consume(fd_info); + } return wakeup_fd_vtable->consume(fd_info); } grpc_error *grpc_wakeup_fd_wakeup(grpc_wakeup_fd *fd_info) { + if (cv_wakeup_fds_enabled) { + return grpc_cv_wakeup_fd_vtable.wakeup(fd_info); + } return wakeup_fd_vtable->wakeup(fd_info); } void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info) { - wakeup_fd_vtable->destroy(fd_info); + if (cv_wakeup_fds_enabled) { + grpc_cv_wakeup_fd_vtable.destroy(fd_info); + } else { + wakeup_fd_vtable->destroy(fd_info); + } } #endif /* GPR_POSIX_WAKEUP_FD */ diff --git a/src/core/lib/iomgr/wakeup_fd_posix.h b/src/core/lib/iomgr/wakeup_fd_posix.h index e269f242d8..71d32d97ba 100644 --- a/src/core/lib/iomgr/wakeup_fd_posix.h +++ b/src/core/lib/iomgr/wakeup_fd_posix.h @@ -71,6 +71,10 @@ void grpc_wakeup_fd_global_destroy(void); * purposes only.*/ void grpc_wakeup_fd_global_init_force_fallback(void); +int grpc_has_wakeup_fd(void); +int grpc_cv_wakeup_fds_enabled(void); +void grpc_enable_cv_wakeup_fds(int enable); + typedef struct grpc_wakeup_fd grpc_wakeup_fd; typedef struct grpc_wakeup_fd_vtable { @@ -88,6 +92,7 @@ struct grpc_wakeup_fd { }; extern int grpc_allow_specialized_wakeup_fd; +extern int grpc_allow_pipe_wakeup_fd; #define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd) diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h index b2805dc66c..5b96d1d851 100644 --- a/src/core/lib/iomgr/workqueue.h +++ b/src/core/lib/iomgr/workqueue.h @@ -40,10 +40,6 @@ #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/pollset_set.h" -#ifdef GPR_POSIX_SOCKET -#include "src/core/lib/iomgr/workqueue_posix.h" -#endif - #ifdef GPR_WINDOWS #include "src/core/lib/iomgr/workqueue_windows.h" #endif @@ -58,20 +54,20 @@ string will be printed alongside the refcount. When it is not defined, the string will be discarded at compilation time. */ -//#define GRPC_WORKQUEUE_REFCOUNT_DEBUG +/*#define GRPC_WORKQUEUE_REFCOUNT_DEBUG*/ #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG #define GRPC_WORKQUEUE_REF(p, r) \ - (grpc_workqueue_ref((p), __FILE__, __LINE__, (r)), (p)) + grpc_workqueue_ref((p), __FILE__, __LINE__, (r)) #define GRPC_WORKQUEUE_UNREF(exec_ctx, p, r) \ grpc_workqueue_unref((exec_ctx), (p), __FILE__, __LINE__, (r)) -void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, - const char *reason); +grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, + int line, const char *reason); void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, const char *file, int line, const char *reason); #else -#define GRPC_WORKQUEUE_REF(p, r) (grpc_workqueue_ref((p)), (p)) +#define GRPC_WORKQUEUE_REF(p, r) grpc_workqueue_ref((p)) #define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p)) -void grpc_workqueue_ref(grpc_workqueue *workqueue); +grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue); void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); #endif diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c deleted file mode 100644 index ecfea68f56..0000000000 --- a/src/core/lib/iomgr/workqueue_posix.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <grpc/support/port_platform.h> - -#ifdef GPR_POSIX_SOCKET - -#include "src/core/lib/iomgr/workqueue.h" - -#include <stdio.h> - -#include <grpc/support/alloc.h> -#include <grpc/support/log.h> -#include <grpc/support/useful.h> - -#include "src/core/lib/iomgr/ev_posix.h" -#include "src/core/lib/profiling/timers.h" - -static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); - -grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx, - grpc_workqueue **workqueue) { - char name[32]; - *workqueue = gpr_malloc(sizeof(grpc_workqueue)); - gpr_ref_init(&(*workqueue)->refs, 1); - gpr_atm_no_barrier_store(&(*workqueue)->state, 1); - grpc_error *err = grpc_wakeup_fd_init(&(*workqueue)->wakeup_fd); - if (err != GRPC_ERROR_NONE) { - gpr_free(*workqueue); - return err; - } - sprintf(name, "workqueue:%p", (void *)(*workqueue)); - (*workqueue)->wakeup_read_fd = grpc_fd_create( - GRPC_WAKEUP_FD_GET_READ_FD(&(*workqueue)->wakeup_fd), name); - gpr_mpscq_init(&(*workqueue)->queue); - grpc_closure_init(&(*workqueue)->read_closure, on_readable, *workqueue); - grpc_fd_notify_on_read(exec_ctx, (*workqueue)->wakeup_read_fd, - &(*workqueue)->read_closure); - return GRPC_ERROR_NONE; -} - -static void workqueue_destroy(grpc_exec_ctx *exec_ctx, - grpc_workqueue *workqueue) { - grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd); -} - -static void workqueue_orphan(grpc_exec_ctx *exec_ctx, - grpc_workqueue *workqueue) { - if (gpr_atm_full_fetch_add(&workqueue->state, -1) == 1) { - workqueue_destroy(exec_ctx, workqueue); - } -} - -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, - const char *reason) { - if (workqueue == NULL) return; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p ref %d -> %d %s", - workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count + 1, - reason); - gpr_ref(&workqueue->refs); -} -#else -void grpc_workqueue_ref(grpc_workqueue *workqueue) { - if (workqueue == NULL) return; - gpr_ref(&workqueue->refs); -} -#endif - -#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - const char *file, int line, const char *reason) { - if (workqueue == NULL) return; - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p unref %d -> %d %s", - workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count - 1, - reason); - if (gpr_unref(&workqueue->refs)) { - workqueue_orphan(exec_ctx, workqueue); - } -} -#else -void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { - if (workqueue == NULL) return; - if (gpr_unref(&workqueue->refs)) { - workqueue_orphan(exec_ctx, workqueue); - } -} -#endif - -static void drain(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { - abort(); -} - -static void wakeup(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { - GPR_TIMER_MARK("workqueue.wakeup", 0); - grpc_error *err = grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd); - if (!GRPC_LOG_IF_ERROR("wakeupfd_wakeup", err)) { - drain(exec_ctx, workqueue); - } -} - -static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - GPR_TIMER_BEGIN("workqueue.on_readable", 0); - - grpc_workqueue *workqueue = arg; - - if (error != GRPC_ERROR_NONE) { - /* HACK: let wakeup_fd code know that we stole the fd */ - workqueue->wakeup_fd.read_fd = 0; - grpc_wakeup_fd_destroy(&workqueue->wakeup_fd); - grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy"); - GPR_ASSERT(gpr_atm_no_barrier_load(&workqueue->state) == 0); - gpr_free(workqueue); - } else { - error = grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd); - gpr_mpscq_node *n = gpr_mpscq_pop(&workqueue->queue); - if (error == GRPC_ERROR_NONE) { - grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd, - &workqueue->read_closure); - } else { - /* recurse to get error handling */ - on_readable(exec_ctx, arg, error); - } - if (n == NULL) { - /* try again - queue in an inconsistant state */ - wakeup(exec_ctx, workqueue); - } else { - switch (gpr_atm_full_fetch_add(&workqueue->state, -2)) { - case 3: // had one count, one unorphaned --> done, unorphaned - break; - case 2: // had one count, one orphaned --> done, orphaned - workqueue_destroy(exec_ctx, workqueue); - break; - case 1: - case 0: - // these values are illegal - representing an already done or - // deleted workqueue - GPR_UNREACHABLE_CODE(break); - default: - // schedule a wakeup since there's more to do - wakeup(exec_ctx, workqueue); - } - grpc_closure *cl = (grpc_closure *)n; - grpc_error *clerr = cl->error; - cl->cb(exec_ctx, cl->cb_arg, clerr); - GRPC_ERROR_UNREF(clerr); - } - } - - GPR_TIMER_END("workqueue.on_readable", 0); -} - -void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, - grpc_closure *closure, grpc_error *error) { - GPR_TIMER_BEGIN("workqueue.enqueue", 0); - gpr_atm last = gpr_atm_full_fetch_add(&workqueue->state, 2); - GPR_ASSERT(last & 1); - closure->error = error; - gpr_mpscq_push(&workqueue->queue, &closure->next_data.atm_next); - if (last == 1) { - wakeup(exec_ctx, workqueue); - } - GPR_TIMER_END("workqueue.enqueue", 0); -} - -#endif /* GPR_POSIX_SOCKET */ diff --git a/src/core/lib/iomgr/workqueue_windows.c b/src/core/lib/iomgr/workqueue_windows.c index ee81dc248e..5c93d3c59e 100644 --- a/src/core/lib/iomgr/workqueue_windows.c +++ b/src/core/lib/iomgr/workqueue_windows.c @@ -43,12 +43,16 @@ // workqueues. #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG -void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, - const char *reason) {} +grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, + int line, const char *reason) { + return workqueue; +} void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, const char *file, int line, const char *reason) {} #else -void grpc_workqueue_ref(grpc_workqueue *workqueue) {} +grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue) { + return workqueue; +} void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {} #endif diff --git a/src/core/lib/profiling/basic_timers.c b/src/core/lib/profiling/basic_timers.c index 51813d0461..bdf9af2339 100644 --- a/src/core/lib/profiling/basic_timers.c +++ b/src/core/lib/profiling/basic_timers.c @@ -83,6 +83,7 @@ static int g_shutdown; static gpr_thd_id g_writing_thread; static __thread int g_thread_id; static int g_next_thread_id; +static int g_writing_enabled = 1; static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) { if (list->head == NULL) { @@ -177,7 +178,7 @@ static void flush_logs(gpr_timer_log_list *list) { } } -static void finish_writing() { +static void finish_writing(void) { pthread_mutex_lock(&g_mu); g_shutdown = 1; pthread_cond_signal(&g_cv); @@ -230,6 +231,10 @@ static void gpr_timers_log_add(const char *tagstr, marker_type type, int important, const char *file, int line) { gpr_timer_entry *entry; + if (!g_writing_enabled) { + return; + } + if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) { rotate_log(); } @@ -261,6 +266,8 @@ void gpr_timer_end(const char *tagstr, int important, const char *file, gpr_timers_log_add(tagstr, END, important, file, line); } +void gpr_timer_set_enabled(int enabled) { g_writing_enabled = enabled; } + /* Basic profiler specific API functions. */ void gpr_timers_global_init(void) {} @@ -272,4 +279,6 @@ void gpr_timers_global_init(void) {} void gpr_timers_global_destroy(void) {} void gpr_timers_set_log_filename(const char *filename) {} + +void gpr_timer_set_enabled(int enabled) {} #endif /* GRPC_BASIC_PROFILER */ diff --git a/src/core/lib/profiling/timers.h b/src/core/lib/profiling/timers.h index c8567e8137..621cdbf656 100644 --- a/src/core/lib/profiling/timers.h +++ b/src/core/lib/profiling/timers.h @@ -50,6 +50,8 @@ void gpr_timer_end(const char *tagstr, int important, const char *file, void gpr_timers_set_log_filename(const char *filename); +void gpr_timer_set_enabled(int enabled); + #if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER)) /* No profiling. No-op all the things. */ #define GPR_TIMER_MARK(tag, important) \ diff --git a/src/core/lib/security/credentials/composite/composite_credentials.c b/src/core/lib/security/credentials/composite/composite_credentials.c index 850e41e646..d55d00b7b6 100644 --- a/src/core/lib/security/credentials/composite/composite_credentials.c +++ b/src/core/lib/security/credentials/composite/composite_credentials.c @@ -242,8 +242,17 @@ static grpc_security_status composite_channel_create_security_connector( return status; } +static grpc_channel_credentials * +composite_channel_duplicate_without_call_credentials( + grpc_channel_credentials *creds) { + grpc_composite_channel_credentials *c = + (grpc_composite_channel_credentials *)creds; + return grpc_channel_credentials_ref(c->inner_creds); +} + static grpc_channel_credentials_vtable composite_channel_credentials_vtable = { - composite_channel_destruct, composite_channel_create_security_connector}; + composite_channel_destruct, composite_channel_create_security_connector, + composite_channel_duplicate_without_call_credentials}; grpc_channel_credentials *grpc_composite_channel_credentials_create( grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds, diff --git a/src/core/lib/security/credentials/composite/composite_credentials.h b/src/core/lib/security/credentials/composite/composite_credentials.h index 0d8966f464..f8425c2b76 100644 --- a/src/core/lib/security/credentials/composite/composite_credentials.h +++ b/src/core/lib/security/credentials/composite/composite_credentials.h @@ -53,7 +53,7 @@ grpc_call_credentials *grpc_credentials_contains_type( grpc_call_credentials *creds, const char *type, grpc_call_credentials **composite_creds); -/* -- Channel composite credentials. -- */ +/* -- Composite channel credentials. -- */ typedef struct { grpc_channel_credentials base; @@ -61,7 +61,7 @@ typedef struct { grpc_call_credentials *call_creds; } grpc_composite_channel_credentials; -/* -- Composite credentials. -- */ +/* -- Composite call credentials. -- */ typedef struct { grpc_call_credentials base; diff --git a/src/core/lib/security/credentials/credentials.c b/src/core/lib/security/credentials/credentials.c index 029a357261..1149e5c2ed 100644 --- a/src/core/lib/security/credentials/credentials.c +++ b/src/core/lib/security/credentials/credentials.c @@ -138,6 +138,18 @@ grpc_security_status grpc_channel_credentials_create_security_connector( channel_creds, NULL, target, args, sc, new_args); } +grpc_channel_credentials * +grpc_channel_credentials_duplicate_without_call_credentials( + grpc_channel_credentials *channel_creds) { + if (channel_creds != NULL && channel_creds->vtable != NULL && + channel_creds->vtable->duplicate_without_call_credentials != NULL) { + return channel_creds->vtable->duplicate_without_call_credentials( + channel_creds); + } else { + return grpc_channel_credentials_ref(channel_creds); + } +} + grpc_server_credentials *grpc_server_credentials_ref( grpc_server_credentials *creds) { if (creds == NULL) return NULL; diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h index 8e9d842ead..6fb5b5b15a 100644 --- a/src/core/lib/security/credentials/credentials.h +++ b/src/core/lib/security/credentials/credentials.h @@ -107,6 +107,9 @@ typedef struct { grpc_channel_credentials *c, grpc_call_credentials *call_creds, const char *target, const grpc_channel_args *args, grpc_channel_security_connector **sc, grpc_channel_args **new_args); + + grpc_channel_credentials *(*duplicate_without_call_credentials)( + grpc_channel_credentials *c); } grpc_channel_credentials_vtable; struct grpc_channel_credentials { @@ -128,6 +131,13 @@ grpc_security_status grpc_channel_credentials_create_security_connector( const grpc_channel_args *args, grpc_channel_security_connector **sc, grpc_channel_args **new_args); +/* Creates a version of the channel credentials without any attached call + credentials. This can be used in order to open a channel to a non-trusted + gRPC load balancer. */ +grpc_channel_credentials * +grpc_channel_credentials_duplicate_without_call_credentials( + grpc_channel_credentials *creds); + /* --- grpc_credentials_md. --- */ typedef struct { diff --git a/src/core/lib/security/credentials/fake/fake_credentials.c b/src/core/lib/security/credentials/fake/fake_credentials.c index 51cafd986f..ea4cb76fb9 100644 --- a/src/core/lib/security/credentials/fake/fake_credentials.c +++ b/src/core/lib/security/credentials/fake/fake_credentials.c @@ -61,7 +61,7 @@ fake_transport_security_server_create_security_connector( static grpc_channel_credentials_vtable fake_transport_security_credentials_vtable = { - NULL, fake_transport_security_create_security_connector}; + NULL, fake_transport_security_create_security_connector, NULL}; static grpc_server_credentials_vtable fake_transport_security_server_credentials_vtable = { diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.c b/src/core/lib/security/credentials/ssl/ssl_credentials.c index 545bca9d98..0dc1fccec4 100644 --- a/src/core/lib/security/credentials/ssl/ssl_credentials.c +++ b/src/core/lib/security/credentials/ssl/ssl_credentials.c @@ -95,7 +95,7 @@ static grpc_security_status ssl_create_security_connector( } static grpc_channel_credentials_vtable ssl_vtable = { - ssl_destruct, ssl_create_security_connector}; + ssl_destruct, ssl_create_security_connector, NULL}; static void ssl_build_config(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, diff --git a/src/core/lib/support/log.c b/src/core/lib/support/log.c index 899f1218b6..af1651dae5 100644 --- a/src/core/lib/support/log.c +++ b/src/core/lib/support/log.c @@ -60,8 +60,9 @@ const char *gpr_log_severity_string(gpr_log_severity severity) { void gpr_log_message(const char *file, int line, gpr_log_severity severity, const char *message) { - if ((gpr_atm)severity < gpr_atm_no_barrier_load(&g_min_severity_to_print)) + if ((gpr_atm)severity < gpr_atm_no_barrier_load(&g_min_severity_to_print)) { return; + } gpr_log_func_args lfargs; memset(&lfargs, 0, sizeof(lfargs)); @@ -82,11 +83,11 @@ void gpr_log_verbosity_init() { gpr_atm min_severity_to_print = GPR_LOG_SEVERITY_ERROR; if (verbosity != NULL) { - if (strcmp(verbosity, "DEBUG") == 0) { + if (gpr_stricmp(verbosity, "DEBUG") == 0) { min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_DEBUG; - } else if (strcmp(verbosity, "INFO") == 0) { + } else if (gpr_stricmp(verbosity, "INFO") == 0) { min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_INFO; - } else if (strcmp(verbosity, "ERROR") == 0) { + } else if (gpr_stricmp(verbosity, "ERROR") == 0) { min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_ERROR; } gpr_free(verbosity); diff --git a/src/core/lib/support/string.c b/src/core/lib/support/string.c index 30c1e67647..d17fb9da4b 100644 --- a/src/core/lib/support/string.c +++ b/src/core/lib/support/string.c @@ -304,3 +304,14 @@ void gpr_strvec_add(gpr_strvec *sv, char *str) { char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) { return gpr_strjoin((const char **)sv->strs, sv->count, final_length); } + +int gpr_stricmp(const char *a, const char *b) { + int ca, cb; + do { + ca = tolower(*a); + cb = tolower(*b); + ++a; + ++b; + } while (ca == cb && ca && cb); + return ca - cb; +} diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h index 2b6bb3eec6..9a94e9471c 100644 --- a/src/core/lib/support/string.h +++ b/src/core/lib/support/string.h @@ -118,6 +118,10 @@ void gpr_strvec_add(gpr_strvec *strs, char *add); total_length as per gpr_strjoin */ char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length); +/** Case insensitive string comparison... return <0 if lower(a)<lower(b), ==0 if + lower(a)==lower(b), >0 if lower(a)>lower(b) */ +int gpr_stricmp(const char *a, const char *b); + #ifdef __cplusplus } #endif diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c index b0f66f4f61..30559304c6 100644 --- a/src/core/lib/surface/call.c +++ b/src/core/lib/surface/call.c @@ -223,33 +223,37 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack, static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp, grpc_error *error); -grpc_call *grpc_call_create( - grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, - grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative, - const void *server_transport_data, grpc_mdelem **add_initial_metadata, - size_t add_initial_metadata_count, gpr_timespec send_deadline) { +grpc_error *grpc_call_create(const grpc_call_create_args *args, + grpc_call **out_call) { size_t i, j; - grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); + grpc_channel_stack *channel_stack = + grpc_channel_get_channel_stack(args->channel); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_call *call; GPR_TIMER_BEGIN("grpc_call_create", 0); call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size); + *out_call = call; memset(call, 0, sizeof(grpc_call)); gpr_mu_init(&call->mu); - call->channel = channel; - call->cq = cq; - call->parent = parent_call; + call->channel = args->channel; + call->cq = args->cq; + call->parent = args->parent_call; /* Always support no compression */ GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE); - call->is_client = server_transport_data == NULL; + call->is_client = args->server_transport_data == NULL; + grpc_mdstr *path = NULL; if (call->is_client) { - GPR_ASSERT(add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT); - for (i = 0; i < add_initial_metadata_count; i++) { - call->send_extra_metadata[i].md = add_initial_metadata[i]; + GPR_ASSERT(args->add_initial_metadata_count < + MAX_SEND_EXTRA_METADATA_COUNT); + for (i = 0; i < args->add_initial_metadata_count; i++) { + call->send_extra_metadata[i].md = args->add_initial_metadata[i]; + if (args->add_initial_metadata[i]->key == GRPC_MDSTR_PATH) { + path = GRPC_MDSTR_REF(args->add_initial_metadata[i]->value); + } } - call->send_extra_metadata_count = (int)add_initial_metadata_count; + call->send_extra_metadata_count = (int)args->add_initial_metadata_count; } else { - GPR_ASSERT(add_initial_metadata_count == 0); + GPR_ASSERT(args->add_initial_metadata_count == 0); call->send_extra_metadata_count = 0; } for (i = 0; i < 2; i++) { @@ -257,84 +261,87 @@ grpc_call *grpc_call_create( call->metadata_batch[i][j].deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); } } - send_deadline = gpr_convert_clock_type(send_deadline, GPR_CLOCK_MONOTONIC); + gpr_timespec send_deadline = + gpr_convert_clock_type(args->send_deadline, GPR_CLOCK_MONOTONIC); - if (parent_call != NULL) { - GRPC_CALL_INTERNAL_REF(parent_call, "child"); + if (args->parent_call != NULL) { + GRPC_CALL_INTERNAL_REF(args->parent_call, "child"); GPR_ASSERT(call->is_client); - GPR_ASSERT(!parent_call->is_client); + GPR_ASSERT(!args->parent_call->is_client); - gpr_mu_lock(&parent_call->mu); + gpr_mu_lock(&args->parent_call->mu); - if (propagation_mask & GRPC_PROPAGATE_DEADLINE) { + if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) { send_deadline = gpr_time_min( gpr_convert_clock_type(send_deadline, - parent_call->send_deadline.clock_type), - parent_call->send_deadline); + args->parent_call->send_deadline.clock_type), + args->parent_call->send_deadline); } /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with * GRPC_PROPAGATE_STATS_CONTEXT */ /* TODO(ctiller): This should change to use the appropriate census start_op * call. */ - if (propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) { - GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); - grpc_call_context_set(call, GRPC_CONTEXT_TRACING, - parent_call->context[GRPC_CONTEXT_TRACING].value, - NULL); + if (args->propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) { + GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); + grpc_call_context_set( + call, GRPC_CONTEXT_TRACING, + args->parent_call->context[GRPC_CONTEXT_TRACING].value, NULL); } else { - GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); + GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT); } - if (propagation_mask & GRPC_PROPAGATE_CANCELLATION) { + if (args->propagation_mask & GRPC_PROPAGATE_CANCELLATION) { call->cancellation_is_inherited = 1; } - if (parent_call->first_child == NULL) { - parent_call->first_child = call; + if (args->parent_call->first_child == NULL) { + args->parent_call->first_child = call; call->sibling_next = call->sibling_prev = call; } else { - call->sibling_next = parent_call->first_child; - call->sibling_prev = parent_call->first_child->sibling_prev; + call->sibling_next = args->parent_call->first_child; + call->sibling_prev = args->parent_call->first_child->sibling_prev; call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = call; } - gpr_mu_unlock(&parent_call->mu); + gpr_mu_unlock(&args->parent_call->mu); } call->send_deadline = send_deadline; - GRPC_CHANNEL_INTERNAL_REF(channel, "call"); + GRPC_CHANNEL_INTERNAL_REF(args->channel, "call"); /* initial refcount dropped by grpc_call_destroy */ - grpc_error *error = grpc_call_stack_init( - &exec_ctx, channel_stack, 1, destroy_call, call, call->context, - server_transport_data, send_deadline, CALL_STACK_FROM_CALL(call)); + grpc_error *error = + grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call, + call->context, args->server_transport_data, path, + send_deadline, CALL_STACK_FROM_CALL(call)); if (error != GRPC_ERROR_NONE) { grpc_status_code status; const char *error_str; grpc_error_get_status(error, &status, &error_str); close_with_status(&exec_ctx, call, status, error_str); - GRPC_ERROR_UNREF(error); } - if (cq != NULL) { + if (args->cq != NULL) { GPR_ASSERT( - pollset_set_alternative == NULL && + args->pollset_set_alternative == NULL && "Only one of 'cq' and 'pollset_set_alternative' should be non-NULL."); - GRPC_CQ_INTERNAL_REF(cq, "bind"); + GRPC_CQ_INTERNAL_REF(args->cq, "bind"); call->pollent = - grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)); + grpc_polling_entity_create_from_pollset(grpc_cq_pollset(args->cq)); } - if (pollset_set_alternative != NULL) { - call->pollent = - grpc_polling_entity_create_from_pollset_set(pollset_set_alternative); + if (args->pollset_set_alternative != NULL) { + call->pollent = grpc_polling_entity_create_from_pollset_set( + args->pollset_set_alternative); } if (!grpc_polling_entity_is_empty(&call->pollent)) { grpc_call_stack_set_pollset_or_pollset_set( &exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent); } + if (path != NULL) GRPC_MDSTR_UNREF(path); + grpc_exec_ctx_finish(&exec_ctx); GPR_TIMER_END("grpc_call_create", 0); - return call; + return error; } void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call, @@ -1038,9 +1045,14 @@ static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data, static void post_batch_completion(grpc_exec_ctx *exec_ctx, batch_control *bctl) { grpc_call *call = bctl->call; + grpc_error *error = bctl->error; + if (bctl->recv_final_op) { + GRPC_ERROR_UNREF(error); + error = GRPC_ERROR_NONE; + } if (bctl->is_notify_tag_closure) { /* unrefs bctl->error */ - grpc_exec_ctx_sched(exec_ctx, bctl->notify_tag, bctl->error, NULL); + grpc_closure_run(exec_ctx, bctl->notify_tag, error); gpr_mu_lock(&call->mu); bctl->call->used_batches = (uint8_t)(bctl->call->used_batches & @@ -1049,7 +1061,7 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx, GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion"); } else { /* unrefs bctl->error */ - grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, bctl->error, + grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, error, finish_batch_completion, bctl, &bctl->cq_completion); } } @@ -1198,6 +1210,14 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx, } } +static void add_batch_error(batch_control *bctl, grpc_error *error) { + if (error == GRPC_ERROR_NONE) return; + if (bctl->error == GRPC_ERROR_NONE) { + bctl->error = GRPC_ERROR_CREATE("Call batch operation failed"); + } + bctl->error = grpc_error_add_child(bctl->error, error); +} + static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx, void *bctlp, grpc_error *error) { batch_control *bctl = bctlp; @@ -1205,9 +1225,8 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx, gpr_mu_lock(&call->mu); - if (error != GRPC_ERROR_NONE) { - bctl->error = GRPC_ERROR_REF(error); - } else { + add_batch_error(bctl, GRPC_ERROR_REF(error)); + if (error == GRPC_ERROR_NONE) { grpc_metadata_batch *md = &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */]; grpc_metadata_batch_filter(md, recv_initial_filter, call); @@ -1304,8 +1323,7 @@ static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, GRPC_ERROR_UNREF(error); error = GRPC_ERROR_NONE; } - GRPC_ERROR_UNREF(bctl->error); - bctl->error = GRPC_ERROR_REF(error); + add_batch_error(bctl, GRPC_ERROR_REF(error)); gpr_mu_unlock(&call->mu); if (gpr_unref(&bctl->steps_to_complete)) { post_batch_completion(exec_ctx, bctl); @@ -1341,6 +1359,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *stream_op = &bctl->op; memset(stream_op, 0, sizeof(*stream_op)); + stream_op->covered_by_poller = true; if (nops == 0) { GRPC_CALL_INTERNAL_REF(call, "completion"); diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h index 3a78fe3aa3..18af41b7fb 100644 --- a/src/core/lib/surface/call.h +++ b/src/core/lib/surface/call.h @@ -49,15 +49,29 @@ typedef void (*grpc_ioreq_completion_func)(grpc_exec_ctx *exec_ctx, grpc_call *call, int success, void *user_data); -grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call, - uint32_t propagation_mask, - grpc_completion_queue *cq, - /* if not NULL, it'll be used in lieu of \a cq */ - grpc_pollset_set *pollset_set_alternative, - const void *server_transport_data, - grpc_mdelem **add_initial_metadata, - size_t add_initial_metadata_count, - gpr_timespec send_deadline); +typedef struct grpc_call_create_args { + grpc_channel *channel; + + grpc_call *parent_call; + uint32_t propagation_mask; + + grpc_completion_queue *cq; + /* if not NULL, it'll be used in lieu of cq */ + grpc_pollset_set *pollset_set_alternative; + + const void *server_transport_data; + + grpc_mdelem **add_initial_metadata; + size_t add_initial_metadata_count; + + gpr_timespec send_deadline; +} grpc_call_create_args; + +/* Create a new call based on \a args. + Regardless of success or failure, always returns a valid new call into *call + */ +grpc_error *grpc_call_create(const grpc_call_create_args *args, + grpc_call **call); void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call, grpc_completion_queue *cq); diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c index 6adb70a987..92d783b78d 100644 --- a/src/core/lib/surface/channel.c +++ b/src/core/lib/surface/channel.c @@ -193,9 +193,21 @@ static grpc_call *grpc_channel_create_call_internal( send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority); } - return grpc_call_create(channel, parent_call, propagation_mask, cq, - pollset_set_alternative, NULL, send_metadata, - num_metadata, deadline); + grpc_call_create_args args; + memset(&args, 0, sizeof(args)); + args.channel = channel; + args.parent_call = parent_call; + args.propagation_mask = propagation_mask; + args.cq = cq; + args.pollset_set_alternative = pollset_set_alternative; + args.server_transport_data = NULL; + args.add_initial_metadata = send_metadata; + args.add_initial_metadata_count = num_metadata; + args.send_deadline = deadline; + + grpc_call *call; + GRPC_LOG_IF_ERROR("call_create", grpc_call_create(&args, &call)); + return call; } grpc_call *grpc_channel_create_call(grpc_channel *channel, diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c index 5978884db8..4e0feb56ac 100644 --- a/src/core/lib/surface/completion_queue.c +++ b/src/core/lib/surface/completion_queue.c @@ -39,6 +39,7 @@ #include <grpc/support/alloc.h> #include <grpc/support/atm.h> #include <grpc/support/log.h> +#include <grpc/support/string_util.h> #include <grpc/support/time.h> #include "src/core/lib/iomgr/pollset.h" @@ -50,6 +51,9 @@ #include "src/core/lib/surface/event_string.h" int grpc_trace_operation_failures; +#ifndef NDEBUG +int grpc_trace_pending_tags; +#endif typedef struct { grpc_pollset_worker **worker; @@ -67,6 +71,9 @@ struct grpc_completion_queue { gpr_refcount pending_events; /** Once owning_refs drops to zero, we will destroy the cq */ gpr_refcount owning_refs; + /** counter of how many things have ever been queued on this completion queue + useful for avoiding locks to check the queue */ + gpr_atm things_queued_ever; /** 0 initially, 1 once we've begun shutting down */ int shutdown; int shutdown_called; @@ -121,15 +128,6 @@ void grpc_cq_global_shutdown(void) { } } -struct grpc_cq_alarm { - grpc_timer alarm; - grpc_cq_completion completion; - /** completion queue where events about this alarm will be posted */ - grpc_completion_queue *cq; - /** user supplied tag */ - void *tag; -}; - grpc_completion_queue *grpc_completion_queue_create(void *reserved) { grpc_completion_queue *cc; GPR_ASSERT(!reserved); @@ -166,6 +164,7 @@ grpc_completion_queue *grpc_completion_queue_create(void *reserved) { cc->is_server_cq = 0; cc->is_non_listening_server_cq = 0; cc->num_pluckers = 0; + gpr_atm_no_barrier_store(&cc->things_queued_ever, 0); #ifndef NDEBUG cc->outstanding_tag_count = 0; #endif @@ -276,6 +275,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, GPR_ASSERT(found); #endif shutdown = gpr_unref(&cc->pending_events); + gpr_atm_no_barrier_fetch_add(&cc->things_queued_ever, 1); if (!shutdown) { cc->completed_tail->next = ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next); @@ -313,13 +313,66 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, GRPC_ERROR_UNREF(error); } +typedef struct { + gpr_atm last_seen_things_queued_ever; + grpc_completion_queue *cq; + gpr_timespec deadline; + grpc_cq_completion *stolen_completion; + void *tag; /* for pluck */ + bool first_loop; +} cq_is_finished_arg; + +static bool cq_is_next_finished(grpc_exec_ctx *exec_ctx, void *arg) { + cq_is_finished_arg *a = arg; + grpc_completion_queue *cq = a->cq; + GPR_ASSERT(a->stolen_completion == NULL); + gpr_atm current_last_seen_things_queued_ever = + gpr_atm_no_barrier_load(&cq->things_queued_ever); + if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) { + gpr_mu_lock(cq->mu); + a->last_seen_things_queued_ever = + gpr_atm_no_barrier_load(&cq->things_queued_ever); + if (cq->completed_tail != &cq->completed_head) { + a->stolen_completion = (grpc_cq_completion *)cq->completed_head.next; + cq->completed_head.next = a->stolen_completion->next & ~(uintptr_t)1; + if (a->stolen_completion == cq->completed_tail) { + cq->completed_tail = &cq->completed_head; + } + gpr_mu_unlock(cq->mu); + return true; + } + gpr_mu_unlock(cq->mu); + } + return !a->first_loop && + gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0; +} + +#ifndef NDEBUG +static void dump_pending_tags(grpc_completion_queue *cc) { + if (!grpc_trace_pending_tags) return; + + gpr_strvec v; + gpr_strvec_init(&v); + gpr_strvec_add(&v, gpr_strdup("PENDING TAGS:")); + for (size_t i = 0; i < cc->outstanding_tag_count; i++) { + char *s; + gpr_asprintf(&s, " %p", cc->outstanding_tags[i]); + gpr_strvec_add(&v, s); + } + char *out = gpr_strvec_flatten(&v, NULL); + gpr_strvec_destroy(&v); + gpr_log(GPR_DEBUG, "%s", out); + gpr_free(out); +} +#else +static void dump_pending_tags(grpc_completion_queue *cc) {} +#endif + grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, gpr_timespec deadline, void *reserved) { grpc_event ret; grpc_pollset_worker *worker = NULL; - int first_loop = 1; gpr_timespec now; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GPR_TIMER_BEGIN("grpc_completion_queue_next", 0); @@ -333,11 +386,33 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, reserved)); GPR_ASSERT(!reserved); + dump_pending_tags(cc); + deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); GRPC_CQ_INTERNAL_REF(cc, "next"); gpr_mu_lock(cc->mu); + cq_is_finished_arg is_finished_arg = { + .last_seen_things_queued_ever = + gpr_atm_no_barrier_load(&cc->things_queued_ever), + .cq = cc, + .deadline = deadline, + .stolen_completion = NULL, + .tag = NULL, + .first_loop = true}; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK( + cq_is_next_finished, &is_finished_arg); for (;;) { + if (is_finished_arg.stolen_completion != NULL) { + gpr_mu_unlock(cc->mu); + grpc_cq_completion *c = is_finished_arg.stolen_completion; + is_finished_arg.stolen_completion = NULL; + ret.type = GRPC_OP_COMPLETE; + ret.success = c->next & 1u; + ret.tag = c->tag; + c->done(&exec_ctx, c->done_arg, c); + break; + } if (cc->completed_tail != &cc->completed_head) { grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next; cc->completed_head.next = c->next & ~(uintptr_t)1; @@ -358,13 +433,13 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, break; } now = gpr_now(GPR_CLOCK_MONOTONIC); - if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { + if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) { gpr_mu_unlock(cc->mu); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; + dump_pending_tags(cc); break; } - first_loop = 0; /* Check alarms - these are a global resource so we just ping each time through on every pollset. May update deadline to ensure timely wakeups. @@ -387,13 +462,16 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, GRPC_ERROR_UNREF(err); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; + dump_pending_tags(cc); break; } } + is_finished_arg.first_loop = false; } GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); GRPC_CQ_INTERNAL_UNREF(cc, "next"); grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(is_finished_arg.stolen_completion == NULL); GPR_TIMER_END("grpc_completion_queue_next", 0); @@ -424,6 +502,37 @@ static void del_plucker(grpc_completion_queue *cc, void *tag, GPR_UNREACHABLE_CODE(return ); } +static bool cq_is_pluck_finished(grpc_exec_ctx *exec_ctx, void *arg) { + cq_is_finished_arg *a = arg; + grpc_completion_queue *cq = a->cq; + GPR_ASSERT(a->stolen_completion == NULL); + gpr_atm current_last_seen_things_queued_ever = + gpr_atm_no_barrier_load(&cq->things_queued_ever); + if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) { + gpr_mu_lock(cq->mu); + a->last_seen_things_queued_ever = + gpr_atm_no_barrier_load(&cq->things_queued_ever); + grpc_cq_completion *c; + grpc_cq_completion *prev = &cq->completed_head; + while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != + &cq->completed_head) { + if (c->tag == a->tag) { + prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1); + if (c == cq->completed_tail) { + cq->completed_tail = prev; + } + gpr_mu_unlock(cq->mu); + a->stolen_completion = c; + return true; + } + prev = c; + } + gpr_mu_unlock(cq->mu); + } + return !a->first_loop && + gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0; +} + grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, gpr_timespec deadline, void *reserved) { grpc_event ret; @@ -431,8 +540,6 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, grpc_cq_completion *prev; grpc_pollset_worker *worker = NULL; gpr_timespec now; - int first_loop = 1; - grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0); @@ -448,11 +555,33 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, } GPR_ASSERT(!reserved); + dump_pending_tags(cc); + deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); GRPC_CQ_INTERNAL_REF(cc, "pluck"); gpr_mu_lock(cc->mu); + cq_is_finished_arg is_finished_arg = { + .last_seen_things_queued_ever = + gpr_atm_no_barrier_load(&cc->things_queued_ever), + .cq = cc, + .deadline = deadline, + .stolen_completion = NULL, + .tag = tag, + .first_loop = true}; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK( + cq_is_pluck_finished, &is_finished_arg); for (;;) { + if (is_finished_arg.stolen_completion != NULL) { + gpr_mu_unlock(cc->mu); + c = is_finished_arg.stolen_completion; + is_finished_arg.stolen_completion = NULL; + ret.type = GRPC_OP_COMPLETE; + ret.success = c->next & 1u; + ret.tag = c->tag; + c->done(&exec_ctx, c->done_arg, c); + break; + } prev = &cc->completed_head; while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != &cc->completed_head) { @@ -485,17 +614,18 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, memset(&ret, 0, sizeof(ret)); /* TODO(ctiller): should we use a different result here */ ret.type = GRPC_QUEUE_TIMEOUT; + dump_pending_tags(cc); break; } now = gpr_now(GPR_CLOCK_MONOTONIC); - if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { + if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) { del_plucker(cc, tag, &worker); gpr_mu_unlock(cc->mu); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; + dump_pending_tags(cc); break; } - first_loop = 0; /* Check alarms - these are a global resource so we just ping each time through on every pollset. May update deadline to ensure timely wakeups. @@ -518,15 +648,18 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag, GRPC_ERROR_UNREF(err); memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; + dump_pending_tags(cc); break; } } + is_finished_arg.first_loop = false; del_plucker(cc, tag, &worker); } done: GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret); GRPC_CQ_INTERNAL_UNREF(cc, "pluck"); grpc_exec_ctx_finish(&exec_ctx); + GPR_ASSERT(is_finished_arg.stolen_completion == NULL); GPR_TIMER_END("grpc_completion_queue_pluck", 0); diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h index 4dbf3aae63..c1cafba5f2 100644 --- a/src/core/lib/surface/completion_queue.h +++ b/src/core/lib/surface/completion_queue.h @@ -44,6 +44,9 @@ extern int grpc_cq_pluck_trace; extern int grpc_cq_event_timeout_trace; extern int grpc_trace_operation_failures; +#ifndef NDEBUG +extern int grpc_trace_pending_tags; +#endif typedef struct grpc_cq_completion { /** user supplied tag */ diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c index 289f4ce8e8..8ca0643ba7 100644 --- a/src/core/lib/surface/init.c +++ b/src/core/lib/surface/init.c @@ -184,12 +184,16 @@ void grpc_init(void) { grpc_register_tracer("compression", &grpc_compression_trace); grpc_register_tracer("queue_pluck", &grpc_cq_pluck_trace); grpc_register_tracer("combiner", &grpc_combiner_trace); + grpc_register_tracer("server_channel", &grpc_server_channel_trace); // Default pluck trace to 1 grpc_cq_pluck_trace = 1; grpc_register_tracer("queue_timeout", &grpc_cq_event_timeout_trace); // Default timeout trace to 1 grpc_cq_event_timeout_trace = 1; grpc_register_tracer("op_failure", &grpc_trace_operation_failures); +#ifndef NDEBUG + grpc_register_tracer("pending_tags", &grpc_trace_pending_tags); +#endif grpc_security_pre_init(); grpc_iomgr_init(); grpc_executor_init(); diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c index 7300d79b9f..3a90308058 100644 --- a/src/core/lib/surface/server.c +++ b/src/core/lib/surface/server.c @@ -71,6 +71,8 @@ typedef struct registered_method registered_method; typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type; +int grpc_server_channel_trace = 0; + typedef struct requested_call { requested_call_type type; size_t cq_idx; @@ -280,6 +282,7 @@ static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_channel_element *elem; op->send_goaway = send_goaway; + op->set_accept_stream = true; sc->slice = gpr_slice_from_copied_string("Server shutdown"); op->goaway_message = &sc->slice; op->goaway_status = GRPC_STATUS_OK; @@ -439,6 +442,13 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand, chand->finish_destroy_channel_closure.cb = finish_destroy_channel; chand->finish_destroy_channel_closure.cb_arg = chand; + if (grpc_server_channel_trace && error != GRPC_ERROR_NONE) { + const char *msg = grpc_error_string(error); + gpr_log(GPR_INFO, "Disconnected client: %s", msg); + grpc_error_free_string(msg); + } + GRPC_ERROR_UNREF(error); + grpc_transport_op *op = grpc_make_transport_op(&chand->finish_destroy_channel_closure); op->set_accept_stream = true; @@ -446,13 +456,6 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand, grpc_channel_stack_element( grpc_channel_get_channel_stack(chand->channel), 0), op); - - if (error != GRPC_ERROR_NONE) { - const char *msg = grpc_error_string(error); - gpr_log(GPR_INFO, "Disconnected client: %s", msg); - grpc_error_free_string(msg); - } - GRPC_ERROR_UNREF(error); } static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) { @@ -773,8 +776,7 @@ static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr, GRPC_ERROR_CREATE_REFERENCING("Missing :authority or :path", &error, 1); } - grpc_exec_ctx_sched(exec_ctx, calld->on_done_recv_initial_metadata, error, - NULL); + grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata, error); } static void server_mutate_op(grpc_call_element *elem, @@ -829,11 +831,20 @@ static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd, const void *transport_server_data) { channel_data *chand = cd; /* create a call */ - grpc_call *call = grpc_call_create(chand->channel, NULL, 0, NULL, NULL, - transport_server_data, NULL, 0, - gpr_inf_future(GPR_CLOCK_MONOTONIC)); + grpc_call_create_args args; + memset(&args, 0, sizeof(args)); + args.channel = chand->channel; + args.server_transport_data = transport_server_data; + args.send_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC); + grpc_call *call; + grpc_error *error = grpc_call_create(&args, &call); grpc_call_element *elem = grpc_call_stack_element(grpc_call_get_call_stack(call), 0); + if (error != GRPC_ERROR_NONE) { + got_initial_metadata(exec_ctx, elem, error); + GRPC_ERROR_UNREF(error); + return; + } call_data *calld = elem->call_data; grpc_op op; memset(&op, 0, sizeof(op)); diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h index 551a40a4ff..a85d9f4964 100644 --- a/src/core/lib/surface/server.h +++ b/src/core/lib/surface/server.h @@ -40,6 +40,9 @@ extern const grpc_channel_filter grpc_server_top_filter; +/** Lightweight tracing of server channel state */ +extern int grpc_server_channel_trace; + /* Add a listener to the server: when the server starts, it will call start, and when it shuts down, it will call destroy */ void grpc_server_add_listener( diff --git a/src/core/lib/transport/connectivity_state.c b/src/core/lib/transport/connectivity_state.c index 68d05e3a85..fdb5307814 100644 --- a/src/core/lib/transport/connectivity_state.c +++ b/src/core/lib/transport/connectivity_state.c @@ -180,7 +180,8 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, *w->current = tracker->current_state; tracker->watchers = w->next; if (grpc_connectivity_state_trace) { - gpr_log(GPR_DEBUG, "NOTIFY: %p", w->notify); + gpr_log(GPR_DEBUG, "NOTIFY: %p %s: %p", tracker, tracker->name, + w->notify); } grpc_exec_ctx_sched(exec_ctx, w->notify, GRPC_ERROR_REF(tracker->current_error), NULL); diff --git a/src/core/lib/transport/mdstr_hash_table.c b/src/core/lib/transport/mdstr_hash_table.c new file mode 100644 index 0000000000..4be0536dd7 --- /dev/null +++ b/src/core/lib/transport/mdstr_hash_table.c @@ -0,0 +1,142 @@ +// +// Copyright 2016, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include "src/core/lib/transport/mdstr_hash_table.h" + +#include <stdbool.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +#include "src/core/lib/transport/metadata.h" + +struct grpc_mdstr_hash_table { + gpr_refcount refs; + size_t num_entries; + grpc_mdstr_hash_table_entry* entries; +}; + +// Helper function for insert and get operations that performs quadratic +// probing (https://en.wikipedia.org/wiki/Quadratic_probing). +static size_t grpc_mdstr_hash_table_find_index( + const grpc_mdstr_hash_table* table, const grpc_mdstr* key, + bool find_empty) { + for (size_t i = 0; i < table->num_entries; ++i) { + const size_t idx = (key->hash + i * i) % table->num_entries; + if (table->entries[idx].key == NULL) + return find_empty ? idx : table->num_entries; + if (table->entries[idx].key == key) return idx; + } + return table->num_entries; // Not found. +} + +static void grpc_mdstr_hash_table_add( + grpc_mdstr_hash_table* table, grpc_mdstr* key, void* value, + const grpc_mdstr_hash_table_vtable* vtable) { + GPR_ASSERT(value != NULL); + const size_t idx = + grpc_mdstr_hash_table_find_index(table, key, true /* find_empty */); + GPR_ASSERT(idx != table->num_entries); // Table should never be full. + grpc_mdstr_hash_table_entry* entry = &table->entries[idx]; + entry->key = GRPC_MDSTR_REF(key); + entry->value = vtable->copy_value(value); + entry->vtable = vtable; +} + +grpc_mdstr_hash_table* grpc_mdstr_hash_table_create( + size_t num_entries, grpc_mdstr_hash_table_entry* entries) { + grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table)); + memset(table, 0, sizeof(*table)); + gpr_ref_init(&table->refs, 1); + // Quadratic probing gets best performance when the table is no more + // than half full. + table->num_entries = num_entries * 2; + const size_t entry_size = + sizeof(grpc_mdstr_hash_table_entry) * table->num_entries; + table->entries = gpr_malloc(entry_size); + memset(table->entries, 0, entry_size); + for (size_t i = 0; i < num_entries; ++i) { + grpc_mdstr_hash_table_entry* entry = &entries[i]; + grpc_mdstr_hash_table_add(table, entry->key, entry->value, entry->vtable); + } + return table; +} + +grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table) { + if (table != NULL) gpr_ref(&table->refs); + return table; +} + +int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) { + if (table != NULL && gpr_unref(&table->refs)) { + for (size_t i = 0; i < table->num_entries; ++i) { + grpc_mdstr_hash_table_entry* entry = &table->entries[i]; + if (entry->key != NULL) { + GRPC_MDSTR_UNREF(entry->key); + entry->vtable->destroy_value(entry->value); + } + } + gpr_free(table->entries); + gpr_free(table); + return 1; + } + return 0; +} + +void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, + const grpc_mdstr* key) { + const size_t idx = + grpc_mdstr_hash_table_find_index(table, key, false /* find_empty */); + if (idx == table->num_entries) return NULL; // Not found. + return table->entries[idx].value; +} + +int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1, + const grpc_mdstr_hash_table* table2) { + // Compare by num_entries. + if (table1->num_entries < table2->num_entries) return -1; + if (table1->num_entries > table2->num_entries) return 1; + for (size_t i = 0; i < table1->num_entries; ++i) { + grpc_mdstr_hash_table_entry* e1 = &table1->entries[i]; + grpc_mdstr_hash_table_entry* e2 = &table2->entries[i]; + // Compare keys by hash value. + if (e1->key->hash < e2->key->hash) return -1; + if (e1->key->hash > e2->key->hash) return 1; + // Compare by vtable (pointer equality). + if (e1->vtable < e2->vtable) return -1; + if (e1->vtable > e2->vtable) return 1; + // Compare values via vtable. + const int value_result = e1->vtable->compare_value(e1->value, e2->value); + if (value_result != 0) return value_result; + } + return 0; +} diff --git a/src/core/lib/transport/mdstr_hash_table.h b/src/core/lib/transport/mdstr_hash_table.h new file mode 100644 index 0000000000..52e5b023db --- /dev/null +++ b/src/core/lib/transport/mdstr_hash_table.h @@ -0,0 +1,83 @@ +/* + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H +#define GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H + +#include "src/core/lib/transport/metadata.h" + +/** Hash table implementation. + * + * This implementation uses open addressing + * (https://en.wikipedia.org/wiki/Open_addressing) with quadratic + * probing (https://en.wikipedia.org/wiki/Quadratic_probing). + * + * The keys are \a grpc_mdstr objects. The values are arbitrary pointers + * with a common vtable. + * + * Hash tables are intentionally immutable, to avoid the need for locking. + */ + +typedef struct grpc_mdstr_hash_table grpc_mdstr_hash_table; + +typedef struct grpc_mdstr_hash_table_vtable { + void (*destroy_value)(void* value); + void* (*copy_value)(void* value); + int (*compare_value)(void* value1, void* value2); +} grpc_mdstr_hash_table_vtable; + +typedef struct grpc_mdstr_hash_table_entry { + grpc_mdstr* key; + void* value; /* Must not be NULL. */ + const grpc_mdstr_hash_table_vtable* vtable; +} grpc_mdstr_hash_table_entry; + +/** Creates a new hash table of containing \a entries, which is an array + of length \a num_entries. + Creates its own copy of all keys and values from \a entries. */ +grpc_mdstr_hash_table* grpc_mdstr_hash_table_create( + size_t num_entries, grpc_mdstr_hash_table_entry* entries); + +grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table); +/** Returns 1 when \a table is destroyed. */ +int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table); + +/** Returns the value from \a table associated with \a key. + Returns NULL if \a key is not found. */ +void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, + const grpc_mdstr* key); + +/** Compares two hash tables. + The sort order is stable but undefined. */ +int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1, + const grpc_mdstr_hash_table* table2); + +#endif /* GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H */ diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c index 5e0352a467..f019ef156a 100644 --- a/src/core/lib/transport/static_metadata.c +++ b/src/core/lib/transport/static_metadata.c @@ -126,9 +126,9 @@ const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = { "if-range", "if-unmodified-since", "last-modified", + "lb-cost", + "lb-token", "link", - "load-reporting-initial", - "load-reporting-trailing", "location", "max-forwards", ":method", diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h index 5b9ee1a60a..e0a8196419 100644 --- a/src/core/lib/transport/static_metadata.h +++ b/src/core/lib/transport/static_metadata.h @@ -175,12 +175,12 @@ extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT]; #define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[62]) /* "last-modified" */ #define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[63]) +/* "lb-cost" */ +#define GRPC_MDSTR_LB_COST (&grpc_static_mdstr_table[64]) +/* "lb-token" */ +#define GRPC_MDSTR_LB_TOKEN (&grpc_static_mdstr_table[65]) /* "link" */ -#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[64]) -/* "load-reporting-initial" */ -#define GRPC_MDSTR_LOAD_REPORTING_INITIAL (&grpc_static_mdstr_table[65]) -/* "load-reporting-trailing" */ -#define GRPC_MDSTR_LOAD_REPORTING_TRAILING (&grpc_static_mdstr_table[66]) +#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[66]) /* "location" */ #define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[67]) /* "max-forwards" */ @@ -337,13 +337,12 @@ extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT]; #define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY (&grpc_static_mdelem_table[44]) /* "last-modified": "" */ #define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45]) +/* "lb-cost": "" */ +#define GRPC_MDELEM_LB_COST_EMPTY (&grpc_static_mdelem_table[46]) +/* "lb-token": "" */ +#define GRPC_MDELEM_LB_TOKEN_EMPTY (&grpc_static_mdelem_table[47]) /* "link": "" */ -#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[46]) -/* "load-reporting-initial": "" */ -#define GRPC_MDELEM_LOAD_REPORTING_INITIAL_EMPTY (&grpc_static_mdelem_table[47]) -/* "load-reporting-trailing": "" */ -#define GRPC_MDELEM_LOAD_REPORTING_TRAILING_EMPTY \ - (&grpc_static_mdelem_table[48]) +#define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[48]) /* "location": "" */ #define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[49]) /* "max-forwards": "" */ diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c index 82fc605218..75aec7a5b4 100644 --- a/src/core/lib/transport/transport.c +++ b/src/core/lib/transport/transport.c @@ -46,8 +46,9 @@ #ifdef GRPC_STREAM_REFCOUNT_DEBUG void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) { gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); - gpr_log(GPR_DEBUG, "%s %p:%p REF %d->%d %s", refcount->object_type, - refcount, refcount->destroy.cb_arg, (int)val, (int)val + 1, reason); + gpr_log(GPR_DEBUG, "%s %p:%p REF %" PRIdPTR "->%" PRIdPTR " %s", + refcount->object_type, refcount, refcount->destroy.cb_arg, val, + val + 1, reason); #else void grpc_stream_ref(grpc_stream_refcount *refcount) { #endif @@ -58,8 +59,9 @@ void grpc_stream_ref(grpc_stream_refcount *refcount) { void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount, const char *reason) { gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); - gpr_log(GPR_DEBUG, "%s %p:%p UNREF %d->%d %s", refcount->object_type, - refcount, refcount->destroy.cb_arg, (int)val, (int)val - 1, reason); + gpr_log(GPR_DEBUG, "%s %p:%p UNREF %" PRIdPTR "->%" PRIdPTR " %s", + refcount->object_type, refcount, refcount->destroy.cb_arg, val, + val - 1, reason); #else void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount) { @@ -274,3 +276,28 @@ grpc_transport_op *grpc_make_transport_op(grpc_closure *on_complete) { op->op.on_consumed = &op->outer_on_complete; return &op->op; } + +typedef struct { + grpc_closure outer_on_complete; + grpc_closure *inner_on_complete; + grpc_transport_stream_op op; +} made_transport_stream_op; + +static void destroy_made_transport_stream_op(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + made_transport_stream_op *op = arg; + grpc_exec_ctx_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error), + NULL); + gpr_free(op); +} + +grpc_transport_stream_op *grpc_make_transport_stream_op( + grpc_closure *on_complete) { + made_transport_stream_op *op = gpr_malloc(sizeof(*op)); + grpc_closure_init(&op->outer_on_complete, destroy_made_transport_stream_op, + op); + op->inner_on_complete = on_complete; + memset(&op->op, 0, sizeof(op->op)); + op->op.on_complete = &op->outer_on_complete; + return &op->op; +} diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index 8dc393fd61..50253ebad1 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -113,6 +113,10 @@ typedef struct grpc_transport_stream_op { have been completed. */ grpc_closure *on_complete; + /** Is the completion of this op covered by a poller (if false: the op should + complete independently of some pollset being polled) */ + bool covered_by_poller; + /** Send initial metadata to the peer, from the provided metadata batch. idempotent_request MUST be set if this is non-null */ grpc_metadata_batch *send_initial_metadata; @@ -252,6 +256,7 @@ void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op, gpr_slice *optional_message); char *grpc_transport_stream_op_string(grpc_transport_stream_op *op); +char *grpc_transport_op_string(grpc_transport_op *op); /* Send a batch of operations on a transport @@ -293,6 +298,10 @@ char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx, /* Allocate a grpc_transport_op, and preconfigure the on_consumed closure to \a on_consumed and then delete the returned transport op */ grpc_transport_op *grpc_make_transport_op(grpc_closure *on_consumed); +/* Allocate a grpc_transport_stream_op, and preconfigure the on_consumed closure + to \a on_consumed and then delete the returned transport op */ +grpc_transport_stream_op *grpc_make_transport_stream_op( + grpc_closure *on_consumed); #ifdef __cplusplus } diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c index 138591db2a..533ec52077 100644 --- a/src/core/lib/transport/transport_op_string.c +++ b/src/core/lib/transport/transport_op_string.c @@ -41,6 +41,7 @@ #include <grpc/support/string_util.h> #include <grpc/support/useful.h> #include "src/core/lib/support/string.h" +#include "src/core/lib/transport/connectivity_state.h" /* These routines are here to facilitate debugging - they produce string representations of various transport data structures */ @@ -72,56 +73,51 @@ static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) { char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { char *tmp; char *out; - int first = 1; gpr_strvec b; gpr_strvec_init(&b); + gpr_strvec_add( + &b, gpr_strdup(op->covered_by_poller ? "[COVERED]" : "[UNCOVERED]")); + if (op->send_initial_metadata != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; + gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{")); put_metadata_list(&b, *op->send_initial_metadata); gpr_strvec_add(&b, gpr_strdup("}")); } if (op->send_message != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; + gpr_strvec_add(&b, gpr_strdup(" ")); gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d", op->send_message->flags, op->send_message->length); gpr_strvec_add(&b, tmp); } if (op->send_trailing_metadata != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; + gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{")); put_metadata_list(&b, *op->send_trailing_metadata); gpr_strvec_add(&b, gpr_strdup("}")); } if (op->recv_initial_metadata != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; + gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA")); } if (op->recv_message != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; + gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE")); } if (op->recv_trailing_metadata != NULL) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; + gpr_strvec_add(&b, gpr_strdup(" ")); gpr_strvec_add(&b, gpr_strdup("RECV_TRAILING_METADATA")); } if (op->cancel_error != GRPC_ERROR_NONE) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; + gpr_strvec_add(&b, gpr_strdup(" ")); const char *msg = grpc_error_string(op->cancel_error); gpr_asprintf(&tmp, "CANCEL:%s", msg); grpc_error_free_string(msg); @@ -129,8 +125,7 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { } if (op->close_error != GRPC_ERROR_NONE) { - if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); - first = 0; + gpr_strvec_add(&b, gpr_strdup(" ")); const char *msg = grpc_error_string(op->close_error); gpr_asprintf(&tmp, "CLOSE:%s", msg); grpc_error_free_string(msg); @@ -143,6 +138,82 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { return out; } +char *grpc_transport_op_string(grpc_transport_op *op) { + char *tmp; + char *out; + bool first = true; + + gpr_strvec b; + gpr_strvec_init(&b); + + if (op->on_connectivity_state_change != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = false; + if (op->connectivity_state != NULL) { + gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:from=%s", + op->on_connectivity_state_change, + grpc_connectivity_state_name(*op->connectivity_state)); + gpr_strvec_add(&b, tmp); + } else { + gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:unsubscribe", + op->on_connectivity_state_change); + gpr_strvec_add(&b, tmp); + } + } + + if (op->disconnect_with_error != GRPC_ERROR_NONE) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = false; + const char *err = grpc_error_string(op->disconnect_with_error); + gpr_asprintf(&tmp, "DISCONNECT:%s", err); + gpr_strvec_add(&b, tmp); + grpc_error_free_string(err); + } + + if (op->send_goaway) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = false; + char *msg = op->goaway_message == NULL + ? "null" + : gpr_dump_slice(*op->goaway_message, + GPR_DUMP_ASCII | GPR_DUMP_HEX); + gpr_asprintf(&tmp, "SEND_GOAWAY:status=%d:msg=%s", op->goaway_status, msg); + if (op->goaway_message != NULL) gpr_free(msg); + gpr_strvec_add(&b, tmp); + } + + if (op->set_accept_stream) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = false; + gpr_asprintf(&tmp, "SET_ACCEPT_STREAM:%p(%p,...)", op->set_accept_stream_fn, + op->set_accept_stream_user_data); + gpr_strvec_add(&b, tmp); + } + + if (op->bind_pollset != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = false; + gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET")); + } + + if (op->bind_pollset_set != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = false; + gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET_SET")); + } + + if (op->send_ping != NULL) { + if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); + first = false; + gpr_strvec_add(&b, gpr_strdup("SEND_PING")); + } + + out = gpr_strvec_flatten(&b, NULL); + gpr_strvec_destroy(&b); + + return out; +} + void grpc_call_log_op(char *file, int line, gpr_log_severity severity, grpc_call_element *elem, grpc_transport_stream_op *op) { char *str = grpc_transport_stream_op_string(op); diff --git a/src/cpp/README.md b/src/cpp/README.md index 8c0f85e5ff..d9b521317a 100644 --- a/src/cpp/README.md +++ b/src/cpp/README.md @@ -3,10 +3,6 @@ This directory contains source code for C++ implementation of gRPC. -#Status - -Beta - #Pre-requisites ##Linux diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc index 5b6aaa777b..b6008f47b1 100644 --- a/src/cpp/client/client_context.cc +++ b/src/cpp/client/client_context.cc @@ -59,7 +59,8 @@ static ClientContext::GlobalCallbacks* g_client_callbacks = ClientContext::ClientContext() : initial_metadata_received_(false), - fail_fast_(true), + wait_for_ready_(false), + wait_for_ready_explicitly_set_(false), idempotent_(false), cacheable_(false), call_(nullptr), diff --git a/src/core/lib/iomgr/workqueue_posix.h b/src/cpp/test/server_context_test_spouse.cc index 03ee21cef7..b93152eea0 100644 --- a/src/core/lib/iomgr/workqueue_posix.h +++ b/src/cpp/test/server_context_test_spouse.cc @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,31 +31,22 @@ * */ -#ifndef GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H -#define GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H - -#include "src/core/lib/iomgr/wakeup_fd_posix.h" -#include "src/core/lib/support/mpscq.h" - -struct grpc_fd; - -struct grpc_workqueue { - gpr_refcount refs; - gpr_mpscq queue; - // state is: - // lower bit - zero if orphaned - // other bits - number of items enqueued - gpr_atm state; - - grpc_wakeup_fd wakeup_fd; - struct grpc_fd *wakeup_read_fd; - - grpc_closure read_closure; -}; - -/** Create a work queue. Returns an error if creation fails. If creation - succeeds, sets *workqueue to point to it. */ -grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx, - grpc_workqueue **workqueue); - -#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H */ +#include <grpc++/test/server_context_test_spouse.h> + +namespace grpc { +namespace testing { + +void ServerContextTestSpouse::AddClientMetadata(const grpc::string& key, + const grpc::string& value) { + client_metadata_storage_.insert( + std::pair<grpc::string, grpc::string>(key, value)); + ctx_->client_metadata_.clear(); + for (auto iter = client_metadata_storage_.begin(); + iter != client_metadata_storage_.end(); ++iter) { + ctx_->client_metadata_.insert(std::pair<grpc::string_ref, grpc::string_ref>( + iter->first.c_str(), iter->second.c_str())); + } +} + +} // namespace testing +} // namespace grpc diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 6a2f520163..ebb7e0021e 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -277,20 +277,31 @@ namespace Grpc.Core.Internal } } - internal class NoSuchMethodCallHandler : IServerCallHandler + internal class UnimplementedMethodCallHandler : IServerCallHandler { - public static readonly NoSuchMethodCallHandler Instance = new NoSuchMethodCallHandler(); + public static readonly UnimplementedMethodCallHandler Instance = new UnimplementedMethodCallHandler(); - public async Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq) + DuplexStreamingServerCallHandler<byte[], byte[]> callHandlerImpl; + + public UnimplementedMethodCallHandler() { - // We don't care about the payload type here. - var asyncCall = new AsyncCallServer<byte[], byte[]>( - (payload) => payload, (payload) => payload, newRpc.Server); - - asyncCall.Initialize(newRpc.Call, cq); - var finishedTask = asyncCall.ServerSideCallAsync(); - await asyncCall.SendStatusFromServerAsync(new Status(StatusCode.Unimplemented, ""), Metadata.Empty, null).ConfigureAwait(false); - await finishedTask.ConfigureAwait(false); + var marshaller = new Marshaller<byte[]>((payload) => payload, (payload) => payload); + var method = new Method<byte[], byte[]>(MethodType.DuplexStreaming, "", "", marshaller, marshaller); + this.callHandlerImpl = new DuplexStreamingServerCallHandler<byte[], byte[]>(method, new DuplexStreamingServerMethod<byte[], byte[]>(UnimplementedMethod)); + } + + /// <summary> + /// Handler used for unimplemented method. + /// </summary> + private Task UnimplementedMethod(IAsyncStreamReader<byte[]> requestStream, IServerStreamWriter<byte[]> responseStream, ServerCallContext ctx) + { + ctx.Status = new Status(StatusCode.Unimplemented, ""); + return Task.FromResult<object>(null); + } + + public Task HandleCall(ServerRpcNew newRpc, CompletionQueueSafeHandle cq) + { + return callHandlerImpl.HandleCall(newRpc, cq); } } diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index 3b554e5e87..dd4a405ed9 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -317,7 +317,7 @@ namespace Grpc.Core IServerCallHandler callHandler; if (!callHandlers.TryGetValue(newRpc.Method, out callHandler)) { - callHandler = NoSuchMethodCallHandler.Instance; + callHandler = UnimplementedMethodCallHandler.Instance; } await callHandler.HandleCall(newRpc, cq).ConfigureAwait(false); } diff --git a/src/csharp/Grpc.Examples/Math.cs b/src/csharp/Grpc.Examples/Math.cs index a17228c8c5..fae4fd3c26 100644 --- a/src/csharp/Grpc.Examples/Math.cs +++ b/src/csharp/Grpc.Examples/Math.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Math { /// <summary>Holder for reflection information generated from math.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class MathReflection { #region Descriptor @@ -46,30 +45,35 @@ namespace Math { } #region Messages - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class DivArgs : pb::IMessage<DivArgs> { private static readonly pb::MessageParser<DivArgs> _parser = new pb::MessageParser<DivArgs>(() => new DivArgs()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<DivArgs> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Math.MathReflection.Descriptor.MessageTypes[0]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public DivArgs() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public DivArgs(DivArgs other) : this() { dividend_ = other.dividend_; divisor_ = other.divisor_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public DivArgs Clone() { return new DivArgs(this); } @@ -77,6 +81,7 @@ namespace Math { /// <summary>Field number for the "dividend" field.</summary> public const int DividendFieldNumber = 1; private long dividend_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public long Dividend { get { return dividend_; } set { @@ -87,6 +92,7 @@ namespace Math { /// <summary>Field number for the "divisor" field.</summary> public const int DivisorFieldNumber = 2; private long divisor_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public long Divisor { get { return divisor_; } set { @@ -94,10 +100,12 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as DivArgs); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(DivArgs other) { if (ReferenceEquals(other, null)) { return false; @@ -110,6 +118,7 @@ namespace Math { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Dividend != 0L) hash ^= Dividend.GetHashCode(); @@ -117,10 +126,12 @@ namespace Math { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Dividend != 0L) { output.WriteRawTag(8); @@ -132,6 +143,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Dividend != 0L) { @@ -143,6 +155,7 @@ namespace Math { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(DivArgs other) { if (other == null) { return; @@ -155,6 +168,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -176,30 +190,35 @@ namespace Math { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class DivReply : pb::IMessage<DivReply> { private static readonly pb::MessageParser<DivReply> _parser = new pb::MessageParser<DivReply>(() => new DivReply()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<DivReply> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Math.MathReflection.Descriptor.MessageTypes[1]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public DivReply() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public DivReply(DivReply other) : this() { quotient_ = other.quotient_; remainder_ = other.remainder_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public DivReply Clone() { return new DivReply(this); } @@ -207,6 +226,7 @@ namespace Math { /// <summary>Field number for the "quotient" field.</summary> public const int QuotientFieldNumber = 1; private long quotient_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public long Quotient { get { return quotient_; } set { @@ -217,6 +237,7 @@ namespace Math { /// <summary>Field number for the "remainder" field.</summary> public const int RemainderFieldNumber = 2; private long remainder_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public long Remainder { get { return remainder_; } set { @@ -224,10 +245,12 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as DivReply); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(DivReply other) { if (ReferenceEquals(other, null)) { return false; @@ -240,6 +263,7 @@ namespace Math { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Quotient != 0L) hash ^= Quotient.GetHashCode(); @@ -247,10 +271,12 @@ namespace Math { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Quotient != 0L) { output.WriteRawTag(8); @@ -262,6 +288,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Quotient != 0L) { @@ -273,6 +300,7 @@ namespace Math { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(DivReply other) { if (other == null) { return; @@ -285,6 +313,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -306,29 +335,34 @@ namespace Math { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class FibArgs : pb::IMessage<FibArgs> { private static readonly pb::MessageParser<FibArgs> _parser = new pb::MessageParser<FibArgs>(() => new FibArgs()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<FibArgs> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Math.MathReflection.Descriptor.MessageTypes[2]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public FibArgs() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public FibArgs(FibArgs other) : this() { limit_ = other.limit_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public FibArgs Clone() { return new FibArgs(this); } @@ -336,6 +370,7 @@ namespace Math { /// <summary>Field number for the "limit" field.</summary> public const int LimitFieldNumber = 1; private long limit_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public long Limit { get { return limit_; } set { @@ -343,10 +378,12 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as FibArgs); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(FibArgs other) { if (ReferenceEquals(other, null)) { return false; @@ -358,16 +395,19 @@ namespace Math { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Limit != 0L) hash ^= Limit.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Limit != 0L) { output.WriteRawTag(8); @@ -375,6 +415,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Limit != 0L) { @@ -383,6 +424,7 @@ namespace Math { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(FibArgs other) { if (other == null) { return; @@ -392,6 +434,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -409,29 +452,34 @@ namespace Math { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Num : pb::IMessage<Num> { private static readonly pb::MessageParser<Num> _parser = new pb::MessageParser<Num>(() => new Num()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Num> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Math.MathReflection.Descriptor.MessageTypes[3]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Num() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Num(Num other) : this() { num_ = other.num_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Num Clone() { return new Num(this); } @@ -439,6 +487,7 @@ namespace Math { /// <summary>Field number for the "num" field.</summary> public const int Num_FieldNumber = 1; private long num_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public long Num_ { get { return num_; } set { @@ -446,10 +495,12 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Num); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Num other) { if (ReferenceEquals(other, null)) { return false; @@ -461,16 +512,19 @@ namespace Math { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Num_ != 0L) hash ^= Num_.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Num_ != 0L) { output.WriteRawTag(8); @@ -478,6 +532,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Num_ != 0L) { @@ -486,6 +541,7 @@ namespace Math { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Num other) { if (other == null) { return; @@ -495,6 +551,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -512,29 +569,34 @@ namespace Math { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class FibReply : pb::IMessage<FibReply> { private static readonly pb::MessageParser<FibReply> _parser = new pb::MessageParser<FibReply>(() => new FibReply()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<FibReply> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Math.MathReflection.Descriptor.MessageTypes[4]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public FibReply() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public FibReply(FibReply other) : this() { count_ = other.count_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public FibReply Clone() { return new FibReply(this); } @@ -542,6 +604,7 @@ namespace Math { /// <summary>Field number for the "count" field.</summary> public const int CountFieldNumber = 1; private long count_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public long Count { get { return count_; } set { @@ -549,10 +612,12 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as FibReply); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(FibReply other) { if (ReferenceEquals(other, null)) { return false; @@ -564,16 +629,19 @@ namespace Math { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Count != 0L) hash ^= Count.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Count != 0L) { output.WriteRawTag(8); @@ -581,6 +649,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Count != 0L) { @@ -589,6 +658,7 @@ namespace Math { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(FibReply other) { if (other == null) { return; @@ -598,6 +668,7 @@ namespace Math { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs index 25abc51419..d6ba61e7dc 100644 --- a/src/csharp/Grpc.Examples/MathGrpc.cs +++ b/src/csharp/Grpc.Examples/MathGrpc.cs @@ -234,6 +234,7 @@ namespace Math { { return CallInvoker.AsyncClientStreamingCall(__Method_Sum, null, options); } + /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> protected override MathClient NewInstance(ClientBaseConfiguration configuration) { return new MathClient(configuration); diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs index 100ad187d7..b8e2e2274c 100644 --- a/src/csharp/Grpc.HealthCheck/Health.cs +++ b/src/csharp/Grpc.HealthCheck/Health.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Grpc.Health.V1 { /// <summary>Holder for reflection information generated from health.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class HealthReflection { #region Descriptor @@ -42,29 +41,34 @@ namespace Grpc.Health.V1 { } #region Messages - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class HealthCheckRequest : pb::IMessage<HealthCheckRequest> { private static readonly pb::MessageParser<HealthCheckRequest> _parser = new pb::MessageParser<HealthCheckRequest>(() => new HealthCheckRequest()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<HealthCheckRequest> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Health.V1.HealthReflection.Descriptor.MessageTypes[0]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HealthCheckRequest() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HealthCheckRequest(HealthCheckRequest other) : this() { service_ = other.service_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HealthCheckRequest Clone() { return new HealthCheckRequest(this); } @@ -72,6 +76,7 @@ namespace Grpc.Health.V1 { /// <summary>Field number for the "service" field.</summary> public const int ServiceFieldNumber = 1; private string service_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string Service { get { return service_; } set { @@ -79,10 +84,12 @@ namespace Grpc.Health.V1 { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as HealthCheckRequest); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(HealthCheckRequest other) { if (ReferenceEquals(other, null)) { return false; @@ -94,16 +101,19 @@ namespace Grpc.Health.V1 { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Service.Length != 0) hash ^= Service.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Service.Length != 0) { output.WriteRawTag(10); @@ -111,6 +121,7 @@ namespace Grpc.Health.V1 { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Service.Length != 0) { @@ -119,6 +130,7 @@ namespace Grpc.Health.V1 { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(HealthCheckRequest other) { if (other == null) { return; @@ -128,6 +140,7 @@ namespace Grpc.Health.V1 { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -145,29 +158,34 @@ namespace Grpc.Health.V1 { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class HealthCheckResponse : pb::IMessage<HealthCheckResponse> { private static readonly pb::MessageParser<HealthCheckResponse> _parser = new pb::MessageParser<HealthCheckResponse>(() => new HealthCheckResponse()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<HealthCheckResponse> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Health.V1.HealthReflection.Descriptor.MessageTypes[1]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HealthCheckResponse() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HealthCheckResponse(HealthCheckResponse other) : this() { status_ = other.status_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HealthCheckResponse Clone() { return new HealthCheckResponse(this); } @@ -175,6 +193,7 @@ namespace Grpc.Health.V1 { /// <summary>Field number for the "status" field.</summary> public const int StatusFieldNumber = 1; private global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus status_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus Status { get { return status_; } set { @@ -182,10 +201,12 @@ namespace Grpc.Health.V1 { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as HealthCheckResponse); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(HealthCheckResponse other) { if (ReferenceEquals(other, null)) { return false; @@ -197,16 +218,19 @@ namespace Grpc.Health.V1 { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Status != 0) hash ^= Status.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Status != 0) { output.WriteRawTag(8); @@ -214,6 +238,7 @@ namespace Grpc.Health.V1 { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Status != 0) { @@ -222,6 +247,7 @@ namespace Grpc.Health.V1 { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(HealthCheckResponse other) { if (other == null) { return; @@ -231,6 +257,7 @@ namespace Grpc.Health.V1 { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -248,7 +275,7 @@ namespace Grpc.Health.V1 { #region Nested types /// <summary>Container for nested types declared in the HealthCheckResponse message type.</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static partial class Types { public enum ServingStatus { [pbr::OriginalName("UNKNOWN")] Unknown = 0, diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs index 43eea0f22f..b2a35a79be 100644 --- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs +++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs @@ -107,6 +107,7 @@ namespace Grpc.Health.V1 { { return CallInvoker.AsyncUnaryCall(__Method_Check, null, options, request); } + /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> protected override HealthClient NewInstance(ClientBaseConfiguration configuration) { return new HealthClient(configuration); diff --git a/src/csharp/Grpc.IntegrationTesting/Control.cs b/src/csharp/Grpc.IntegrationTesting/Control.cs index 412f800ff9..7928b51ba5 100644 --- a/src/csharp/Grpc.IntegrationTesting/Control.cs +++ b/src/csharp/Grpc.IntegrationTesting/Control.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Grpc.Testing { /// <summary>Holder for reflection information generated from src/proto/grpc/testing/control.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class ControlReflection { #region Descriptor @@ -71,18 +70,19 @@ namespace Grpc.Testing { "ASgBEhoKEmNsaWVudF9zeXN0ZW1fdGltZRgFIAEoARIYChBjbGllbnRfdXNl", "cl90aW1lGAYgASgBEhIKCmxhdGVuY3lfNTAYByABKAESEgoKbGF0ZW5jeV85", "MBgIIAEoARISCgpsYXRlbmN5Xzk1GAkgASgBEhIKCmxhdGVuY3lfOTkYCiAB", - "KAESEwoLbGF0ZW5jeV85OTkYCyABKAEimAIKDlNjZW5hcmlvUmVzdWx0EigK", + "KAESEwoLbGF0ZW5jeV85OTkYCyABKAEiyAIKDlNjZW5hcmlvUmVzdWx0EigK", "CHNjZW5hcmlvGAEgASgLMhYuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvEi4KCWxh", "dGVuY2llcxgCIAEoCzIbLmdycGMudGVzdGluZy5IaXN0b2dyYW1EYXRhEi8K", "DGNsaWVudF9zdGF0cxgDIAMoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0", "cxIvCgxzZXJ2ZXJfc3RhdHMYBCADKAsyGS5ncnBjLnRlc3RpbmcuU2VydmVy", "U3RhdHMSFAoMc2VydmVyX2NvcmVzGAUgAygFEjQKB3N1bW1hcnkYBiABKAsy", - "Iy5ncnBjLnRlc3RpbmcuU2NlbmFyaW9SZXN1bHRTdW1tYXJ5KkEKCkNsaWVu", - "dFR5cGUSDwoLU1lOQ19DTElFTlQQABIQCgxBU1lOQ19DTElFTlQQARIQCgxP", - "VEhFUl9DTElFTlQQAipbCgpTZXJ2ZXJUeXBlEg8KC1NZTkNfU0VSVkVSEAAS", - "EAoMQVNZTkNfU0VSVkVSEAESGAoUQVNZTkNfR0VORVJJQ19TRVJWRVIQAhIQ", - "CgxPVEhFUl9TRVJWRVIQAyojCgdScGNUeXBlEgkKBVVOQVJZEAASDQoJU1RS", - "RUFNSU5HEAFiBnByb3RvMw==")); + "Iy5ncnBjLnRlc3RpbmcuU2NlbmFyaW9SZXN1bHRTdW1tYXJ5EhYKDmNsaWVu", + "dF9zdWNjZXNzGAcgAygIEhYKDnNlcnZlcl9zdWNjZXNzGAggAygIKkEKCkNs", + "aWVudFR5cGUSDwoLU1lOQ19DTElFTlQQABIQCgxBU1lOQ19DTElFTlQQARIQ", + "CgxPVEhFUl9DTElFTlQQAipbCgpTZXJ2ZXJUeXBlEg8KC1NZTkNfU0VSVkVS", + "EAASEAoMQVNZTkNfU0VSVkVSEAESGAoUQVNZTkNfR0VORVJJQ19TRVJWRVIQ", + "AhIQCgxPVEhFUl9TRVJWRVIQAyojCgdScGNUeXBlEgkKBVVOQVJZEAASDQoJ", + "U1RSRUFNSU5HEAFiBnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { global::Grpc.Testing.PayloadsReflection.Descriptor, global::Grpc.Testing.StatsReflection.Descriptor, }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.ClientType), typeof(global::Grpc.Testing.ServerType), typeof(global::Grpc.Testing.RpcType), }, new pbr::GeneratedClrTypeInfo[] { @@ -103,7 +103,7 @@ namespace Grpc.Testing { new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Scenario), global::Grpc.Testing.Scenario.Parser, new[]{ "Name", "ClientConfig", "NumClients", "ServerConfig", "NumServers", "WarmupSeconds", "BenchmarkSeconds", "SpawnLocalWorkerCount" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Scenarios), global::Grpc.Testing.Scenarios.Parser, new[]{ "Scenarios_" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ScenarioResultSummary), global::Grpc.Testing.ScenarioResultSummary.Parser, new[]{ "Qps", "QpsPerServerCore", "ServerSystemTime", "ServerUserTime", "ClientSystemTime", "ClientUserTime", "Latency50", "Latency90", "Latency95", "Latency99", "Latency999" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ScenarioResult), global::Grpc.Testing.ScenarioResult.Parser, new[]{ "Scenario", "Latencies", "ClientStats", "ServerStats", "ServerCores", "Summary" }, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ScenarioResult), global::Grpc.Testing.ScenarioResult.Parser, new[]{ "Scenario", "Latencies", "ClientStats", "ServerStats", "ServerCores", "Summary", "ClientSuccess", "ServerSuccess" }, null, null, null) })); } #endregion @@ -145,29 +145,34 @@ namespace Grpc.Testing { /// Parameters of poisson process distribution, which is a good representation /// of activity coming in from independent identical stationary sources. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class PoissonParams : pb::IMessage<PoissonParams> { private static readonly pb::MessageParser<PoissonParams> _parser = new pb::MessageParser<PoissonParams>(() => new PoissonParams()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<PoissonParams> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[0]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public PoissonParams() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public PoissonParams(PoissonParams other) : this() { offeredLoad_ = other.offeredLoad_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public PoissonParams Clone() { return new PoissonParams(this); } @@ -178,6 +183,7 @@ namespace Grpc.Testing { /// <summary> /// The rate of arrivals (a.k.a. lambda parameter of the exp distribution). /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double OfferedLoad { get { return offeredLoad_; } set { @@ -185,10 +191,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as PoissonParams); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(PoissonParams other) { if (ReferenceEquals(other, null)) { return false; @@ -200,16 +208,19 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (OfferedLoad != 0D) hash ^= OfferedLoad.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (OfferedLoad != 0D) { output.WriteRawTag(9); @@ -217,6 +228,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (OfferedLoad != 0D) { @@ -225,6 +237,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(PoissonParams other) { if (other == null) { return; @@ -234,6 +247,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -255,36 +269,43 @@ namespace Grpc.Testing { /// Once an RPC finishes, immediately start a new one. /// No configuration parameters needed. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ClosedLoopParams : pb::IMessage<ClosedLoopParams> { private static readonly pb::MessageParser<ClosedLoopParams> _parser = new pb::MessageParser<ClosedLoopParams>(() => new ClosedLoopParams()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ClosedLoopParams> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[1]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClosedLoopParams() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClosedLoopParams(ClosedLoopParams other) : this() { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClosedLoopParams Clone() { return new ClosedLoopParams(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ClosedLoopParams); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ClosedLoopParams other) { if (ReferenceEquals(other, null)) { return false; @@ -295,29 +316,35 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ClosedLoopParams other) { if (other == null) { return; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -331,25 +358,29 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class LoadParams : pb::IMessage<LoadParams> { private static readonly pb::MessageParser<LoadParams> _parser = new pb::MessageParser<LoadParams>(() => new LoadParams()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<LoadParams> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[2]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public LoadParams() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public LoadParams(LoadParams other) : this() { switch (other.LoadCase) { case LoadOneofCase.ClosedLoop: @@ -362,12 +393,14 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public LoadParams Clone() { return new LoadParams(this); } /// <summary>Field number for the "closed_loop" field.</summary> public const int ClosedLoopFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ClosedLoopParams ClosedLoop { get { return loadCase_ == LoadOneofCase.ClosedLoop ? (global::Grpc.Testing.ClosedLoopParams) load_ : null; } set { @@ -378,6 +411,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "poisson" field.</summary> public const int PoissonFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.PoissonParams Poisson { get { return loadCase_ == LoadOneofCase.Poisson ? (global::Grpc.Testing.PoissonParams) load_ : null; } set { @@ -394,19 +428,23 @@ namespace Grpc.Testing { Poisson = 2, } private LoadOneofCase loadCase_ = LoadOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public LoadOneofCase LoadCase { get { return loadCase_; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void ClearLoad() { loadCase_ = LoadOneofCase.None; load_ = null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as LoadParams); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(LoadParams other) { if (ReferenceEquals(other, null)) { return false; @@ -420,6 +458,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (loadCase_ == LoadOneofCase.ClosedLoop) hash ^= ClosedLoop.GetHashCode(); @@ -428,10 +467,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (loadCase_ == LoadOneofCase.ClosedLoop) { output.WriteRawTag(10); @@ -443,6 +484,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (loadCase_ == LoadOneofCase.ClosedLoop) { @@ -454,6 +496,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(LoadParams other) { if (other == null) { return; @@ -469,6 +512,7 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -503,30 +547,35 @@ namespace Grpc.Testing { /// <summary> /// presence of SecurityParams implies use of TLS /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class SecurityParams : pb::IMessage<SecurityParams> { private static readonly pb::MessageParser<SecurityParams> _parser = new pb::MessageParser<SecurityParams>(() => new SecurityParams()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<SecurityParams> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[3]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SecurityParams() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SecurityParams(SecurityParams other) : this() { useTestCa_ = other.useTestCa_; serverHostOverride_ = other.serverHostOverride_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SecurityParams Clone() { return new SecurityParams(this); } @@ -534,6 +583,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "use_test_ca" field.</summary> public const int UseTestCaFieldNumber = 1; private bool useTestCa_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool UseTestCa { get { return useTestCa_; } set { @@ -544,6 +594,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "server_host_override" field.</summary> public const int ServerHostOverrideFieldNumber = 2; private string serverHostOverride_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string ServerHostOverride { get { return serverHostOverride_; } set { @@ -551,10 +602,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as SecurityParams); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(SecurityParams other) { if (ReferenceEquals(other, null)) { return false; @@ -567,6 +620,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (UseTestCa != false) hash ^= UseTestCa.GetHashCode(); @@ -574,10 +628,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (UseTestCa != false) { output.WriteRawTag(8); @@ -589,6 +645,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (UseTestCa != false) { @@ -600,6 +657,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(SecurityParams other) { if (other == null) { return; @@ -612,6 +670,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -633,25 +692,29 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ClientConfig : pb::IMessage<ClientConfig> { private static readonly pb::MessageParser<ClientConfig> _parser = new pb::MessageParser<ClientConfig>(() => new ClientConfig()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ClientConfig> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[4]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientConfig() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientConfig(ClientConfig other) : this() { serverTargets_ = other.serverTargets_.Clone(); clientType_ = other.clientType_; @@ -668,6 +731,7 @@ namespace Grpc.Testing { otherClientApi_ = other.otherClientApi_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientConfig Clone() { return new ClientConfig(this); } @@ -680,6 +744,7 @@ namespace Grpc.Testing { /// <summary> /// List of targets to connect to. At least one target needs to be specified. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<string> ServerTargets { get { return serverTargets_; } } @@ -687,6 +752,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "client_type" field.</summary> public const int ClientTypeFieldNumber = 2; private global::Grpc.Testing.ClientType clientType_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ClientType ClientType { get { return clientType_; } set { @@ -697,6 +763,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "security_params" field.</summary> public const int SecurityParamsFieldNumber = 3; private global::Grpc.Testing.SecurityParams securityParams_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.SecurityParams SecurityParams { get { return securityParams_; } set { @@ -711,6 +778,7 @@ namespace Grpc.Testing { /// How many concurrent RPCs to start for each channel. /// For synchronous client, use a separate thread for each outstanding RPC. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int OutstandingRpcsPerChannel { get { return outstandingRpcsPerChannel_; } set { @@ -725,6 +793,7 @@ namespace Grpc.Testing { /// Number of independent client channels to create. /// i-th channel will connect to server_target[i % server_targets.size()] /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int ClientChannels { get { return clientChannels_; } set { @@ -738,6 +807,7 @@ namespace Grpc.Testing { /// <summary> /// Only for async client. Number of threads to use to start/manage RPCs. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int AsyncClientThreads { get { return asyncClientThreads_; } set { @@ -748,6 +818,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "rpc_type" field.</summary> public const int RpcTypeFieldNumber = 8; private global::Grpc.Testing.RpcType rpcType_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.RpcType RpcType { get { return rpcType_; } set { @@ -761,6 +832,7 @@ namespace Grpc.Testing { /// <summary> /// The requested load for the entire client (aggregated over all the threads). /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.LoadParams LoadParams { get { return loadParams_; } set { @@ -771,6 +843,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "payload_config" field.</summary> public const int PayloadConfigFieldNumber = 11; private global::Grpc.Testing.PayloadConfig payloadConfig_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.PayloadConfig PayloadConfig { get { return payloadConfig_; } set { @@ -781,6 +854,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "histogram_params" field.</summary> public const int HistogramParamsFieldNumber = 12; private global::Grpc.Testing.HistogramParams histogramParams_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.HistogramParams HistogramParams { get { return histogramParams_; } set { @@ -796,6 +870,7 @@ namespace Grpc.Testing { /// <summary> /// Specify the cores we should run the client on, if desired /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<int> CoreList { get { return coreList_; } } @@ -803,6 +878,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "core_limit" field.</summary> public const int CoreLimitFieldNumber = 14; private int coreLimit_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CoreLimit { get { return coreLimit_; } set { @@ -816,6 +892,7 @@ namespace Grpc.Testing { /// <summary> /// If we use an OTHER_CLIENT client_type, this string gives more detail /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string OtherClientApi { get { return otherClientApi_; } set { @@ -823,10 +900,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ClientConfig); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ClientConfig other) { if (ReferenceEquals(other, null)) { return false; @@ -850,6 +929,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; hash ^= serverTargets_.GetHashCode(); @@ -868,10 +948,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { serverTargets_.WriteTo(output, _repeated_serverTargets_codec); if (ClientType != 0) { @@ -921,6 +1003,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; size += serverTargets_.CalculateSize(_repeated_serverTargets_codec); @@ -961,6 +1044,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ClientConfig other) { if (other == null) { return; @@ -1014,6 +1098,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1092,29 +1177,34 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ClientStatus : pb::IMessage<ClientStatus> { private static readonly pb::MessageParser<ClientStatus> _parser = new pb::MessageParser<ClientStatus>(() => new ClientStatus()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ClientStatus> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[5]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientStatus() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientStatus(ClientStatus other) : this() { Stats = other.stats_ != null ? other.Stats.Clone() : null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientStatus Clone() { return new ClientStatus(this); } @@ -1122,6 +1212,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "stats" field.</summary> public const int StatsFieldNumber = 1; private global::Grpc.Testing.ClientStats stats_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ClientStats Stats { get { return stats_; } set { @@ -1129,10 +1220,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ClientStatus); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ClientStatus other) { if (ReferenceEquals(other, null)) { return false; @@ -1144,16 +1237,19 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (stats_ != null) hash ^= Stats.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (stats_ != null) { output.WriteRawTag(10); @@ -1161,6 +1257,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (stats_ != null) { @@ -1169,6 +1266,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ClientStatus other) { if (other == null) { return; @@ -1181,6 +1279,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1204,29 +1303,34 @@ namespace Grpc.Testing { /// <summary> /// Request current stats /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Mark : pb::IMessage<Mark> { private static readonly pb::MessageParser<Mark> _parser = new pb::MessageParser<Mark>(() => new Mark()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Mark> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[6]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Mark() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Mark(Mark other) : this() { reset_ = other.reset_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Mark Clone() { return new Mark(this); } @@ -1237,6 +1341,7 @@ namespace Grpc.Testing { /// <summary> /// if true, the stats will be reset after taking their snapshot. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Reset { get { return reset_; } set { @@ -1244,10 +1349,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Mark); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Mark other) { if (ReferenceEquals(other, null)) { return false; @@ -1259,16 +1366,19 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Reset != false) hash ^= Reset.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Reset != false) { output.WriteRawTag(8); @@ -1276,6 +1386,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Reset != false) { @@ -1284,6 +1395,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Mark other) { if (other == null) { return; @@ -1293,6 +1405,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1310,25 +1423,29 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ClientArgs : pb::IMessage<ClientArgs> { private static readonly pb::MessageParser<ClientArgs> _parser = new pb::MessageParser<ClientArgs>(() => new ClientArgs()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ClientArgs> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[7]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientArgs() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientArgs(ClientArgs other) : this() { switch (other.ArgtypeCase) { case ArgtypeOneofCase.Setup: @@ -1341,12 +1458,14 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientArgs Clone() { return new ClientArgs(this); } /// <summary>Field number for the "setup" field.</summary> public const int SetupFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ClientConfig Setup { get { return argtypeCase_ == ArgtypeOneofCase.Setup ? (global::Grpc.Testing.ClientConfig) argtype_ : null; } set { @@ -1357,6 +1476,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "mark" field.</summary> public const int MarkFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.Mark Mark { get { return argtypeCase_ == ArgtypeOneofCase.Mark ? (global::Grpc.Testing.Mark) argtype_ : null; } set { @@ -1373,19 +1493,23 @@ namespace Grpc.Testing { Mark = 2, } private ArgtypeOneofCase argtypeCase_ = ArgtypeOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ArgtypeOneofCase ArgtypeCase { get { return argtypeCase_; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void ClearArgtype() { argtypeCase_ = ArgtypeOneofCase.None; argtype_ = null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ClientArgs); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ClientArgs other) { if (ReferenceEquals(other, null)) { return false; @@ -1399,6 +1523,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (argtypeCase_ == ArgtypeOneofCase.Setup) hash ^= Setup.GetHashCode(); @@ -1407,10 +1532,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (argtypeCase_ == ArgtypeOneofCase.Setup) { output.WriteRawTag(10); @@ -1422,6 +1549,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (argtypeCase_ == ArgtypeOneofCase.Setup) { @@ -1433,6 +1561,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ClientArgs other) { if (other == null) { return; @@ -1448,6 +1577,7 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1479,25 +1609,29 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ServerConfig : pb::IMessage<ServerConfig> { private static readonly pb::MessageParser<ServerConfig> _parser = new pb::MessageParser<ServerConfig>(() => new ServerConfig()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ServerConfig> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[8]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerConfig() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerConfig(ServerConfig other) : this() { serverType_ = other.serverType_; SecurityParams = other.securityParams_ != null ? other.SecurityParams.Clone() : null; @@ -1509,6 +1643,7 @@ namespace Grpc.Testing { otherServerApi_ = other.otherServerApi_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerConfig Clone() { return new ServerConfig(this); } @@ -1516,6 +1651,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "server_type" field.</summary> public const int ServerTypeFieldNumber = 1; private global::Grpc.Testing.ServerType serverType_ = 0; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ServerType ServerType { get { return serverType_; } set { @@ -1526,6 +1662,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "security_params" field.</summary> public const int SecurityParamsFieldNumber = 2; private global::Grpc.Testing.SecurityParams securityParams_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.SecurityParams SecurityParams { get { return securityParams_; } set { @@ -1539,6 +1676,7 @@ namespace Grpc.Testing { /// <summary> /// Port on which to listen. Zero means pick unused port. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int Port { get { return port_; } set { @@ -1552,6 +1690,7 @@ namespace Grpc.Testing { /// <summary> /// Only for async server. Number of threads used to serve the requests. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int AsyncServerThreads { get { return asyncServerThreads_; } set { @@ -1565,6 +1704,7 @@ namespace Grpc.Testing { /// <summary> /// Specify the number of cores to limit server to, if desired /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CoreLimit { get { return coreLimit_; } set { @@ -1578,6 +1718,7 @@ namespace Grpc.Testing { /// <summary> /// payload config, used in generic server /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.PayloadConfig PayloadConfig { get { return payloadConfig_; } set { @@ -1593,6 +1734,7 @@ namespace Grpc.Testing { /// <summary> /// Specify the cores we should run the server on, if desired /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<int> CoreList { get { return coreList_; } } @@ -1603,6 +1745,7 @@ namespace Grpc.Testing { /// <summary> /// If we use an OTHER_SERVER client_type, this string gives more detail /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string OtherServerApi { get { return otherServerApi_; } set { @@ -1610,10 +1753,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ServerConfig); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ServerConfig other) { if (ReferenceEquals(other, null)) { return false; @@ -1632,6 +1777,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (ServerType != 0) hash ^= ServerType.GetHashCode(); @@ -1645,10 +1791,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (ServerType != 0) { output.WriteRawTag(8); @@ -1681,6 +1829,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (ServerType != 0) { @@ -1708,6 +1857,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ServerConfig other) { if (other == null) { return; @@ -1742,6 +1892,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1794,25 +1945,29 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ServerArgs : pb::IMessage<ServerArgs> { private static readonly pb::MessageParser<ServerArgs> _parser = new pb::MessageParser<ServerArgs>(() => new ServerArgs()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ServerArgs> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[9]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerArgs() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerArgs(ServerArgs other) : this() { switch (other.ArgtypeCase) { case ArgtypeOneofCase.Setup: @@ -1825,12 +1980,14 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerArgs Clone() { return new ServerArgs(this); } /// <summary>Field number for the "setup" field.</summary> public const int SetupFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ServerConfig Setup { get { return argtypeCase_ == ArgtypeOneofCase.Setup ? (global::Grpc.Testing.ServerConfig) argtype_ : null; } set { @@ -1841,6 +1998,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "mark" field.</summary> public const int MarkFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.Mark Mark { get { return argtypeCase_ == ArgtypeOneofCase.Mark ? (global::Grpc.Testing.Mark) argtype_ : null; } set { @@ -1857,19 +2015,23 @@ namespace Grpc.Testing { Mark = 2, } private ArgtypeOneofCase argtypeCase_ = ArgtypeOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ArgtypeOneofCase ArgtypeCase { get { return argtypeCase_; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void ClearArgtype() { argtypeCase_ = ArgtypeOneofCase.None; argtype_ = null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ServerArgs); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ServerArgs other) { if (ReferenceEquals(other, null)) { return false; @@ -1883,6 +2045,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (argtypeCase_ == ArgtypeOneofCase.Setup) hash ^= Setup.GetHashCode(); @@ -1891,10 +2054,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (argtypeCase_ == ArgtypeOneofCase.Setup) { output.WriteRawTag(10); @@ -1906,6 +2071,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (argtypeCase_ == ArgtypeOneofCase.Setup) { @@ -1917,6 +2083,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ServerArgs other) { if (other == null) { return; @@ -1932,6 +2099,7 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1963,31 +2131,36 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ServerStatus : pb::IMessage<ServerStatus> { private static readonly pb::MessageParser<ServerStatus> _parser = new pb::MessageParser<ServerStatus>(() => new ServerStatus()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ServerStatus> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[10]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerStatus() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerStatus(ServerStatus other) : this() { Stats = other.stats_ != null ? other.Stats.Clone() : null; port_ = other.port_; cores_ = other.cores_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerStatus Clone() { return new ServerStatus(this); } @@ -1995,6 +2168,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "stats" field.</summary> public const int StatsFieldNumber = 1; private global::Grpc.Testing.ServerStats stats_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ServerStats Stats { get { return stats_; } set { @@ -2008,6 +2182,7 @@ namespace Grpc.Testing { /// <summary> /// the port bound by the server /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int Port { get { return port_; } set { @@ -2021,6 +2196,7 @@ namespace Grpc.Testing { /// <summary> /// Number of cores available to the server /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int Cores { get { return cores_; } set { @@ -2028,10 +2204,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ServerStatus); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ServerStatus other) { if (ReferenceEquals(other, null)) { return false; @@ -2045,6 +2223,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (stats_ != null) hash ^= Stats.GetHashCode(); @@ -2053,10 +2232,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (stats_ != null) { output.WriteRawTag(10); @@ -2072,6 +2253,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (stats_ != null) { @@ -2086,6 +2268,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ServerStatus other) { if (other == null) { return; @@ -2104,6 +2287,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -2132,36 +2316,43 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class CoreRequest : pb::IMessage<CoreRequest> { private static readonly pb::MessageParser<CoreRequest> _parser = new pb::MessageParser<CoreRequest>(() => new CoreRequest()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<CoreRequest> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[11]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public CoreRequest() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public CoreRequest(CoreRequest other) : this() { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public CoreRequest Clone() { return new CoreRequest(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as CoreRequest); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(CoreRequest other) { if (ReferenceEquals(other, null)) { return false; @@ -2172,29 +2363,35 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(CoreRequest other) { if (other == null) { return; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -2208,29 +2405,34 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class CoreResponse : pb::IMessage<CoreResponse> { private static readonly pb::MessageParser<CoreResponse> _parser = new pb::MessageParser<CoreResponse>(() => new CoreResponse()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<CoreResponse> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[12]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public CoreResponse() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public CoreResponse(CoreResponse other) : this() { cores_ = other.cores_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public CoreResponse Clone() { return new CoreResponse(this); } @@ -2241,6 +2443,7 @@ namespace Grpc.Testing { /// <summary> /// Number of cores available on the server /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int Cores { get { return cores_; } set { @@ -2248,10 +2451,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as CoreResponse); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(CoreResponse other) { if (ReferenceEquals(other, null)) { return false; @@ -2263,16 +2468,19 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Cores != 0) hash ^= Cores.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Cores != 0) { output.WriteRawTag(8); @@ -2280,6 +2488,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Cores != 0) { @@ -2288,6 +2497,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(CoreResponse other) { if (other == null) { return; @@ -2297,6 +2507,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -2314,36 +2525,43 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Void : pb::IMessage<Void> { private static readonly pb::MessageParser<Void> _parser = new pb::MessageParser<Void>(() => new Void()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Void> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[13]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Void() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Void(Void other) : this() { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Void Clone() { return new Void(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Void); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Void other) { if (ReferenceEquals(other, null)) { return false; @@ -2354,29 +2572,35 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Void other) { if (other == null) { return; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -2393,25 +2617,29 @@ namespace Grpc.Testing { /// <summary> /// A single performance scenario: input to qps_json_driver /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Scenario : pb::IMessage<Scenario> { private static readonly pb::MessageParser<Scenario> _parser = new pb::MessageParser<Scenario>(() => new Scenario()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Scenario> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[14]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Scenario() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Scenario(Scenario other) : this() { name_ = other.name_; ClientConfig = other.clientConfig_ != null ? other.ClientConfig.Clone() : null; @@ -2423,6 +2651,7 @@ namespace Grpc.Testing { spawnLocalWorkerCount_ = other.spawnLocalWorkerCount_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Scenario Clone() { return new Scenario(this); } @@ -2433,6 +2662,7 @@ namespace Grpc.Testing { /// <summary> /// Human readable name for this scenario /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string Name { get { return name_; } set { @@ -2446,6 +2676,7 @@ namespace Grpc.Testing { /// <summary> /// Client configuration /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ClientConfig ClientConfig { get { return clientConfig_; } set { @@ -2459,6 +2690,7 @@ namespace Grpc.Testing { /// <summary> /// Number of clients to start for the test /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int NumClients { get { return numClients_; } set { @@ -2472,6 +2704,7 @@ namespace Grpc.Testing { /// <summary> /// Server configuration /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ServerConfig ServerConfig { get { return serverConfig_; } set { @@ -2485,6 +2718,7 @@ namespace Grpc.Testing { /// <summary> /// Number of servers to start for the test /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int NumServers { get { return numServers_; } set { @@ -2498,6 +2732,7 @@ namespace Grpc.Testing { /// <summary> /// Warmup period, in seconds /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int WarmupSeconds { get { return warmupSeconds_; } set { @@ -2511,6 +2746,7 @@ namespace Grpc.Testing { /// <summary> /// Benchmark time, in seconds /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int BenchmarkSeconds { get { return benchmarkSeconds_; } set { @@ -2524,6 +2760,7 @@ namespace Grpc.Testing { /// <summary> /// Number of workers to spawn locally (usually zero) /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int SpawnLocalWorkerCount { get { return spawnLocalWorkerCount_; } set { @@ -2531,10 +2768,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Scenario); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Scenario other) { if (ReferenceEquals(other, null)) { return false; @@ -2553,6 +2792,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Name.Length != 0) hash ^= Name.GetHashCode(); @@ -2566,10 +2806,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Name.Length != 0) { output.WriteRawTag(10); @@ -2605,6 +2847,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Name.Length != 0) { @@ -2634,6 +2877,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Scenario other) { if (other == null) { return; @@ -2670,6 +2914,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -2724,29 +2969,34 @@ namespace Grpc.Testing { /// <summary> /// A set of scenarios to be run with qps_json_driver /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Scenarios : pb::IMessage<Scenarios> { private static readonly pb::MessageParser<Scenarios> _parser = new pb::MessageParser<Scenarios>(() => new Scenarios()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Scenarios> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[15]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Scenarios() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Scenarios(Scenarios other) : this() { scenarios_ = other.scenarios_.Clone(); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Scenarios Clone() { return new Scenarios(this); } @@ -2756,14 +3006,17 @@ namespace Grpc.Testing { private static readonly pb::FieldCodec<global::Grpc.Testing.Scenario> _repeated_scenarios_codec = pb::FieldCodec.ForMessage(10, global::Grpc.Testing.Scenario.Parser); private readonly pbc::RepeatedField<global::Grpc.Testing.Scenario> scenarios_ = new pbc::RepeatedField<global::Grpc.Testing.Scenario>(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<global::Grpc.Testing.Scenario> Scenarios_ { get { return scenarios_; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Scenarios); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Scenarios other) { if (ReferenceEquals(other, null)) { return false; @@ -2775,26 +3028,31 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; hash ^= scenarios_.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { scenarios_.WriteTo(output, _repeated_scenarios_codec); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; size += scenarios_.CalculateSize(_repeated_scenarios_codec); return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Scenarios other) { if (other == null) { return; @@ -2802,6 +3060,7 @@ namespace Grpc.Testing { scenarios_.Add(other.scenarios_); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -2823,25 +3082,29 @@ namespace Grpc.Testing { /// Basic summary that can be computed from ClientStats and ServerStats /// once the scenario has finished. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ScenarioResultSummary : pb::IMessage<ScenarioResultSummary> { private static readonly pb::MessageParser<ScenarioResultSummary> _parser = new pb::MessageParser<ScenarioResultSummary>(() => new ScenarioResultSummary()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ScenarioResultSummary> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[16]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ScenarioResultSummary() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ScenarioResultSummary(ScenarioResultSummary other) : this() { qps_ = other.qps_; qpsPerServerCore_ = other.qpsPerServerCore_; @@ -2856,6 +3119,7 @@ namespace Grpc.Testing { latency999_ = other.latency999_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ScenarioResultSummary Clone() { return new ScenarioResultSummary(this); } @@ -2866,6 +3130,7 @@ namespace Grpc.Testing { /// <summary> /// Total number of operations per second over all clients. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double Qps { get { return qps_; } set { @@ -2879,6 +3144,7 @@ namespace Grpc.Testing { /// <summary> /// QPS per one server core. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double QpsPerServerCore { get { return qpsPerServerCore_; } set { @@ -2892,6 +3158,7 @@ namespace Grpc.Testing { /// <summary> /// server load based on system_time (0.85 => 85%) /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double ServerSystemTime { get { return serverSystemTime_; } set { @@ -2905,6 +3172,7 @@ namespace Grpc.Testing { /// <summary> /// server load based on user_time (0.85 => 85%) /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double ServerUserTime { get { return serverUserTime_; } set { @@ -2918,6 +3186,7 @@ namespace Grpc.Testing { /// <summary> /// client load based on system_time (0.85 => 85%) /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double ClientSystemTime { get { return clientSystemTime_; } set { @@ -2931,6 +3200,7 @@ namespace Grpc.Testing { /// <summary> /// client load based on user_time (0.85 => 85%) /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double ClientUserTime { get { return clientUserTime_; } set { @@ -2944,6 +3214,7 @@ namespace Grpc.Testing { /// <summary> /// X% latency percentiles (in nanoseconds) /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double Latency50 { get { return latency50_; } set { @@ -2954,6 +3225,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "latency_90" field.</summary> public const int Latency90FieldNumber = 8; private double latency90_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double Latency90 { get { return latency90_; } set { @@ -2964,6 +3236,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "latency_95" field.</summary> public const int Latency95FieldNumber = 9; private double latency95_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double Latency95 { get { return latency95_; } set { @@ -2974,6 +3247,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "latency_99" field.</summary> public const int Latency99FieldNumber = 10; private double latency99_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double Latency99 { get { return latency99_; } set { @@ -2984,6 +3258,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "latency_999" field.</summary> public const int Latency999FieldNumber = 11; private double latency999_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double Latency999 { get { return latency999_; } set { @@ -2991,10 +3266,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ScenarioResultSummary); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ScenarioResultSummary other) { if (ReferenceEquals(other, null)) { return false; @@ -3016,6 +3293,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Qps != 0D) hash ^= Qps.GetHashCode(); @@ -3032,10 +3310,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Qps != 0D) { output.WriteRawTag(9); @@ -3083,6 +3363,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Qps != 0D) { @@ -3121,6 +3402,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ScenarioResultSummary other) { if (other == null) { return; @@ -3160,6 +3442,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -3220,25 +3503,29 @@ namespace Grpc.Testing { /// <summary> /// Results of a single benchmark scenario. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ScenarioResult : pb::IMessage<ScenarioResult> { private static readonly pb::MessageParser<ScenarioResult> _parser = new pb::MessageParser<ScenarioResult>(() => new ScenarioResult()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ScenarioResult> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.ControlReflection.Descriptor.MessageTypes[17]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ScenarioResult() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ScenarioResult(ScenarioResult other) : this() { Scenario = other.scenario_ != null ? other.Scenario.Clone() : null; Latencies = other.latencies_ != null ? other.Latencies.Clone() : null; @@ -3246,8 +3533,11 @@ namespace Grpc.Testing { serverStats_ = other.serverStats_.Clone(); serverCores_ = other.serverCores_.Clone(); Summary = other.summary_ != null ? other.Summary.Clone() : null; + clientSuccess_ = other.clientSuccess_.Clone(); + serverSuccess_ = other.serverSuccess_.Clone(); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ScenarioResult Clone() { return new ScenarioResult(this); } @@ -3258,6 +3548,7 @@ namespace Grpc.Testing { /// <summary> /// Inputs used to run the scenario. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.Scenario Scenario { get { return scenario_; } set { @@ -3271,6 +3562,7 @@ namespace Grpc.Testing { /// <summary> /// Histograms from all clients merged into one histogram. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.HistogramData Latencies { get { return latencies_; } set { @@ -3286,6 +3578,7 @@ namespace Grpc.Testing { /// <summary> /// Client stats for each client /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<global::Grpc.Testing.ClientStats> ClientStats { get { return clientStats_; } } @@ -3298,6 +3591,7 @@ namespace Grpc.Testing { /// <summary> /// Server stats for each server /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<global::Grpc.Testing.ServerStats> ServerStats { get { return serverStats_; } } @@ -3310,6 +3604,7 @@ namespace Grpc.Testing { /// <summary> /// Number of cores available to each server /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<int> ServerCores { get { return serverCores_; } } @@ -3320,6 +3615,7 @@ namespace Grpc.Testing { /// <summary> /// An after-the-fact computed summary /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ScenarioResultSummary Summary { get { return summary_; } set { @@ -3327,10 +3623,35 @@ namespace Grpc.Testing { } } + /// <summary>Field number for the "client_success" field.</summary> + public const int ClientSuccessFieldNumber = 7; + private static readonly pb::FieldCodec<bool> _repeated_clientSuccess_codec + = pb::FieldCodec.ForBool(58); + private readonly pbc::RepeatedField<bool> clientSuccess_ = new pbc::RepeatedField<bool>(); + /// <summary> + /// Information on success or failure of each worker + /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField<bool> ClientSuccess { + get { return clientSuccess_; } + } + + /// <summary>Field number for the "server_success" field.</summary> + public const int ServerSuccessFieldNumber = 8; + private static readonly pb::FieldCodec<bool> _repeated_serverSuccess_codec + = pb::FieldCodec.ForBool(66); + private readonly pbc::RepeatedField<bool> serverSuccess_ = new pbc::RepeatedField<bool>(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField<bool> ServerSuccess { + get { return serverSuccess_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ScenarioResult); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ScenarioResult other) { if (ReferenceEquals(other, null)) { return false; @@ -3344,9 +3665,12 @@ namespace Grpc.Testing { if(!serverStats_.Equals(other.serverStats_)) return false; if(!serverCores_.Equals(other.serverCores_)) return false; if (!object.Equals(Summary, other.Summary)) return false; + if(!clientSuccess_.Equals(other.clientSuccess_)) return false; + if(!serverSuccess_.Equals(other.serverSuccess_)) return false; return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (scenario_ != null) hash ^= Scenario.GetHashCode(); @@ -3355,13 +3679,17 @@ namespace Grpc.Testing { hash ^= serverStats_.GetHashCode(); hash ^= serverCores_.GetHashCode(); if (summary_ != null) hash ^= Summary.GetHashCode(); + hash ^= clientSuccess_.GetHashCode(); + hash ^= serverSuccess_.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (scenario_ != null) { output.WriteRawTag(10); @@ -3378,8 +3706,11 @@ namespace Grpc.Testing { output.WriteRawTag(50); output.WriteMessage(Summary); } + clientSuccess_.WriteTo(output, _repeated_clientSuccess_codec); + serverSuccess_.WriteTo(output, _repeated_serverSuccess_codec); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (scenario_ != null) { @@ -3394,9 +3725,12 @@ namespace Grpc.Testing { if (summary_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(Summary); } + size += clientSuccess_.CalculateSize(_repeated_clientSuccess_codec); + size += serverSuccess_.CalculateSize(_repeated_serverSuccess_codec); return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ScenarioResult other) { if (other == null) { return; @@ -3422,8 +3756,11 @@ namespace Grpc.Testing { } Summary.MergeFrom(other.Summary); } + clientSuccess_.Add(other.clientSuccess_); + serverSuccess_.Add(other.serverSuccess_); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -3465,6 +3802,16 @@ namespace Grpc.Testing { input.ReadMessage(summary_); break; } + case 58: + case 56: { + clientSuccess_.AddEntriesFrom(input, _repeated_clientSuccess_codec); + break; + } + case 66: + case 64: { + serverSuccess_.AddEntriesFrom(input, _repeated_serverSuccess_codec); + break; + } } } } diff --git a/src/csharp/Grpc.IntegrationTesting/Empty.cs b/src/csharp/Grpc.IntegrationTesting/Empty.cs index cf1c23fb0f..3017e664b9 100644 --- a/src/csharp/Grpc.IntegrationTesting/Empty.cs +++ b/src/csharp/Grpc.IntegrationTesting/Empty.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Grpc.Testing { /// <summary>Holder for reflection information generated from src/proto/grpc/testing/empty.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class EmptyReflection { #region Descriptor @@ -44,36 +43,43 @@ namespace Grpc.Testing { /// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; /// }; /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Empty : pb::IMessage<Empty> { private static readonly pb::MessageParser<Empty> _parser = new pb::MessageParser<Empty>(() => new Empty()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Empty> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.EmptyReflection.Descriptor.MessageTypes[0]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Empty() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Empty(Empty other) : this() { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Empty Clone() { return new Empty(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Empty); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Empty other) { if (ReferenceEquals(other, null)) { return false; @@ -84,29 +90,35 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Empty other) { if (other == null) { return; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 79fd18b6d5..cb926328e0 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -520,12 +520,12 @@ namespace Grpc.IntegrationTesting }; var call = client.FullDuplexCall(headers: CreateTestMetadata()); - var responseHeaders = await call.ResponseHeadersAsync; await call.RequestStream.WriteAsync(request); await call.RequestStream.CompleteAsync(); await call.ResponseStream.ToListAsync(); + var responseHeaders = await call.ResponseHeadersAsync; var responseTrailers = call.GetTrailers(); Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value); diff --git a/src/csharp/Grpc.IntegrationTesting/Messages.cs b/src/csharp/Grpc.IntegrationTesting/Messages.cs index 1240db128b..369fe738d6 100644 --- a/src/csharp/Grpc.IntegrationTesting/Messages.cs +++ b/src/csharp/Grpc.IntegrationTesting/Messages.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Grpc.Testing { /// <summary>Holder for reflection information generated from src/proto/grpc/testing/messages.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class MessagesReflection { #region Descriptor @@ -94,29 +93,34 @@ namespace Grpc.Testing { /// https://github.com/grpc/grpc/issues/6980 has been fixed. /// import "google/protobuf/wrappers.proto"; /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class BoolValue : pb::IMessage<BoolValue> { private static readonly pb::MessageParser<BoolValue> _parser = new pb::MessageParser<BoolValue>(() => new BoolValue()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<BoolValue> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[0]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public BoolValue() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public BoolValue(BoolValue other) : this() { value_ = other.value_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public BoolValue Clone() { return new BoolValue(this); } @@ -127,6 +131,7 @@ namespace Grpc.Testing { /// <summary> /// The bool value. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Value { get { return value_; } set { @@ -134,10 +139,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as BoolValue); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(BoolValue other) { if (ReferenceEquals(other, null)) { return false; @@ -149,16 +156,19 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Value != false) hash ^= Value.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Value != false) { output.WriteRawTag(8); @@ -166,6 +176,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Value != false) { @@ -174,6 +185,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(BoolValue other) { if (other == null) { return; @@ -183,6 +195,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -203,30 +216,35 @@ namespace Grpc.Testing { /// <summary> /// A block of data, to simply increase gRPC message size. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class Payload : pb::IMessage<Payload> { private static readonly pb::MessageParser<Payload> _parser = new pb::MessageParser<Payload>(() => new Payload()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<Payload> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[1]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Payload() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Payload(Payload other) : this() { type_ = other.type_; body_ = other.body_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public Payload Clone() { return new Payload(this); } @@ -238,6 +256,7 @@ namespace Grpc.Testing { /// DEPRECATED, don't use. To be removed shortly. /// The type of data in body. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.PayloadType Type { get { return type_; } set { @@ -251,6 +270,7 @@ namespace Grpc.Testing { /// <summary> /// Primary contents of payload. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pb::ByteString Body { get { return body_; } set { @@ -258,10 +278,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as Payload); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(Payload other) { if (ReferenceEquals(other, null)) { return false; @@ -274,6 +296,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Type != 0) hash ^= Type.GetHashCode(); @@ -281,10 +304,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Type != 0) { output.WriteRawTag(8); @@ -296,6 +321,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Type != 0) { @@ -307,6 +333,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(Payload other) { if (other == null) { return; @@ -319,6 +346,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -344,30 +372,35 @@ namespace Grpc.Testing { /// A protobuf representation for grpc status. This is used by test /// clients to specify a status that the server should attempt to return. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class EchoStatus : pb::IMessage<EchoStatus> { private static readonly pb::MessageParser<EchoStatus> _parser = new pb::MessageParser<EchoStatus>(() => new EchoStatus()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<EchoStatus> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[2]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public EchoStatus() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public EchoStatus(EchoStatus other) : this() { code_ = other.code_; message_ = other.message_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public EchoStatus Clone() { return new EchoStatus(this); } @@ -375,6 +408,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "code" field.</summary> public const int CodeFieldNumber = 1; private int code_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int Code { get { return code_; } set { @@ -385,6 +419,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "message" field.</summary> public const int MessageFieldNumber = 2; private string message_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string Message { get { return message_; } set { @@ -392,10 +427,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as EchoStatus); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(EchoStatus other) { if (ReferenceEquals(other, null)) { return false; @@ -408,6 +445,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Code != 0) hash ^= Code.GetHashCode(); @@ -415,10 +453,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Code != 0) { output.WriteRawTag(8); @@ -430,6 +470,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Code != 0) { @@ -441,6 +482,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(EchoStatus other) { if (other == null) { return; @@ -453,6 +495,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -477,25 +520,29 @@ namespace Grpc.Testing { /// <summary> /// Unary request. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class SimpleRequest : pb::IMessage<SimpleRequest> { private static readonly pb::MessageParser<SimpleRequest> _parser = new pb::MessageParser<SimpleRequest>(() => new SimpleRequest()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<SimpleRequest> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[3]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SimpleRequest() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SimpleRequest(SimpleRequest other) : this() { responseType_ = other.responseType_; responseSize_ = other.responseSize_; @@ -507,6 +554,7 @@ namespace Grpc.Testing { ExpectCompressed = other.expectCompressed_ != null ? other.ExpectCompressed.Clone() : null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SimpleRequest Clone() { return new SimpleRequest(this); } @@ -519,6 +567,7 @@ namespace Grpc.Testing { /// Desired payload type in the response from the server. /// If response_type is RANDOM, server randomly chooses one from other formats. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.PayloadType ResponseType { get { return responseType_; } set { @@ -532,6 +581,7 @@ namespace Grpc.Testing { /// <summary> /// Desired payload size in the response from the server. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int ResponseSize { get { return responseSize_; } set { @@ -545,6 +595,7 @@ namespace Grpc.Testing { /// <summary> /// Optional input payload sent along with the request. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.Payload Payload { get { return payload_; } set { @@ -558,6 +609,7 @@ namespace Grpc.Testing { /// <summary> /// Whether SimpleResponse should include username. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool FillUsername { get { return fillUsername_; } set { @@ -571,6 +623,7 @@ namespace Grpc.Testing { /// <summary> /// Whether SimpleResponse should include OAuth scope. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool FillOauthScope { get { return fillOauthScope_; } set { @@ -587,6 +640,7 @@ namespace Grpc.Testing { /// implement the full compression tests by introspecting the call to verify /// the response's compression status. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.BoolValue ResponseCompressed { get { return responseCompressed_; } set { @@ -600,6 +654,7 @@ namespace Grpc.Testing { /// <summary> /// Whether server should return a given status /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.EchoStatus ResponseStatus { get { return responseStatus_; } set { @@ -613,6 +668,7 @@ namespace Grpc.Testing { /// <summary> /// Whether the server should expect this request to be compressed. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.BoolValue ExpectCompressed { get { return expectCompressed_; } set { @@ -620,10 +676,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as SimpleRequest); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(SimpleRequest other) { if (ReferenceEquals(other, null)) { return false; @@ -642,6 +700,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (ResponseType != 0) hash ^= ResponseType.GetHashCode(); @@ -655,10 +714,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (ResponseType != 0) { output.WriteRawTag(8); @@ -694,6 +755,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (ResponseType != 0) { @@ -723,6 +785,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(SimpleRequest other) { if (other == null) { return; @@ -765,6 +828,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -825,31 +889,36 @@ namespace Grpc.Testing { /// <summary> /// Unary response, as configured by the request. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class SimpleResponse : pb::IMessage<SimpleResponse> { private static readonly pb::MessageParser<SimpleResponse> _parser = new pb::MessageParser<SimpleResponse>(() => new SimpleResponse()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<SimpleResponse> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[4]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SimpleResponse() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SimpleResponse(SimpleResponse other) : this() { Payload = other.payload_ != null ? other.Payload.Clone() : null; username_ = other.username_; oauthScope_ = other.oauthScope_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SimpleResponse Clone() { return new SimpleResponse(this); } @@ -860,6 +929,7 @@ namespace Grpc.Testing { /// <summary> /// Payload to increase message size. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.Payload Payload { get { return payload_; } set { @@ -874,6 +944,7 @@ namespace Grpc.Testing { /// The user the request came from, for verifying authentication was /// successful when the client expected it. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string Username { get { return username_; } set { @@ -887,6 +958,7 @@ namespace Grpc.Testing { /// <summary> /// OAuth scope. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string OauthScope { get { return oauthScope_; } set { @@ -894,10 +966,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as SimpleResponse); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(SimpleResponse other) { if (ReferenceEquals(other, null)) { return false; @@ -911,6 +985,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (payload_ != null) hash ^= Payload.GetHashCode(); @@ -919,10 +994,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (payload_ != null) { output.WriteRawTag(10); @@ -938,6 +1015,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (payload_ != null) { @@ -952,6 +1030,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(SimpleResponse other) { if (other == null) { return; @@ -970,6 +1049,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1001,30 +1081,35 @@ namespace Grpc.Testing { /// <summary> /// Client-streaming request. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class StreamingInputCallRequest : pb::IMessage<StreamingInputCallRequest> { private static readonly pb::MessageParser<StreamingInputCallRequest> _parser = new pb::MessageParser<StreamingInputCallRequest>(() => new StreamingInputCallRequest()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<StreamingInputCallRequest> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[5]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingInputCallRequest() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingInputCallRequest(StreamingInputCallRequest other) : this() { Payload = other.payload_ != null ? other.Payload.Clone() : null; ExpectCompressed = other.expectCompressed_ != null ? other.ExpectCompressed.Clone() : null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingInputCallRequest Clone() { return new StreamingInputCallRequest(this); } @@ -1035,6 +1120,7 @@ namespace Grpc.Testing { /// <summary> /// Optional input payload sent along with the request. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.Payload Payload { get { return payload_; } set { @@ -1051,6 +1137,7 @@ namespace Grpc.Testing { /// implement the full compression tests by introspecting the call to verify /// the request's compression status. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.BoolValue ExpectCompressed { get { return expectCompressed_; } set { @@ -1058,10 +1145,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as StreamingInputCallRequest); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(StreamingInputCallRequest other) { if (ReferenceEquals(other, null)) { return false; @@ -1074,6 +1163,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (payload_ != null) hash ^= Payload.GetHashCode(); @@ -1081,10 +1171,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (payload_ != null) { output.WriteRawTag(10); @@ -1096,6 +1188,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (payload_ != null) { @@ -1107,6 +1200,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(StreamingInputCallRequest other) { if (other == null) { return; @@ -1125,6 +1219,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1155,29 +1250,34 @@ namespace Grpc.Testing { /// <summary> /// Client-streaming response. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class StreamingInputCallResponse : pb::IMessage<StreamingInputCallResponse> { private static readonly pb::MessageParser<StreamingInputCallResponse> _parser = new pb::MessageParser<StreamingInputCallResponse>(() => new StreamingInputCallResponse()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<StreamingInputCallResponse> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[6]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingInputCallResponse() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingInputCallResponse(StreamingInputCallResponse other) : this() { aggregatedPayloadSize_ = other.aggregatedPayloadSize_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingInputCallResponse Clone() { return new StreamingInputCallResponse(this); } @@ -1188,6 +1288,7 @@ namespace Grpc.Testing { /// <summary> /// Aggregated size of payloads received from the client. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int AggregatedPayloadSize { get { return aggregatedPayloadSize_; } set { @@ -1195,10 +1296,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as StreamingInputCallResponse); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(StreamingInputCallResponse other) { if (ReferenceEquals(other, null)) { return false; @@ -1210,16 +1313,19 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (AggregatedPayloadSize != 0) hash ^= AggregatedPayloadSize.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (AggregatedPayloadSize != 0) { output.WriteRawTag(8); @@ -1227,6 +1333,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (AggregatedPayloadSize != 0) { @@ -1235,6 +1342,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(StreamingInputCallResponse other) { if (other == null) { return; @@ -1244,6 +1352,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1264,31 +1373,36 @@ namespace Grpc.Testing { /// <summary> /// Configuration for a particular response. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ResponseParameters : pb::IMessage<ResponseParameters> { private static readonly pb::MessageParser<ResponseParameters> _parser = new pb::MessageParser<ResponseParameters>(() => new ResponseParameters()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ResponseParameters> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[7]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ResponseParameters() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ResponseParameters(ResponseParameters other) : this() { size_ = other.size_; intervalUs_ = other.intervalUs_; Compressed = other.compressed_ != null ? other.Compressed.Clone() : null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ResponseParameters Clone() { return new ResponseParameters(this); } @@ -1299,6 +1413,7 @@ namespace Grpc.Testing { /// <summary> /// Desired payload sizes in responses from the server. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int Size { get { return size_; } set { @@ -1313,6 +1428,7 @@ namespace Grpc.Testing { /// Desired interval between consecutive responses in the response stream in /// microseconds. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int IntervalUs { get { return intervalUs_; } set { @@ -1329,6 +1445,7 @@ namespace Grpc.Testing { /// implement the full compression tests by introspecting the call to verify /// the response's compression status. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.BoolValue Compressed { get { return compressed_; } set { @@ -1336,10 +1453,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ResponseParameters); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ResponseParameters other) { if (ReferenceEquals(other, null)) { return false; @@ -1353,6 +1472,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Size != 0) hash ^= Size.GetHashCode(); @@ -1361,10 +1481,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Size != 0) { output.WriteRawTag(8); @@ -1380,6 +1502,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Size != 0) { @@ -1394,6 +1517,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ResponseParameters other) { if (other == null) { return; @@ -1412,6 +1536,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1443,25 +1568,29 @@ namespace Grpc.Testing { /// <summary> /// Server-streaming request. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class StreamingOutputCallRequest : pb::IMessage<StreamingOutputCallRequest> { private static readonly pb::MessageParser<StreamingOutputCallRequest> _parser = new pb::MessageParser<StreamingOutputCallRequest>(() => new StreamingOutputCallRequest()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<StreamingOutputCallRequest> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[8]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingOutputCallRequest() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingOutputCallRequest(StreamingOutputCallRequest other) : this() { responseType_ = other.responseType_; responseParameters_ = other.responseParameters_.Clone(); @@ -1469,6 +1598,7 @@ namespace Grpc.Testing { ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingOutputCallRequest Clone() { return new StreamingOutputCallRequest(this); } @@ -1483,6 +1613,7 @@ namespace Grpc.Testing { /// might be of different types. This is to simulate a mixed type of payload /// stream. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.PayloadType ResponseType { get { return responseType_; } set { @@ -1498,6 +1629,7 @@ namespace Grpc.Testing { /// <summary> /// Configuration for each expected response message. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<global::Grpc.Testing.ResponseParameters> ResponseParameters { get { return responseParameters_; } } @@ -1508,6 +1640,7 @@ namespace Grpc.Testing { /// <summary> /// Optional input payload sent along with the request. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.Payload Payload { get { return payload_; } set { @@ -1521,6 +1654,7 @@ namespace Grpc.Testing { /// <summary> /// Whether server should return a given status /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.EchoStatus ResponseStatus { get { return responseStatus_; } set { @@ -1528,10 +1662,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as StreamingOutputCallRequest); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(StreamingOutputCallRequest other) { if (ReferenceEquals(other, null)) { return false; @@ -1546,6 +1682,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (ResponseType != 0) hash ^= ResponseType.GetHashCode(); @@ -1555,10 +1692,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (ResponseType != 0) { output.WriteRawTag(8); @@ -1575,6 +1714,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (ResponseType != 0) { @@ -1590,6 +1730,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(StreamingOutputCallRequest other) { if (other == null) { return; @@ -1612,6 +1753,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1650,29 +1792,34 @@ namespace Grpc.Testing { /// <summary> /// Server-streaming response, as configured by the request and parameters. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class StreamingOutputCallResponse : pb::IMessage<StreamingOutputCallResponse> { private static readonly pb::MessageParser<StreamingOutputCallResponse> _parser = new pb::MessageParser<StreamingOutputCallResponse>(() => new StreamingOutputCallResponse()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<StreamingOutputCallResponse> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[9]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingOutputCallResponse() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingOutputCallResponse(StreamingOutputCallResponse other) : this() { Payload = other.payload_ != null ? other.Payload.Clone() : null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public StreamingOutputCallResponse Clone() { return new StreamingOutputCallResponse(this); } @@ -1683,6 +1830,7 @@ namespace Grpc.Testing { /// <summary> /// Payload to increase response size. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.Payload Payload { get { return payload_; } set { @@ -1690,10 +1838,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as StreamingOutputCallResponse); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(StreamingOutputCallResponse other) { if (ReferenceEquals(other, null)) { return false; @@ -1705,16 +1855,19 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (payload_ != null) hash ^= Payload.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (payload_ != null) { output.WriteRawTag(10); @@ -1722,6 +1875,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (payload_ != null) { @@ -1730,6 +1884,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(StreamingOutputCallResponse other) { if (other == null) { return; @@ -1742,6 +1897,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1766,29 +1922,34 @@ namespace Grpc.Testing { /// For reconnect interop test only. /// Client tells server what reconnection parameters it used. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ReconnectParams : pb::IMessage<ReconnectParams> { private static readonly pb::MessageParser<ReconnectParams> _parser = new pb::MessageParser<ReconnectParams>(() => new ReconnectParams()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ReconnectParams> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[10]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ReconnectParams() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ReconnectParams(ReconnectParams other) : this() { maxReconnectBackoffMs_ = other.maxReconnectBackoffMs_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ReconnectParams Clone() { return new ReconnectParams(this); } @@ -1796,6 +1957,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "max_reconnect_backoff_ms" field.</summary> public const int MaxReconnectBackoffMsFieldNumber = 1; private int maxReconnectBackoffMs_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int MaxReconnectBackoffMs { get { return maxReconnectBackoffMs_; } set { @@ -1803,10 +1965,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ReconnectParams); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ReconnectParams other) { if (ReferenceEquals(other, null)) { return false; @@ -1818,16 +1982,19 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (MaxReconnectBackoffMs != 0) hash ^= MaxReconnectBackoffMs.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (MaxReconnectBackoffMs != 0) { output.WriteRawTag(8); @@ -1835,6 +2002,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (MaxReconnectBackoffMs != 0) { @@ -1843,6 +2011,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ReconnectParams other) { if (other == null) { return; @@ -1852,6 +2021,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -1874,30 +2044,35 @@ namespace Grpc.Testing { /// Server tells client whether its reconnects are following the spec and the /// reconnect backoffs it saw. /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ReconnectInfo : pb::IMessage<ReconnectInfo> { private static readonly pb::MessageParser<ReconnectInfo> _parser = new pb::MessageParser<ReconnectInfo>(() => new ReconnectInfo()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ReconnectInfo> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[11]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ReconnectInfo() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ReconnectInfo(ReconnectInfo other) : this() { passed_ = other.passed_; backoffMs_ = other.backoffMs_.Clone(); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ReconnectInfo Clone() { return new ReconnectInfo(this); } @@ -1905,6 +2080,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "passed" field.</summary> public const int PassedFieldNumber = 1; private bool passed_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Passed { get { return passed_; } set { @@ -1917,14 +2093,17 @@ namespace Grpc.Testing { private static readonly pb::FieldCodec<int> _repeated_backoffMs_codec = pb::FieldCodec.ForInt32(18); private readonly pbc::RepeatedField<int> backoffMs_ = new pbc::RepeatedField<int>(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<int> BackoffMs { get { return backoffMs_; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ReconnectInfo); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ReconnectInfo other) { if (ReferenceEquals(other, null)) { return false; @@ -1937,6 +2116,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Passed != false) hash ^= Passed.GetHashCode(); @@ -1944,10 +2124,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Passed != false) { output.WriteRawTag(8); @@ -1956,6 +2138,7 @@ namespace Grpc.Testing { backoffMs_.WriteTo(output, _repeated_backoffMs_codec); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Passed != false) { @@ -1965,6 +2148,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ReconnectInfo other) { if (other == null) { return; @@ -1975,6 +2159,7 @@ namespace Grpc.Testing { backoffMs_.Add(other.backoffMs_); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { diff --git a/src/csharp/Grpc.IntegrationTesting/Metrics.cs b/src/csharp/Grpc.IntegrationTesting/Metrics.cs index 8f31fbc2a9..4de1847e5f 100644 --- a/src/csharp/Grpc.IntegrationTesting/Metrics.cs +++ b/src/csharp/Grpc.IntegrationTesting/Metrics.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Grpc.Testing { /// <summary>Holder for reflection information generated from src/proto/grpc/testing/metrics.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class MetricsReflection { #region Descriptor @@ -47,25 +46,29 @@ namespace Grpc.Testing { /// <summary> /// Reponse message containing the gauge name and value /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class GaugeResponse : pb::IMessage<GaugeResponse> { private static readonly pb::MessageParser<GaugeResponse> _parser = new pb::MessageParser<GaugeResponse>(() => new GaugeResponse()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<GaugeResponse> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MetricsReflection.Descriptor.MessageTypes[0]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public GaugeResponse() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public GaugeResponse(GaugeResponse other) : this() { name_ = other.name_; switch (other.ValueCase) { @@ -82,6 +85,7 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public GaugeResponse Clone() { return new GaugeResponse(this); } @@ -89,6 +93,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "name" field.</summary> public const int NameFieldNumber = 1; private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string Name { get { return name_; } set { @@ -98,6 +103,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "long_value" field.</summary> public const int LongValueFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public long LongValue { get { return valueCase_ == ValueOneofCase.LongValue ? (long) value_ : 0L; } set { @@ -108,6 +114,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "double_value" field.</summary> public const int DoubleValueFieldNumber = 3; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double DoubleValue { get { return valueCase_ == ValueOneofCase.DoubleValue ? (double) value_ : 0D; } set { @@ -118,6 +125,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "string_value" field.</summary> public const int StringValueFieldNumber = 4; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string StringValue { get { return valueCase_ == ValueOneofCase.StringValue ? (string) value_ : ""; } set { @@ -135,19 +143,23 @@ namespace Grpc.Testing { StringValue = 4, } private ValueOneofCase valueCase_ = ValueOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ValueOneofCase ValueCase { get { return valueCase_; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void ClearValue() { valueCase_ = ValueOneofCase.None; value_ = null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as GaugeResponse); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(GaugeResponse other) { if (ReferenceEquals(other, null)) { return false; @@ -163,6 +175,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Name.Length != 0) hash ^= Name.GetHashCode(); @@ -173,10 +186,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Name.Length != 0) { output.WriteRawTag(10); @@ -196,6 +211,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Name.Length != 0) { @@ -213,6 +229,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(GaugeResponse other) { if (other == null) { return; @@ -234,6 +251,7 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -266,29 +284,34 @@ namespace Grpc.Testing { /// <summary> /// Request message containing the gauge name /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class GaugeRequest : pb::IMessage<GaugeRequest> { private static readonly pb::MessageParser<GaugeRequest> _parser = new pb::MessageParser<GaugeRequest>(() => new GaugeRequest()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<GaugeRequest> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MetricsReflection.Descriptor.MessageTypes[1]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public GaugeRequest() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public GaugeRequest(GaugeRequest other) : this() { name_ = other.name_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public GaugeRequest Clone() { return new GaugeRequest(this); } @@ -296,6 +319,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "name" field.</summary> public const int NameFieldNumber = 1; private string name_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public string Name { get { return name_; } set { @@ -303,10 +327,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as GaugeRequest); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(GaugeRequest other) { if (ReferenceEquals(other, null)) { return false; @@ -318,16 +344,19 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Name.Length != 0) hash ^= Name.GetHashCode(); return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Name.Length != 0) { output.WriteRawTag(10); @@ -335,6 +364,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Name.Length != 0) { @@ -343,6 +373,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(GaugeRequest other) { if (other == null) { return; @@ -352,6 +383,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -369,36 +401,43 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class EmptyMessage : pb::IMessage<EmptyMessage> { private static readonly pb::MessageParser<EmptyMessage> _parser = new pb::MessageParser<EmptyMessage>(() => new EmptyMessage()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<EmptyMessage> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.MetricsReflection.Descriptor.MessageTypes[2]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public EmptyMessage() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public EmptyMessage(EmptyMessage other) : this() { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public EmptyMessage Clone() { return new EmptyMessage(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as EmptyMessage); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(EmptyMessage other) { if (ReferenceEquals(other, null)) { return false; @@ -409,29 +448,35 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(EmptyMessage other) { if (other == null) { return; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs index 040798e3c2..bcd7e3c040 100644 --- a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs +++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs @@ -161,6 +161,7 @@ namespace Grpc.Testing { { return CallInvoker.AsyncUnaryCall(__Method_GetGauge, null, options, request); } + /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> protected override MetricsServiceClient NewInstance(ClientBaseConfiguration configuration) { return new MetricsServiceClient(configuration); diff --git a/src/csharp/Grpc.IntegrationTesting/Payloads.cs b/src/csharp/Grpc.IntegrationTesting/Payloads.cs index 3ad7a44f4b..7aef35cda3 100644 --- a/src/csharp/Grpc.IntegrationTesting/Payloads.cs +++ b/src/csharp/Grpc.IntegrationTesting/Payloads.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Grpc.Testing { /// <summary>Holder for reflection information generated from src/proto/grpc/testing/payloads.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class PayloadsReflection { #region Descriptor @@ -45,30 +44,35 @@ namespace Grpc.Testing { } #region Messages - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ByteBufferParams : pb::IMessage<ByteBufferParams> { private static readonly pb::MessageParser<ByteBufferParams> _parser = new pb::MessageParser<ByteBufferParams>(() => new ByteBufferParams()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ByteBufferParams> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.PayloadsReflection.Descriptor.MessageTypes[0]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ByteBufferParams() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ByteBufferParams(ByteBufferParams other) : this() { reqSize_ = other.reqSize_; respSize_ = other.respSize_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ByteBufferParams Clone() { return new ByteBufferParams(this); } @@ -76,6 +80,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "req_size" field.</summary> public const int ReqSizeFieldNumber = 1; private int reqSize_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int ReqSize { get { return reqSize_; } set { @@ -86,6 +91,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "resp_size" field.</summary> public const int RespSizeFieldNumber = 2; private int respSize_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int RespSize { get { return respSize_; } set { @@ -93,10 +99,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ByteBufferParams); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ByteBufferParams other) { if (ReferenceEquals(other, null)) { return false; @@ -109,6 +117,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (ReqSize != 0) hash ^= ReqSize.GetHashCode(); @@ -116,10 +125,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (ReqSize != 0) { output.WriteRawTag(8); @@ -131,6 +142,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (ReqSize != 0) { @@ -142,6 +154,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ByteBufferParams other) { if (other == null) { return; @@ -154,6 +167,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -175,30 +189,35 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class SimpleProtoParams : pb::IMessage<SimpleProtoParams> { private static readonly pb::MessageParser<SimpleProtoParams> _parser = new pb::MessageParser<SimpleProtoParams>(() => new SimpleProtoParams()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<SimpleProtoParams> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.PayloadsReflection.Descriptor.MessageTypes[1]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SimpleProtoParams() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SimpleProtoParams(SimpleProtoParams other) : this() { reqSize_ = other.reqSize_; respSize_ = other.respSize_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public SimpleProtoParams Clone() { return new SimpleProtoParams(this); } @@ -206,6 +225,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "req_size" field.</summary> public const int ReqSizeFieldNumber = 1; private int reqSize_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int ReqSize { get { return reqSize_; } set { @@ -216,6 +236,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "resp_size" field.</summary> public const int RespSizeFieldNumber = 2; private int respSize_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int RespSize { get { return respSize_; } set { @@ -223,10 +244,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as SimpleProtoParams); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(SimpleProtoParams other) { if (ReferenceEquals(other, null)) { return false; @@ -239,6 +262,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (ReqSize != 0) hash ^= ReqSize.GetHashCode(); @@ -246,10 +270,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (ReqSize != 0) { output.WriteRawTag(8); @@ -261,6 +287,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (ReqSize != 0) { @@ -272,6 +299,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(SimpleProtoParams other) { if (other == null) { return; @@ -284,6 +312,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -309,36 +338,43 @@ namespace Grpc.Testing { /// TODO (vpai): Fill this in once the details of complex, representative /// protos are decided /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ComplexProtoParams : pb::IMessage<ComplexProtoParams> { private static readonly pb::MessageParser<ComplexProtoParams> _parser = new pb::MessageParser<ComplexProtoParams>(() => new ComplexProtoParams()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ComplexProtoParams> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.PayloadsReflection.Descriptor.MessageTypes[2]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ComplexProtoParams() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ComplexProtoParams(ComplexProtoParams other) : this() { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ComplexProtoParams Clone() { return new ComplexProtoParams(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ComplexProtoParams); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ComplexProtoParams other) { if (ReferenceEquals(other, null)) { return false; @@ -349,29 +385,35 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ComplexProtoParams other) { if (other == null) { return; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -385,25 +427,29 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class PayloadConfig : pb::IMessage<PayloadConfig> { private static readonly pb::MessageParser<PayloadConfig> _parser = new pb::MessageParser<PayloadConfig>(() => new PayloadConfig()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<PayloadConfig> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.PayloadsReflection.Descriptor.MessageTypes[3]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public PayloadConfig() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public PayloadConfig(PayloadConfig other) : this() { switch (other.PayloadCase) { case PayloadOneofCase.BytebufParams: @@ -419,12 +465,14 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public PayloadConfig Clone() { return new PayloadConfig(this); } /// <summary>Field number for the "bytebuf_params" field.</summary> public const int BytebufParamsFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ByteBufferParams BytebufParams { get { return payloadCase_ == PayloadOneofCase.BytebufParams ? (global::Grpc.Testing.ByteBufferParams) payload_ : null; } set { @@ -435,6 +483,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "simple_params" field.</summary> public const int SimpleParamsFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.SimpleProtoParams SimpleParams { get { return payloadCase_ == PayloadOneofCase.SimpleParams ? (global::Grpc.Testing.SimpleProtoParams) payload_ : null; } set { @@ -445,6 +494,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "complex_params" field.</summary> public const int ComplexParamsFieldNumber = 3; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.ComplexProtoParams ComplexParams { get { return payloadCase_ == PayloadOneofCase.ComplexParams ? (global::Grpc.Testing.ComplexProtoParams) payload_ : null; } set { @@ -462,19 +512,23 @@ namespace Grpc.Testing { ComplexParams = 3, } private PayloadOneofCase payloadCase_ = PayloadOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public PayloadOneofCase PayloadCase { get { return payloadCase_; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void ClearPayload() { payloadCase_ = PayloadOneofCase.None; payload_ = null; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as PayloadConfig); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(PayloadConfig other) { if (ReferenceEquals(other, null)) { return false; @@ -489,6 +543,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (payloadCase_ == PayloadOneofCase.BytebufParams) hash ^= BytebufParams.GetHashCode(); @@ -498,10 +553,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (payloadCase_ == PayloadOneofCase.BytebufParams) { output.WriteRawTag(10); @@ -517,6 +574,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (payloadCase_ == PayloadOneofCase.BytebufParams) { @@ -531,6 +589,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(PayloadConfig other) { if (other == null) { return; @@ -549,6 +608,7 @@ namespace Grpc.Testing { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { diff --git a/src/csharp/Grpc.IntegrationTesting/Services.cs b/src/csharp/Grpc.IntegrationTesting/Services.cs index e10b45c9a2..bf36a0253b 100644 --- a/src/csharp/Grpc.IntegrationTesting/Services.cs +++ b/src/csharp/Grpc.IntegrationTesting/Services.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Grpc.Testing { /// <summary>Holder for reflection information generated from src/proto/grpc/testing/services.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class ServicesReflection { #region Descriptor diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs index e205dea93e..848dd04fa7 100644 --- a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs +++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs @@ -161,6 +161,7 @@ namespace Grpc.Testing { { return CallInvoker.AsyncDuplexStreamingCall(__Method_StreamingCall, null, options); } + /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> protected override BenchmarkServiceClient NewInstance(ClientBaseConfiguration configuration) { return new BenchmarkServiceClient(configuration); @@ -396,6 +397,7 @@ namespace Grpc.Testing { { return CallInvoker.AsyncUnaryCall(__Method_QuitWorker, null, options, request); } + /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> protected override WorkerServiceClient NewInstance(ClientBaseConfiguration configuration) { return new WorkerServiceClient(configuration); diff --git a/src/csharp/Grpc.IntegrationTesting/Stats.cs b/src/csharp/Grpc.IntegrationTesting/Stats.cs index 304d676113..0ae77cfb92 100644 --- a/src/csharp/Grpc.IntegrationTesting/Stats.cs +++ b/src/csharp/Grpc.IntegrationTesting/Stats.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Grpc.Testing { /// <summary>Holder for reflection information generated from src/proto/grpc/testing/stats.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class StatsReflection { #region Descriptor @@ -46,31 +45,36 @@ namespace Grpc.Testing { } #region Messages - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ServerStats : pb::IMessage<ServerStats> { private static readonly pb::MessageParser<ServerStats> _parser = new pb::MessageParser<ServerStats>(() => new ServerStats()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ServerStats> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.StatsReflection.Descriptor.MessageTypes[0]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerStats() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerStats(ServerStats other) : this() { timeElapsed_ = other.timeElapsed_; timeUser_ = other.timeUser_; timeSystem_ = other.timeSystem_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ServerStats Clone() { return new ServerStats(this); } @@ -81,6 +85,7 @@ namespace Grpc.Testing { /// <summary> /// wall clock time change in seconds since last reset /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double TimeElapsed { get { return timeElapsed_; } set { @@ -94,6 +99,7 @@ namespace Grpc.Testing { /// <summary> /// change in user time (in seconds) used by the server since last reset /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double TimeUser { get { return timeUser_; } set { @@ -108,6 +114,7 @@ namespace Grpc.Testing { /// change in server time (in seconds) used by the server process and all /// threads since last reset /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double TimeSystem { get { return timeSystem_; } set { @@ -115,10 +122,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ServerStats); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ServerStats other) { if (ReferenceEquals(other, null)) { return false; @@ -132,6 +141,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode(); @@ -140,10 +150,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (TimeElapsed != 0D) { output.WriteRawTag(9); @@ -159,6 +171,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (TimeElapsed != 0D) { @@ -173,6 +186,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ServerStats other) { if (other == null) { return; @@ -188,6 +202,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -216,30 +231,35 @@ namespace Grpc.Testing { /// <summary> /// Histogram params based on grpc/support/histogram.c /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class HistogramParams : pb::IMessage<HistogramParams> { private static readonly pb::MessageParser<HistogramParams> _parser = new pb::MessageParser<HistogramParams>(() => new HistogramParams()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<HistogramParams> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.StatsReflection.Descriptor.MessageTypes[1]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HistogramParams() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HistogramParams(HistogramParams other) : this() { resolution_ = other.resolution_; maxPossible_ = other.maxPossible_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HistogramParams Clone() { return new HistogramParams(this); } @@ -250,6 +270,7 @@ namespace Grpc.Testing { /// <summary> /// first bucket is [0, 1 + resolution) /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double Resolution { get { return resolution_; } set { @@ -263,6 +284,7 @@ namespace Grpc.Testing { /// <summary> /// use enough buckets to allow this value /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double MaxPossible { get { return maxPossible_; } set { @@ -270,10 +292,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as HistogramParams); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(HistogramParams other) { if (ReferenceEquals(other, null)) { return false; @@ -286,6 +310,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (Resolution != 0D) hash ^= Resolution.GetHashCode(); @@ -293,10 +318,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (Resolution != 0D) { output.WriteRawTag(9); @@ -308,6 +335,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (Resolution != 0D) { @@ -319,6 +347,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(HistogramParams other) { if (other == null) { return; @@ -331,6 +360,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -355,25 +385,29 @@ namespace Grpc.Testing { /// <summary> /// Histogram data based on grpc/support/histogram.c /// </summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class HistogramData : pb::IMessage<HistogramData> { private static readonly pb::MessageParser<HistogramData> _parser = new pb::MessageParser<HistogramData>(() => new HistogramData()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<HistogramData> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.StatsReflection.Descriptor.MessageTypes[2]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HistogramData() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HistogramData(HistogramData other) : this() { bucket_ = other.bucket_.Clone(); minSeen_ = other.minSeen_; @@ -383,6 +417,7 @@ namespace Grpc.Testing { count_ = other.count_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public HistogramData Clone() { return new HistogramData(this); } @@ -392,6 +427,7 @@ namespace Grpc.Testing { private static readonly pb::FieldCodec<uint> _repeated_bucket_codec = pb::FieldCodec.ForUInt32(10); private readonly pbc::RepeatedField<uint> bucket_ = new pbc::RepeatedField<uint>(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField<uint> Bucket { get { return bucket_; } } @@ -399,6 +435,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "min_seen" field.</summary> public const int MinSeenFieldNumber = 2; private double minSeen_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double MinSeen { get { return minSeen_; } set { @@ -409,6 +446,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "max_seen" field.</summary> public const int MaxSeenFieldNumber = 3; private double maxSeen_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double MaxSeen { get { return maxSeen_; } set { @@ -419,6 +457,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "sum" field.</summary> public const int SumFieldNumber = 4; private double sum_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double Sum { get { return sum_; } set { @@ -429,6 +468,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "sum_of_squares" field.</summary> public const int SumOfSquaresFieldNumber = 5; private double sumOfSquares_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double SumOfSquares { get { return sumOfSquares_; } set { @@ -439,6 +479,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "count" field.</summary> public const int CountFieldNumber = 6; private double count_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double Count { get { return count_; } set { @@ -446,10 +487,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as HistogramData); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(HistogramData other) { if (ReferenceEquals(other, null)) { return false; @@ -466,6 +509,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; hash ^= bucket_.GetHashCode(); @@ -477,10 +521,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { bucket_.WriteTo(output, _repeated_bucket_codec); if (MinSeen != 0D) { @@ -505,6 +551,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; size += bucket_.CalculateSize(_repeated_bucket_codec); @@ -526,6 +573,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(HistogramData other) { if (other == null) { return; @@ -548,6 +596,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { @@ -586,25 +635,29 @@ namespace Grpc.Testing { } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class ClientStats : pb::IMessage<ClientStats> { private static readonly pb::MessageParser<ClientStats> _parser = new pb::MessageParser<ClientStats>(() => new ClientStats()); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pb::MessageParser<ClientStats> Parser { get { return _parser; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public static pbr::MessageDescriptor Descriptor { get { return global::Grpc.Testing.StatsReflection.Descriptor.MessageTypes[3]; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] pbr::MessageDescriptor pb::IMessage.Descriptor { get { return Descriptor; } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientStats() { OnConstruction(); } partial void OnConstruction(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientStats(ClientStats other) : this() { Latencies = other.latencies_ != null ? other.Latencies.Clone() : null; timeElapsed_ = other.timeElapsed_; @@ -612,6 +665,7 @@ namespace Grpc.Testing { timeSystem_ = other.timeSystem_; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public ClientStats Clone() { return new ClientStats(this); } @@ -622,6 +676,7 @@ namespace Grpc.Testing { /// <summary> /// Latency histogram. Data points are in nanoseconds. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public global::Grpc.Testing.HistogramData Latencies { get { return latencies_; } set { @@ -635,6 +690,7 @@ namespace Grpc.Testing { /// <summary> /// See ServerStats for details. /// </summary> + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double TimeElapsed { get { return timeElapsed_; } set { @@ -645,6 +701,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "time_user" field.</summary> public const int TimeUserFieldNumber = 3; private double timeUser_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double TimeUser { get { return timeUser_; } set { @@ -655,6 +712,7 @@ namespace Grpc.Testing { /// <summary>Field number for the "time_system" field.</summary> public const int TimeSystemFieldNumber = 4; private double timeSystem_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public double TimeSystem { get { return timeSystem_; } set { @@ -662,10 +720,12 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override bool Equals(object other) { return Equals(other as ClientStats); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public bool Equals(ClientStats other) { if (ReferenceEquals(other, null)) { return false; @@ -680,6 +740,7 @@ namespace Grpc.Testing { return true; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override int GetHashCode() { int hash = 1; if (latencies_ != null) hash ^= Latencies.GetHashCode(); @@ -689,10 +750,12 @@ namespace Grpc.Testing { return hash; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public override string ToString() { return pb::JsonFormatter.ToDiagnosticString(this); } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void WriteTo(pb::CodedOutputStream output) { if (latencies_ != null) { output.WriteRawTag(10); @@ -712,6 +775,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public int CalculateSize() { int size = 0; if (latencies_ != null) { @@ -729,6 +793,7 @@ namespace Grpc.Testing { return size; } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(ClientStats other) { if (other == null) { return; @@ -750,6 +815,7 @@ namespace Grpc.Testing { } } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public void MergeFrom(pb::CodedInputStream input) { uint tag; while ((tag = input.ReadTag()) != 0) { diff --git a/src/csharp/Grpc.IntegrationTesting/Test.cs b/src/csharp/Grpc.IntegrationTesting/Test.cs index 9258dc185d..88c2b8a921 100644 --- a/src/csharp/Grpc.IntegrationTesting/Test.cs +++ b/src/csharp/Grpc.IntegrationTesting/Test.cs @@ -10,7 +10,6 @@ using scg = global::System.Collections.Generic; namespace Grpc.Testing { /// <summary>Holder for reflection information generated from src/proto/grpc/testing/test.proto</summary> - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class TestReflection { #region Descriptor diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs index 3e149da3e0..61f2ed4015 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs @@ -314,6 +314,7 @@ namespace Grpc.Testing { { return CallInvoker.AsyncDuplexStreamingCall(__Method_HalfDuplexCall, null, options); } + /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> protected override TestServiceClient NewInstance(ClientBaseConfiguration configuration) { return new TestServiceClient(configuration); @@ -420,6 +421,7 @@ namespace Grpc.Testing { { return CallInvoker.AsyncUnaryCall(__Method_UnimplementedCall, null, options, request); } + /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> protected override UnimplementedServiceClient NewInstance(ClientBaseConfiguration configuration) { return new UnimplementedServiceClient(configuration); @@ -535,6 +537,7 @@ namespace Grpc.Testing { { return CallInvoker.AsyncUnaryCall(__Method_Stop, null, options, request); } + /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> protected override ReconnectServiceClient NewInstance(ClientBaseConfiguration configuration) { return new ReconnectServiceClient(configuration); diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec index 0c937ab9cb..ba4e1d674c 100644 --- a/src/csharp/Grpc.Tools.nuspec +++ b/src/csharp/Grpc.Tools.nuspec @@ -17,17 +17,17 @@ </metadata> <files> <!-- forward slashes in src path enable building on Linux --> - <file src="protoc_plugins/windows_x86/protoc.exe" target="tools\windows_x86\protoc.exe" /> - <file src="protoc_plugins/windows_x86/grpc_csharp_plugin.exe" target="tools\windows_x86\grpc_csharp_plugin.exe" /> - <file src="protoc_plugins/windows_x64/protoc.exe" target="tools\windows_x64\protoc.exe" /> - <file src="protoc_plugins/windows_x64/grpc_csharp_plugin.exe" target="tools\windows_x64\grpc_csharp_plugin.exe" /> - <file src="protoc_plugins/linux_x86/protoc" target="tools\linux_x86\protoc" /> - <file src="protoc_plugins/linux_x86/grpc_csharp_plugin" target="tools\linux_x86\grpc_csharp_plugin" /> - <file src="protoc_plugins/linux_x64/protoc" target="tools\linux_x64\protoc" /> - <file src="protoc_plugins/linux_x64/grpc_csharp_plugin" target="tools\linux_x64\grpc_csharp_plugin" /> - <file src="protoc_plugins/macosx_x86/protoc" target="tools\macosx_x86\protoc" /> - <file src="protoc_plugins/macosx_x86/grpc_csharp_plugin" target="tools\macosx_x86\grpc_csharp_plugin" /> - <file src="protoc_plugins/macosx_x64/protoc" target="tools\macosx_x64\protoc" /> - <file src="protoc_plugins/macosx_x64/grpc_csharp_plugin" target="tools\macosx_x64\grpc_csharp_plugin" /> + <file src="protoc_plugins/windows_x86/protoc.exe" target="tools/windows_x86/protoc.exe" /> + <file src="protoc_plugins/windows_x86/grpc_csharp_plugin.exe" target="tools/windows_x86/grpc_csharp_plugin.exe" /> + <file src="protoc_plugins/windows_x64/protoc.exe" target="tools/windows_x64/protoc.exe" /> + <file src="protoc_plugins/windows_x64/grpc_csharp_plugin.exe" target="tools/windows_x64/grpc_csharp_plugin.exe" /> + <file src="protoc_plugins/linux_x86/protoc" target="tools/linux_x86/protoc" /> + <file src="protoc_plugins/linux_x86/grpc_csharp_plugin" target="tools/linux_x86/grpc_csharp_plugin" /> + <file src="protoc_plugins/linux_x64/protoc" target="tools/linux_x64/protoc" /> + <file src="protoc_plugins/linux_x64/grpc_csharp_plugin" target="tools/linux_x64/grpc_csharp_plugin" /> + <file src="protoc_plugins/macosx_x86/protoc" target="tools/macosx_x86/protoc" /> + <file src="protoc_plugins/macosx_x86/grpc_csharp_plugin" target="tools/macosx_x86/grpc_csharp_plugin" /> + <file src="protoc_plugins/macosx_x64/protoc" target="tools/macosx_x64/protoc" /> + <file src="protoc_plugins/macosx_x64/grpc_csharp_plugin" target="tools/macosx_x64/grpc_csharp_plugin" /> </files> </package> diff --git a/src/csharp/README.md b/src/csharp/README.md index 18d5945a8a..0405ff88a0 100644 --- a/src/csharp/README.md +++ b/src/csharp/README.md @@ -4,10 +4,13 @@ gRPC C# A C# implementation of gRPC. -Status ------- +SUPPORTED PLATFORMS +------------------ + +- .NET Framework 4.5+ (Windows) +- [.NET Core](https://dotnet.github.io/) on Linux, Windows and Mac OS X (starting from version 1.0.1) +- Mono 4+ on Linux, Windows and Mac OS X -Beta PREREQUISITES -------------- @@ -16,6 +19,7 @@ PREREQUISITES - Linux: Mono 4+, MonoDevelop 5.9+ (with NuGet add-in installed) - Mac OS X: Xamarin Studio 5.9+ + HOW TO USE -------------- @@ -69,12 +73,6 @@ different languages. tools/run_tests/run_tests.py -l csharp ``` -ON .NET CORE SUPPORT ------------------- - -We are committed to providing full support for [.NET Core](https://dotnet.github.io/) in near future, -but currently, the support is for .NET Core is experimental/work-in-progress. - DOCUMENTATION ------------- - [API Reference][] @@ -102,9 +100,7 @@ CONTENTS THE NATIVE DEPENDENCY --------------- -Internally, gRPC C# uses a native library written in C (gRPC C core) and invokes its functionality via P/Invoke. `grpc_csharp_ext` library is a native extension library that facilitates this by wrapping some C core API into a form that's more digestible for P/Invoke. - -Prior to version 0.13, installing `grpc_csharp_ext` was required to make gRPC work on Linux and MacOS. Starting with version 0.13, we have improved the packaging story significantly and precompiled versions of the native library for all supported platforms are now shipped with the NuGet package. Just installing the `Grpc` NuGet package should be the only step needed to use gRPC C#, regardless of your platform (Windows, Linux or Mac) and the bitness (32 or 64bit). +Internally, gRPC C# uses a native library written in C (gRPC C core) and invokes its functionality via P/Invoke. The fact that a native library is used should be fully transparent to the users and just installing the `Grpc.Core` NuGet package is the only step needed to use gRPC C# on all supported platforms. [API Reference]: http://www.grpc.io/grpc/csharp/ [Helloworld Example]: ../../examples/csharp/helloworld diff --git a/src/node/README.md b/src/node/README.md index 9eafce9243..4b906643bc 100644 --- a/src/node/README.md +++ b/src/node/README.md @@ -1,9 +1,6 @@ [![npm](https://img.shields.io/npm/v/grpc.svg)](https://www.npmjs.com/package/grpc) # Node.js gRPC Library -## Status -Beta - ## PREREQUISITES - `node`: This requires `node` to be installed, version `0.12` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package. diff --git a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj index ab7159cda2..8d34b26c4f 100644 --- a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj +++ b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 48; objects = { /* Begin PBXBuildFile section */ @@ -129,7 +129,7 @@ 6369A2621A9322E20015FC5C /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = gRPC; TargetAttributes = { 6369A2691A9322E20015FC5C = { @@ -138,7 +138,7 @@ }; }; buildConfigurationList = 6369A2651A9322E20015FC5C /* Build configuration list for PBXProject "Sample" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -253,8 +253,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -263,6 +265,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -296,8 +299,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -305,6 +310,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; diff --git a/src/objective-c/examples/Sample/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme b/src/objective-c/examples/Sample/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme index d399e22e46..881474b111 100644 --- a/src/objective-c/examples/Sample/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme +++ b/src/objective-c/examples/Sample/Sample.xcodeproj/xcshareddata/xcschemes/Sample.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0730" + LastUpgradeVersion = "0800" version = "1.3"> <BuildAction parallelizeBuildables = "YES" diff --git a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj index afc3da7116..55b392e778 100644 --- a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj +++ b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 48; objects = { /* Begin PBXBuildFile section */ @@ -123,16 +123,17 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = gRPC; TargetAttributes = { 633BFFC11B950B210007E424 = { CreatedOnToolsVersion = 6.4; + LastSwiftMigration = 0800; }; }; }; buildConfigurationList = 633BFFBD1B950B210007E424 /* Build configuration list for PBXProject "SwiftSample" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -246,8 +247,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -292,8 +295,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -312,6 +317,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.4; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -327,6 +333,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "io.grpc.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_VERSION = 3.0; USER_HEADER_SEARCH_PATHS = ""; }; name = Debug; @@ -341,6 +348,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "io.grpc.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_VERSION = 3.0; USER_HEADER_SEARCH_PATHS = ""; }; name = Release; @@ -355,7 +363,7 @@ 633BFFE01B950B210007E424 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; 633BFFE11B950B210007E424 /* Build configuration list for PBXNativeTarget "SwiftSample" */ = { isa = XCConfigurationList; @@ -364,7 +372,7 @@ 633BFFE31B950B210007E424 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ }; diff --git a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/xcshareddata/xcschemes/SwiftSample.xcscheme b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/xcshareddata/xcschemes/SwiftSample.xcscheme index bba6a02b2b..87bca5ec68 100644 --- a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/xcshareddata/xcschemes/SwiftSample.xcscheme +++ b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/xcshareddata/xcschemes/SwiftSample.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0730" + LastUpgradeVersion = "0800" version = "1.3"> <BuildAction parallelizeBuildables = "YES" diff --git a/src/objective-c/examples/SwiftSample/ViewController.swift b/src/objective-c/examples/SwiftSample/ViewController.swift index 66d4fa9412..6b25e71f2d 100644 --- a/src/objective-c/examples/SwiftSample/ViewController.swift +++ b/src/objective-c/examples/SwiftSample/ViewController.swift @@ -51,7 +51,7 @@ class ViewController: UIViewController { // Example gRPC call using a generated proto client library: let service = RMTTestService(host: RemoteHost) - service.unaryCallWithRequest(request) { response, error in + service.unaryCall(with: request) { response, error in if let response = response { NSLog("1. Finished successfully with response:\n\(response)") } else { @@ -63,40 +63,39 @@ class ViewController: UIViewController { // Same but manipulating headers: var RPC : GRPCProtoCall! // Needed to convince Swift to capture by reference (__block) - RPC = service.RPCToUnaryCallWithRequest(request) { response, error in + RPC = service.rpcToUnaryCall(with: request) { response, error in if let response = response { NSLog("2. Finished successfully with response:\n\(response)") } else { NSLog("2. Finished with error: \(error!)") } - NSLog("2. Response headers: \(RPC.responseHeaders)") - NSLog("2. Response trailers: \(RPC.responseTrailers)") + NSLog("2. Response headers: \(RPC.responseHeaders!)") + NSLog("2. Response trailers: \(RPC.responseTrailers!)") } - // TODO(jcanizales): Revert to using subscript syntax once XCode 8 is released. - RPC.requestHeaders.setObject("My value", forKey: "My-Header") + RPC.requestHeaders["My-Header"] = "My value"; RPC.start() // Same example call using the generic gRPC client library: - let method = GRPCProtoMethod(package: "grpc.testing", service: "TestService", method: "UnaryCall") + let method = GRPCProtoMethod(package: "grpc.testing", service: "TestService", method: "UnaryCall")! let requestsWriter = GRXWriter(value: request.data()) - let call = GRPCCall(host: RemoteHost, path: method.HTTPPath, requestsWriter: requestsWriter) + let call = GRPCCall(host: RemoteHost, path: method.httpPath, requestsWriter: requestsWriter)! - call.requestHeaders.setObject("My value", forKey: "My-Header") + call.requestHeaders["My-Header"] = "My value"; - call.startWithWriteable(GRXWriteable { response, error in - if let response = response as? NSData { + call.start(with: GRXWriteable { response, error in + if let response = response as? Data { NSLog("3. Received response:\n\(try! RMTSimpleResponse(data: response))") } else { NSLog("3. Finished with error: \(error!)") } - NSLog("3. Response headers: \(call.responseHeaders)") - NSLog("3. Response trailers: \(call.responseTrailers)") + NSLog("3. Response headers: \(call.responseHeaders!)") + NSLog("3. Response trailers: \(call.responseTrailers!)") }) } } diff --git a/src/objective-c/tests/Info.plist b/src/objective-c/tests/Info.plist index fbeeb96ba6..ba72822e87 100644 --- a/src/objective-c/tests/Info.plist +++ b/src/objective-c/tests/Info.plist @@ -7,7 +7,7 @@ <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleIdentifier</key> - <string>gRPC.$(PRODUCT_NAME:rfc1034identifier)</string> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index 44f22c9e85..9804734d6a 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -92,20 +92,21 @@ return 0; } ++ (void)setUp { +#ifdef GRPC_COMPILE_WITH_CRONET + // Cronet setup + [Cronet setHttp2Enabled:YES]; + [Cronet start]; + [GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]]; +#endif +} + - (void)setUp { self.continueAfterFailure = NO; [GRPCCall resetHostSettings]; _service = self.class.host ? [RMTTestService serviceWithHost:self.class.host] : nil; -#ifdef GRPC_COMPILE_WITH_CRONET - if (cronetEngine == NULL) { - // Cronet setup - [Cronet setHttp2Enabled:YES]; - [Cronet start]; - [GRPCCall useCronetWithEngine:[Cronet getGlobalEngine]]; - } -#endif } - (void)testEmptyUnaryRPC { diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index c4a6567ae0..8dccbf0f72 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 48; objects = { /* Begin PBXBuildFile section */ @@ -535,7 +535,7 @@ 635697BF1B14FC11007A7283 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0630; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = gRPC; TargetAttributes = { 5E8A5DA31D3840B4000F8BC4 = { @@ -565,7 +565,7 @@ }; }; buildConfigurationList = 635697C21B14FC11007A7283 /* Build configuration list for PBXProject "Tests" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 8.0"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -1151,8 +1151,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; @@ -1205,6 +1207,7 @@ ); INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "gRPC.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Cronet; @@ -1362,6 +1365,7 @@ ); INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "gRPC.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -1376,6 +1380,7 @@ ); INFOPLIST_FILE = Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "gRPC.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -1393,13 +1398,16 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -1436,8 +1444,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme index d1d616c4cf..740a1c0672 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/AllTests.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0630" + LastUpgradeVersion = "0800" version = "1.3"> <BuildAction parallelizeBuildables = "YES" diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme index a1da2e0c97..538149c4ee 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0730" + LastUpgradeVersion = "0800" version = "1.3"> <BuildAction parallelizeBuildables = "YES" diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme index ce358bf69f..acf6f38ef2 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalCleartext.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0700" + LastUpgradeVersion = "0800" version = "1.3"> <BuildAction parallelizeBuildables = "YES" diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSL.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSL.xcscheme index f268da1fb0..95cc317093 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSL.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsLocalSSL.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0700" + LastUpgradeVersion = "0800" version = "1.3"> <BuildAction parallelizeBuildables = "YES" diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme index 186d7208e0..8504845da4 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemote.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0700" + LastUpgradeVersion = "0800" version = "1.3"> <BuildAction parallelizeBuildables = "YES" diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme index 1d211115f7..08955e1e03 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0730" + LastUpgradeVersion = "0800" version = "1.3"> <BuildAction parallelizeBuildables = "YES" diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme index 3abc1d42e4..b5672fce02 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/RxLibraryUnitTests.xcscheme @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "0700" + LastUpgradeVersion = "0800" version = "1.3"> <BuildAction parallelizeBuildables = "YES" diff --git a/src/php/README.md b/src/php/README.md index 0e5b4de31e..1b15768d44 100644 --- a/src/php/README.md +++ b/src/php/README.md @@ -4,10 +4,6 @@ This directory contains source code for PHP implementation of gRPC layered on shared C library. -#Status - -GA - ## Environment **Prerequisite:** diff --git a/src/php/composer.json b/src/php/composer.json index 6042094032..2d5d555bc2 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -8,6 +8,7 @@ "version": "1.1.0", "require": { "php": ">=5.5.0", + "ext-grpc": "*", "google/protobuf": "v3.1.0-alpha-1" }, "require-dev": { diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php index 124d324913..72012a49d0 100755 --- a/src/php/tests/interop/interop_client.php +++ b/src/php/tests/interop/interop_client.php @@ -477,9 +477,11 @@ function statusCodeAndMessage($stub) list($result, $status) = $call->wait(); hardAssert($status->code === 2, - 'Received unexpected status code'); + 'Received unexpected UnaryCall status code: ' . + $status->code); hardAssert($status->details === 'test status message', - 'Received unexpected status details'); + 'Received unexpected UnaryCall status details: ' . + $status->details); $streaming_call = $stub->FullDuplexCall(); @@ -487,12 +489,15 @@ function statusCodeAndMessage($stub) $streaming_request->setResponseStatus($echo_status); $streaming_call->write($streaming_request); $streaming_call->writesDone(); + $result = $streaming_call->read(); $status = $streaming_call->getStatus(); hardAssert($status->code === 2, - 'Received unexpected status code'); + 'Received unexpected FullDuplexCall status code: ' . + $status->code); hardAssert($status->details === 'test status message', - 'Received unexpected status details'); + 'Received unexpected FullDuplexCall status details: ' . + $status->details); } function unimplementedMethod($stub) diff --git a/src/proto/grpc/testing/test.proto b/src/proto/grpc/testing/test.proto index 84369db4b8..d6ef58ab12 100644 --- a/src/proto/grpc/testing/test.proto +++ b/src/proto/grpc/testing/test.proto @@ -47,6 +47,11 @@ service TestService { // One request followed by one response. rpc UnaryCall(SimpleRequest) returns (SimpleResponse); + // One request followed by one response. Response has cache control + // headers set such that a caching HTTP proxy (such as GFE) can + // satisfy subsequent requests. + rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse); + // One request followed by a sequence of responses (streamed download). // The server returns the payload with client desired type and sizes. rpc StreamingOutputCall(StreamingOutputCallRequest) @@ -69,6 +74,10 @@ service TestService { // first request. rpc HalfDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); + + // The test server will not implement this method. It will be used + // to test the behavior when clients call unimplemented methods. + rpc UnimplementedMethod(grpc.testing.Empty) returns (grpc.testing.Empty); } // A simple service NOT implemented at servers so clients can test for diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi index ad20c94de9..9560fad137 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi @@ -173,10 +173,14 @@ cdef extern from "grpc/grpc.h": GRPC_ARG_INTEGER GRPC_ARG_POINTER - ctypedef struct grpc_arg_value_pointer: - void *address "p" + ctypedef struct grpc_arg_pointer_vtable: void *(*copy)(void *) void (*destroy)(void *) + int (*cmp)(void *, void *) + + ctypedef struct grpc_arg_value_pointer: + void *address "p" + grpc_arg_pointer_vtable *vtable union grpc_arg_value: char *string diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi index 96c5b02bc2..00ec91b131 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi @@ -84,6 +84,7 @@ cdef class SslPemKeyCertPair: cdef class ChannelArg: cdef grpc_arg c_arg + cdef grpc_arg_pointer_vtable ptr_vtable cdef readonly object key, value diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi index 5a11a08f54..8a4eef4d2e 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi +++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi @@ -27,6 +27,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from libc.stdint cimport intptr_t class ConnectivityState: idle = GRPC_CHANNEL_IDLE @@ -304,20 +305,49 @@ cdef class SslPemKeyCertPair: self.c_pair.certificate_chain = self.certificate_chain + +cdef void* copy_ptr(void* ptr): + return ptr + + +cdef void destroy_ptr(void* ptr): + pass + + +cdef int compare_ptr(void* ptr1, void* ptr2): + if ptr1 < ptr2: + return -1 + elif ptr1 > ptr2: + return 1 + else: + return 0 + + cdef class ChannelArg: def __cinit__(self, bytes key, value): self.key = key + self.value = value self.c_arg.key = self.key if isinstance(value, int): - self.value = value self.c_arg.type = GRPC_ARG_INTEGER self.c_arg.value.integer = self.value elif isinstance(value, bytes): - self.value = value self.c_arg.type = GRPC_ARG_STRING self.c_arg.value.string = self.value + elif hasattr(value, '__int__'): + # Pointer objects must override __int__() to return + # the underlying C address (Python ints are word size). The + # lifecycle of the pointer is fixed to the lifecycle of the + # python object wrapping it. + self.ptr_vtable.copy = ©_ptr + self.ptr_vtable.destroy = &destroy_ptr + self.ptr_vtable.cmp = &compare_ptr + self.c_arg.type = GRPC_ARG_POINTER + self.c_arg.value.pointer.vtable = &self.ptr_vtable + self.c_arg.value.pointer.address = <void*>(<intptr_t>int(self.value)) else: + # TODO Add supported pointer types to this message raise TypeError('Expected int or bytes, got {}'.format(type(value))) diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py index 5f846ce773..5223712dfa 100644 --- a/src/python/grpcio/grpc/_server.py +++ b/src/python/grpcio/grpc/_server.py @@ -462,7 +462,6 @@ def _unary_response_in_pool( rpc_event, state, response, response_serializer) if serialized_response is not None: _status(rpc_event, state, serialized_response) - return def _stream_response_in_pool( diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 5b270b3954..fb24e12d9b 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -134,11 +134,11 @@ CORE_SOURCE_FILES = [ 'src/core/lib/iomgr/udp_server.c', 'src/core/lib/iomgr/unix_sockets_posix.c', 'src/core/lib/iomgr/unix_sockets_posix_noop.c', + 'src/core/lib/iomgr/wakeup_fd_cv.c', 'src/core/lib/iomgr/wakeup_fd_eventfd.c', 'src/core/lib/iomgr/wakeup_fd_nospecial.c', 'src/core/lib/iomgr/wakeup_fd_pipe.c', 'src/core/lib/iomgr/wakeup_fd_posix.c', - 'src/core/lib/iomgr/workqueue_posix.c', 'src/core/lib/iomgr/workqueue_windows.c', 'src/core/lib/json/json.c', 'src/core/lib/json/json_reader.c', @@ -164,6 +164,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/surface/version.c', 'src/core/lib/transport/byte_stream.c', 'src/core/lib/transport/connectivity_state.c', + 'src/core/lib/transport/mdstr_hash_table.c', 'src/core/lib/transport/metadata.c', 'src/core/lib/transport/metadata_batch.c', 'src/core/lib/transport/static_metadata.c', @@ -233,6 +234,7 @@ CORE_SOURCE_FILES = [ 'src/core/ext/client_channel/lb_policy.c', 'src/core/ext/client_channel/lb_policy_factory.c', 'src/core/ext/client_channel/lb_policy_registry.c', + 'src/core/ext/client_channel/method_config.c', 'src/core/ext/client_channel/parse_address.c', 'src/core/ext/client_channel/resolver.c', 'src/core/ext/client_channel/resolver_factory.c', diff --git a/src/python/grpcio_tests/tests/unit/_channel_args_test.py b/src/python/grpcio_tests/tests/unit/_channel_args_test.py index 6a636d7993..b46497afd6 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_args_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_args_test.py @@ -33,11 +33,18 @@ import unittest import grpc +class TestPointerWrapper(object): + + def __int__(self): + return 123456 + + TEST_CHANNEL_ARGS = ( ('arg1', b'bytes_val'), ('arg2', 'str_val'), ('arg3', 1), (b'arg4', 'str_val'), + ('arg6', TestPointerWrapper()), ) diff --git a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py index 1324ad37b6..3d9dd17ff6 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py @@ -34,8 +34,6 @@ import time import unittest import grpc -from grpc import _channel -from grpc import _server from tests.unit.framework.common import test_constants from tests.unit import _thread_pool @@ -78,7 +76,7 @@ class ChannelConnectivityTest(unittest.TestCase): def test_lonely_channel_connectivity(self): callback = _Callback() - channel = _channel.Channel('localhost:12345', (), None) + channel = grpc.insecure_channel('localhost:12345') channel.subscribe(callback.update, try_to_connect=False) first_connectivities = callback.block_until_connectivities_satisfy(bool) channel.subscribe(callback.update, try_to_connect=True) @@ -105,13 +103,13 @@ class ChannelConnectivityTest(unittest.TestCase): def test_immediately_connectable_channel_connectivity(self): thread_pool = _thread_pool.RecordingThreadPool(max_workers=None) - server = _server.Server(thread_pool, (), ()) + server = grpc.server(thread_pool) port = server.add_insecure_port('[::]:0') server.start() first_callback = _Callback() second_callback = _Callback() - channel = _channel.Channel('localhost:{}'.format(port), (), None) + channel = grpc.insecure_channel('localhost:{}'.format(port)) channel.subscribe(first_callback.update, try_to_connect=False) first_connectivities = first_callback.block_until_connectivities_satisfy( bool) @@ -146,12 +144,12 @@ class ChannelConnectivityTest(unittest.TestCase): def test_reachable_then_unreachable_channel_connectivity(self): thread_pool = _thread_pool.RecordingThreadPool(max_workers=None) - server = _server.Server(thread_pool, (), ()) + server = grpc.server(thread_pool) port = server.add_insecure_port('[::]:0') server.start() callback = _Callback() - channel = _channel.Channel('localhost:{}'.format(port), (), None) + channel = grpc.insecure_channel('localhost:{}'.format(port)) channel.subscribe(callback.update, try_to_connect=True) callback.block_until_connectivities_satisfy(_ready_in_connectivities) # Now take down the server and confirm that channel readiness is repudiated. diff --git a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py index 60d478bcd9..e0a7d15aa7 100644 --- a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py +++ b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py @@ -33,8 +33,6 @@ import threading import unittest import grpc -from grpc import _channel -from grpc import _server from tests.unit.framework.common import test_constants from tests.unit import _thread_pool @@ -79,7 +77,7 @@ class ChannelReadyFutureTest(unittest.TestCase): def test_immediately_connectable_channel_connectivity(self): thread_pool = _thread_pool.RecordingThreadPool(max_workers=None) - server = _server.Server(thread_pool, (), ()) + server = grpc.server(thread_pool) port = server.add_insecure_port('[::]:0') server.start() channel = grpc.insecure_channel('localhost:{}'.format(port)) diff --git a/src/ruby/README.md b/src/ruby/README.md index 67e94dd354..f476fe72be 100644 --- a/src/ruby/README.md +++ b/src/ruby/README.md @@ -4,11 +4,6 @@ gRPC Ruby A Ruby implementation of gRPC. -Status ------- - -Beta - PREREQUISITES ------------- diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb index 48bc61e494..5ae4f25537 100644 --- a/src/ruby/spec/generic/active_call_spec.rb +++ b/src/ruby/spec/generic/active_call_spec.rb @@ -137,6 +137,8 @@ describe GRPC::ActiveCall do msg = 'message is a string' client_call.write_flag = f client_call.remote_send(msg) + # flush the message in case writes are set to buffered + call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil) if f == 1 # confirm that the message was marshalled recvd_rpc = @server.request_call |