aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Vijay Pai <vpai@google.com>2016-10-18 12:15:08 -0700
committerGravatar Vijay Pai <vpai@google.com>2016-10-18 12:15:08 -0700
commit9fa9315d62c3163a93eeae2b3d3bb70231567b83 (patch)
tree49968018548e4a294026a9f95b8ea5363efceb0e /src
parent23c5b812687d0ebb86ed86d64416b232f8771e56 (diff)
parent948f95b2ce4204f859c867207bd991d30ca17ee7 (diff)
Merge remote-tracking branch 'upstream/master' into fc_1dstream
Diffstat (limited to 'src')
-rw-r--r--src/compiler/csharp_generator.cc3
-rw-r--r--src/core/ext/client_config/client_channel.c22
-rw-r--r--src/core/ext/client_config/lb_policy.h6
-rw-r--r--src/core/ext/client_config/subchannel.c4
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb.c186
-rw-r--r--src/core/ext/lb_policy/pick_first/pick_first.c12
-rw-r--r--src/core/ext/lb_policy/round_robin/round_robin.c14
-rw-r--r--src/core/ext/load_reporting/load_reporting.h20
-rw-r--r--src/core/ext/load_reporting/load_reporting_filter.c4
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_plugin.c3
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c2214
-rw-r--r--src/core/ext/transport/chttp2/transport/frame.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.c68
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.h9
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_goaway.c18
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_goaway.h9
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.c13
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.h8
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.c38
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.h9
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.c23
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.h9
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_window_update.c34
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_window_update.h5
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.c492
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.h17
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h654
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c910
-rw-r--r--src/core/ext/transport/chttp2/transport/stream_lists.c351
-rw-r--r--src/core/ext/transport/chttp2/transport/stream_map.c36
-rw-r--r--src/core/ext/transport/chttp2/transport/stream_map.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.c466
-rw-r--r--src/core/lib/iomgr/closure.c18
-rw-r--r--src/core/lib/iomgr/closure.h11
-rw-r--r--src/core/lib/iomgr/combiner.c372
-rw-r--r--src/core/lib/iomgr/combiner.h15
-rw-r--r--src/core/lib/iomgr/error.c18
-rw-r--r--src/core/lib/iomgr/error.h12
-rw-r--r--src/core/lib/iomgr/ev_epoll_linux.c231
-rw-r--r--src/core/lib/iomgr/ev_poll_and_epoll_posix.c30
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.c271
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.h1
-rw-r--r--src/core/lib/iomgr/ev_posix.c24
-rw-r--r--src/core/lib/iomgr/ev_posix.h13
-rw-r--r--src/core/lib/iomgr/exec_ctx.c61
-rw-r--r--src/core/lib/iomgr/exec_ctx.h24
-rw-r--r--src/core/lib/iomgr/iomgr.c11
-rw-r--r--src/core/lib/iomgr/tcp_posix.c11
-rw-r--r--src/core/lib/iomgr/wakeup_fd_cv.c118
-rw-r--r--src/core/lib/iomgr/wakeup_fd_cv.h80
-rw-r--r--src/core/lib/iomgr/wakeup_fd_pipe.c12
-rw-r--r--src/core/lib/iomgr/wakeup_fd_posix.c33
-rw-r--r--src/core/lib/iomgr/wakeup_fd_posix.h5
-rw-r--r--src/core/lib/iomgr/workqueue.h16
-rw-r--r--src/core/lib/iomgr/workqueue_posix.c196
-rw-r--r--src/core/lib/iomgr/workqueue_windows.c10
-rw-r--r--src/core/lib/profiling/basic_timers.c11
-rw-r--r--src/core/lib/profiling/timers.h2
-rw-r--r--src/core/lib/support/log.c9
-rw-r--r--src/core/lib/support/string.c11
-rw-r--r--src/core/lib/support/string.h4
-rw-r--r--src/core/lib/surface/call.c118
-rw-r--r--src/core/lib/surface/call.h32
-rw-r--r--src/core/lib/surface/channel.c18
-rw-r--r--src/core/lib/surface/completion_queue.c167
-rw-r--r--src/core/lib/surface/completion_queue.h3
-rw-r--r--src/core/lib/surface/init.c4
-rw-r--r--src/core/lib/surface/server.c35
-rw-r--r--src/core/lib/surface/server.h3
-rw-r--r--src/core/lib/transport/connectivity_state.c3
-rw-r--r--src/core/lib/transport/static_metadata.c4
-rw-r--r--src/core/lib/transport/static_metadata.h21
-rw-r--r--src/core/lib/transport/transport.c35
-rw-r--r--src/core/lib/transport/transport.h9
-rw-r--r--src/core/lib/transport/transport_op_string.c105
-rw-r--r--src/cpp/test/server_context_test_spouse.cc (renamed from src/core/lib/iomgr/workqueue_posix.h)49
-rw-r--r--src/csharp/Grpc.Examples/Math.cs83
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs1
-rw-r--r--src/csharp/Grpc.HealthCheck/Health.cs35
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthGrpc.cs1
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Control.cs401
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Empty.cs16
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Messages.cs211
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Metrics.cs53
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs1
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Payloads.cs70
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Services.cs1
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Stats.cs76
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Test.cs1
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs3
-rw-r--r--src/objective-c/tests/InteropTests.m17
-rwxr-xr-xsrc/php/tests/interop/interop_client.php13
-rw-r--r--src/proto/grpc/testing/test.proto4
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi8
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/records.pxd.pxi1
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi34
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_args_test.py7
-rw-r--r--src/ruby/spec/generic/active_call_spec.rb2
101 files changed, 4888 insertions, 4058 deletions
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/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c
index a6056c3e8d..cbf79afa17 100644
--- a/src/core/ext/client_config/client_channel.c
+++ b/src/core/ext/client_config/client_channel.c
@@ -513,10 +513,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);
@@ -564,6 +568,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,
@@ -629,8 +636,8 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
gpr_mu_unlock(&chand->mu);
// 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)};
+ 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);
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "pick_subchannel");
@@ -672,6 +679,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 +747,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 */
diff --git a/src/core/ext/client_config/lb_policy.h b/src/core/ext/client_config/lb_policy.h
index 110d08fcac..de424cd105 100644
--- a/src/core/ext/client_config/lb_policy.h
+++ b/src/core/ext/client_config/lb_policy.h
@@ -35,7 +35,6 @@
#define GRPC_CORE_EXT_CLIENT_CONFIG_LB_POLICY_H
#include "src/core/ext/client_config/subchannel.h"
-#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/transport/connectivity_state.h"
/** A load balancing policy: specified by a vtable and a struct (which
@@ -55,8 +54,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
@@ -153,7 +150,8 @@ void grpc_lb_policy_init(grpc_lb_policy *policy,
once the pick is complete with its error argument set to indicate
success or failure.
- Any I/O should be done under \a pick_args->pollent. */
+ 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_config/subchannel.c b/src/core/ext/client_config/subchannel.c
index 0bbaa3e382..4cece2d908 100644
--- a/src/core/ext/client_config/subchannel.c
+++ b/src/core/ext/client_config/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;
}
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
index 626f285b90..9af92b787d 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. */
@@ -134,6 +134,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 +158,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 +185,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 +209,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 +228,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 +238,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 +246,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;
}
@@ -307,13 +303,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 */
@@ -399,14 +388,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 +413,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;
@@ -446,18 +469,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 +504,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 +519,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 +532,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 +550,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);
}
@@ -648,15 +675,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 +713,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 +744,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;
@@ -775,39 +798,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 +935,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,
@@ -1076,6 +1080,7 @@ static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
/* 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 +1098,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 +1106,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,
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 961a0c9b19..6533327343 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);
}
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 930fa86aca..9bd3f9da24 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);
}
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/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/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..351b069613 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
*/
@@ -1236,10 +1260,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 +1524,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/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/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..c4effa9a05 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -223,33 +223,33 @@ 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;
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];
}
- 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,75 +257,75 @@ 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));
+ args->server_transport_data, 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(
@@ -334,7 +334,7 @@ grpc_call *grpc_call_create(
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 +1038,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 +1054,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 +1203,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 +1218,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 +1316,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 +1352,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/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/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.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/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/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 b52c4cbad6..d6ef58ab12 100644
--- a/src/proto/grpc/testing/test.proto
+++ b/src/proto/grpc/testing/test.proto
@@ -74,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 = &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_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 2bebf48c70..406f88a02d 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',
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/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