aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Craig Tiller <ctiller@google.com>2016-09-23 09:52:37 -0700
committerGravatar Craig Tiller <ctiller@google.com>2016-09-23 09:52:37 -0700
commitc5423beeb89982a2c9f59a926e5807555122a1ca (patch)
treedd6a7fb08e4d3be123bf13025c2ae3b43f817436 /src
parent3f665f5fefb4ec7687f44d8a60eb660bee1f3e6c (diff)
parent687a0e641057d42394e1574629df6368cc6e5322 (diff)
Merge branch 'direct-calls' into zefuzz-dc
Diffstat (limited to 'src')
-rw-r--r--src/core/ext/census/trace_context.c86
-rw-r--r--src/core/ext/census/trace_context.h68
-rw-r--r--src/core/ext/census/tracing.c16
-rw-r--r--src/core/ext/client_config/client_channel.c56
-rw-r--r--src/core/ext/client_config/client_channel.h13
-rw-r--r--src/core/ext/client_config/lb_policy.c10
-rw-r--r--src/core/ext/client_config/lb_policy.h60
-rw-r--r--src/core/ext/client_config/lb_policy_factory.c58
-rw-r--r--src/core/ext/client_config/lb_policy_factory.h48
-rw-r--r--src/core/ext/client_config/resolver_factory.h5
-rw-r--r--src/core/ext/client_config/resolver_registry.c4
-rw-r--r--src/core/ext/client_config/resolver_registry.h3
-rw-r--r--src/core/ext/client_config/resolver_result.c122
-rw-r--r--src/core/ext/client_config/resolver_result.h103
-rw-r--r--src/core/ext/client_config/subchannel.c48
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb.c385
-rw-r--r--src/core/ext/lb_policy/grpclb/load_balancer_api.c5
-rw-r--r--src/core/ext/lb_policy/grpclb/load_balancer_api.h1
-rw-r--r--src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c10
-rw-r--r--src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h32
-rw-r--r--src/core/ext/lb_policy/pick_first/pick_first.c40
-rw-r--r--src/core/ext/lb_policy/round_robin/round_robin.c102
-rw-r--r--src/core/ext/resolver/dns/native/dns_resolver.c30
-rw-r--r--src/core/ext/resolver/sockaddr/sockaddr_resolver.c50
-rw-r--r--src/core/ext/transport/chttp2/client/insecure/channel_create.c17
-rw-r--r--src/core/ext/transport/chttp2/client/secure/secure_channel_create.c15
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_plugin.c3
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c2534
-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.h669
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c884
-rw-r--r--src/core/ext/transport/chttp2/transport/stream_lists.c344
-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.c465
-rw-r--r--src/core/lib/channel/channel_args.c18
-rw-r--r--src/core/lib/channel/channel_args.h8
-rw-r--r--src/core/lib/channel/channel_stack.c23
-rw-r--r--src/core/lib/channel/compress_filter.c14
-rw-r--r--src/core/lib/channel/message_size_filter.c165
-rw-r--r--src/core/lib/channel/message_size_filter.h39
-rw-r--r--src/core/lib/iomgr/closure.c20
-rw-r--r--src/core/lib/iomgr/closure.h25
-rw-r--r--src/core/lib/iomgr/combiner.c324
-rw-r--r--src/core/lib/iomgr/combiner.h66
-rw-r--r--src/core/lib/iomgr/error.c4
-rw-r--r--src/core/lib/iomgr/error.h8
-rw-r--r--src/core/lib/iomgr/ev_epoll_linux.c211
-rw-r--r--src/core/lib/iomgr/ev_poll_and_epoll_posix.c30
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.c30
-rw-r--r--src/core/lib/iomgr/ev_posix.c23
-rw-r--r--src/core/lib/iomgr/ev_posix.h13
-rw-r--r--src/core/lib/iomgr/exec_ctx.c65
-rw-r--r--src/core/lib/iomgr/exec_ctx.h18
-rw-r--r--src/core/lib/iomgr/iomgr.c11
-rw-r--r--src/core/lib/iomgr/tcp_posix.c28
-rw-r--r--src/core/lib/iomgr/workqueue.h20
-rw-r--r--src/core/lib/iomgr/workqueue_posix.c151
-rw-r--r--src/core/lib/iomgr/workqueue_windows.c12
-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/security/credentials/plugin/plugin_credentials.c25
-rw-r--r--src/core/lib/security/transport/client_auth_filter.c5
-rw-r--r--src/core/lib/security/transport/secure_endpoint.c5
-rw-r--r--src/core/lib/security/transport/server_auth_filter.c27
-rw-r--r--src/core/lib/support/log.c9
-rw-r--r--src/core/lib/support/mpscq.c83
-rw-r--r--src/core/lib/support/mpscq.h (renamed from src/core/lib/iomgr/workqueue_posix.h)47
-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.c195
-rw-r--r--src/core/lib/surface/call.h32
-rw-r--r--src/core/lib/surface/channel.c46
-rw-r--r--src/core/lib/surface/channel.h1
-rw-r--r--src/core/lib/surface/channel_ping.c11
-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.c16
-rw-r--r--src/core/lib/surface/lame_client.c6
-rw-r--r--src/core/lib/surface/server.c90
-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/metadata.c18
-rw-r--r--src/core/lib/transport/metadata.h2
-rw-r--r--src/core/lib/transport/transport.c62
-rw-r--r--src/core/lib/transport/transport.h30
-rw-r--r--src/core/lib/transport/transport_op_string.c95
-rw-r--r--src/cpp/server/server_builder.cc15
-rw-r--r--src/cpp/server/server_cc.cc10
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs4
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs102
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs31
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs40
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallServer.cs6
-rw-r--r--src/csharp/Grpc.Tools.nuspec25
-rw-r--r--src/csharp/build_packages.bat8
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.sh3
-rw-r--r--src/objective-c/GRPCClient/private/GRPCHost.m2
-rw-r--r--src/objective-c/tests/InteropTests.m2
-rwxr-xr-xsrc/objective-c/tests/run_tests.sh4
-rw-r--r--src/php/lib/Grpc/BaseStub.php1
-rwxr-xr-xsrc/php/tests/interop/interop_client.php102
-rw-r--r--src/php/tests/unit_tests/CallCredentials2Test.php3
-rw-r--r--src/proto/grpc/lb/v1/load_balancer.options4
-rw-r--r--src/proto/grpc/lb/v1/load_balancer.proto31
-rw-r--r--src/python/grpcio/commands.py3
-rw-r--r--src/python/grpcio/grpc/__init__.py12
-rw-r--r--src/python/grpcio/grpc/_channel.py17
-rw-r--r--src/python/grpcio/grpc/_common.py10
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi5
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi2
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi2
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi2
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi4
-rw-r--r--src/python/grpcio/grpc/_cython/cygrpc.pxd16
-rw-r--r--src/python/grpcio/grpc/_cython/cygrpc.pyx16
-rw-r--r--src/python/grpcio/grpc/_server.py5
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py5
-rw-r--r--src/python/grpcio_tests/tests/tests.json1
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_args_test.py53
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py10
-rw-r--r--src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py2
-rw-r--r--src/python/grpcio_tests/tests/unit/_cython/_cancel_many_calls_test.py5
-rw-r--r--src/python/grpcio_tests/tests/unit/_cython/_read_some_but_not_all_responses_test.py5
-rw-r--r--src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py9
-rw-r--r--src/ruby/ext/grpc/rb_channel.c2
140 files changed, 5424 insertions, 4572 deletions
diff --git a/src/core/ext/census/trace_context.c b/src/core/ext/census/trace_context.c
new file mode 100644
index 0000000000..fbb20d3448
--- /dev/null
+++ b/src/core/ext/census/trace_context.c
@@ -0,0 +1,86 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/census/trace_context.h"
+
+#include <grpc/census.h>
+#include <grpc/support/log.h>
+#include <stdbool.h>
+
+#include "third_party/nanopb/pb_decode.h"
+#include "third_party/nanopb/pb_encode.h"
+
+// This function assumes the TraceContext is valid.
+size_t encode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer,
+ const size_t buf_size) {
+ // Create a stream that will write to our buffer.
+ pb_ostream_t stream = pb_ostream_from_buffer(buffer, buf_size);
+
+ // encode message
+ bool status = pb_encode(&stream, google_trace_TraceContext_fields, ctxt);
+
+ if (!status) {
+ gpr_log(GPR_DEBUG, "TraceContext encoding failed: %s",
+ PB_GET_ERROR(&stream));
+ return 0;
+ }
+
+ return stream.bytes_written;
+}
+
+bool decode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer,
+ const size_t nbytes) {
+ // Create a stream that reads nbytes from the buffer.
+ pb_istream_t stream = pb_istream_from_buffer(buffer, nbytes);
+
+ // decode message
+ bool status = pb_decode(&stream, google_trace_TraceContext_fields, ctxt);
+
+ if (!status) {
+ gpr_log(GPR_DEBUG, "TraceContext decoding failed: %s",
+ PB_GET_ERROR(&stream));
+ return false;
+ }
+
+ // check fields
+ if (!ctxt->has_trace_id) {
+ gpr_log(GPR_DEBUG, "Invalid TraceContext: missing trace_id");
+ return false;
+ }
+ if (!ctxt->has_span_id) {
+ gpr_log(GPR_DEBUG, "Invalid TraceContext: missing span_id");
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/core/ext/census/trace_context.h b/src/core/ext/census/trace_context.h
new file mode 100644
index 0000000000..ee71fef460
--- /dev/null
+++ b/src/core/ext/census/trace_context.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/* Functions for manipulating trace contexts as defined in
+ src/proto/census/trace.proto */
+#ifndef GRPC_CORE_EXT_CENSUS_TRACE_CONTEXT_H
+#define GRPC_CORE_EXT_CENSUS_TRACE_CONTEXT_H
+
+#include "src/core/ext/census/gen/trace_context.pb.h"
+
+/* Maximum number of bytes required to encode a TraceContext (31)
+1 byte for trace_id field
+1 byte for trace_id length
+1 byte for trace_id.hi field
+8 bytes for trace_id.hi (uint64_t)
+1 byte for trace_id.lo field
+8 bytes for trace_id.lo (uint64_t)
+1 byte for span_id field
+8 bytes for span_id (uint64_t)
+1 byte for is_sampled field
+1 byte for is_sampled (bool) */
+#define TRACE_MAX_CONTEXT_SIZE 31
+
+/* Encode a trace context (ctxt) into proto format to the buffer provided. The
+size of buffer must be at least TRACE_MAX_CONTEXT_SIZE. On success, returns the
+number of bytes successfully encoded into buffer. On failure, returns 0. */
+size_t encode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer,
+ const size_t buf_size);
+
+/* Decode a proto-encoded TraceContext from the provided buffer into the
+TraceContext structure (ctxt). The function expects to be supplied the number
+of bytes to be read from buffer (nbytes). This function will also validate that
+the TraceContext has a span_id and a trace_id, and will return false if either
+of these do not exist. On success, returns true and false otherwise. */
+bool decode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer,
+ const size_t nbytes);
+
+#endif
diff --git a/src/core/ext/census/tracing.c b/src/core/ext/census/tracing.c
index 3b5d6dab2b..8f0e12296d 100644
--- a/src/core/ext/census/tracing.c
+++ b/src/core/ext/census/tracing.c
@@ -31,15 +31,19 @@
*
*/
+//#include "src/core/ext/census/tracing.h"
+
#include <grpc/census.h>
/* TODO(aveitch): These are all placeholder implementations. */
-int census_trace_mask(const census_context *context) {
- return CENSUS_TRACE_MASK_NONE;
-}
+// int census_trace_mask(const census_context *context) {
+// return CENSUS_TRACE_MASK_NONE;
+// }
+
+// void census_set_trace_mask(int trace_mask) {}
-void census_set_trace_mask(int trace_mask) {}
+// void census_trace_print(census_context *context, uint32_t type,
+// const char *buffer, size_t n) {}
-void census_trace_print(census_context *context, uint32_t type,
- const char *buffer, size_t n) {}
+// void SetTracerParams(const Params& params);
diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c
index 61e012578e..63797bfa1e 100644
--- a/src/core/ext/client_config/client_channel.c
+++ b/src/core/ext/client_config/client_channel.c
@@ -42,6 +42,7 @@
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
+#include "src/core/ext/client_config/lb_policy_registry.h"
#include "src/core/ext/client_config/subchannel.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/connected_channel.h"
@@ -63,6 +64,8 @@ typedef struct client_channel_channel_data {
grpc_resolver *resolver;
/** have we started resolving this channel */
bool started_resolving;
+ /** client channel factory */
+ grpc_client_channel_factory *client_channel_factory;
/** mutex protecting client configuration, including all
variables below in this data structure */
@@ -173,20 +176,26 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
if (chand->resolver_result != NULL) {
- lb_policy = grpc_resolver_result_get_lb_policy(chand->resolver_result);
+ grpc_lb_policy_args lb_policy_args;
+ lb_policy_args.addresses =
+ grpc_resolver_result_get_addresses(chand->resolver_result);
+ lb_policy_args.additional_args =
+ grpc_resolver_result_get_lb_policy_args(chand->resolver_result);
+ lb_policy_args.client_channel_factory = chand->client_channel_factory;
+ lb_policy = grpc_lb_policy_create(
+ exec_ctx,
+ grpc_resolver_result_get_lb_policy_name(chand->resolver_result),
+ &lb_policy_args);
if (lb_policy != NULL) {
- GRPC_LB_POLICY_REF(lb_policy, "channel");
GRPC_LB_POLICY_REF(lb_policy, "config_change");
GRPC_ERROR_UNREF(state_error);
state =
grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error);
}
-
grpc_resolver_result_unref(exec_ctx, chand->resolver_result);
+ chand->resolver_result = NULL;
}
- chand->resolver_result = NULL;
-
if (lb_policy != NULL) {
grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties,
chand->interested_parties);
@@ -346,6 +355,9 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_resolver_shutdown(exec_ctx, chand->resolver);
GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
}
+ if (chand->client_channel_factory != NULL) {
+ grpc_client_channel_factory_unref(exec_ctx, chand->client_channel_factory);
+ }
if (chand->lb_policy != NULL) {
grpc_pollset_set_del_pollset_set(exec_ctx,
chand->lb_policy->interested_parties,
@@ -387,13 +399,15 @@ typedef struct client_channel_call_data {
grpc_connected_subchannel *connected_subchannel;
grpc_polling_entity *pollent;
- grpc_transport_stream_op *waiting_ops;
+ grpc_transport_stream_op **waiting_ops;
size_t waiting_ops_count;
size_t waiting_ops_capacity;
grpc_closure next_step;
grpc_call_stack *owning_call;
+
+ grpc_linked_mdelem lb_token_mdelem;
} call_data;
static void add_waiting_locked(call_data *calld, grpc_transport_stream_op *op) {
@@ -404,7 +418,7 @@ static void add_waiting_locked(call_data *calld, grpc_transport_stream_op *op) {
gpr_realloc(calld->waiting_ops,
calld->waiting_ops_capacity * sizeof(*calld->waiting_ops));
}
- calld->waiting_ops[calld->waiting_ops_count++] = *op;
+ calld->waiting_ops[calld->waiting_ops_count++] = op;
GPR_TIMER_END("add_waiting_locked", 0);
}
@@ -413,14 +427,14 @@ static void fail_locked(grpc_exec_ctx *exec_ctx, call_data *calld,
size_t i;
for (i = 0; i < calld->waiting_ops_count; i++) {
grpc_transport_stream_op_finish_with_failure(
- exec_ctx, &calld->waiting_ops[i], GRPC_ERROR_REF(error));
+ exec_ctx, calld->waiting_ops[i], GRPC_ERROR_REF(error));
}
calld->waiting_ops_count = 0;
GRPC_ERROR_UNREF(error);
}
typedef struct {
- grpc_transport_stream_op *ops;
+ grpc_transport_stream_op **ops;
size_t nops;
grpc_subchannel_call *call;
} retry_ops_args;
@@ -429,7 +443,7 @@ static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) {
retry_ops_args *a = args;
size_t i;
for (i = 0; i < a->nops; i++) {
- grpc_subchannel_call_process_op(exec_ctx, a->call, &a->ops[i]);
+ grpc_subchannel_call_process_op(exec_ctx, a->call, a->ops[i]);
}
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops");
gpr_free(a->ops);
@@ -437,6 +451,10 @@ static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) {
}
static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) {
+ if (calld->waiting_ops_count == 0) {
+ return;
+ }
+
retry_ops_args *a = gpr_malloc(sizeof(*a));
a->ops = calld->waiting_ops;
a->nops = calld->waiting_ops_count;
@@ -566,9 +584,11 @@ static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
int r;
GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel");
gpr_mu_unlock(&chand->mu);
- r = grpc_lb_policy_pick(exec_ctx, lb_policy, calld->pollent,
- initial_metadata, initial_metadata_flags,
- connected_subchannel, on_ready);
+ const grpc_lb_policy_pick_args inputs = {calld->pollent, initial_metadata,
+ initial_metadata_flags,
+ &calld->lb_token_mdelem};
+ 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");
GPR_TIMER_END("pick_subchannel", 0);
return r;
@@ -759,10 +779,12 @@ const grpc_channel_filter grpc_client_channel_filter = {
"client-channel",
};
-void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx,
- grpc_channel_stack *channel_stack,
- grpc_resolver *resolver) {
+void grpc_client_channel_finish_initialization(
+ grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
+ grpc_resolver *resolver,
+ grpc_client_channel_factory *client_channel_factory) {
/* post construction initialization: set the transport setup pointer */
+ GPR_ASSERT(client_channel_factory != NULL);
grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
channel_data *chand = elem->channel_data;
gpr_mu_lock(&chand->mu);
@@ -776,6 +798,8 @@ void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx,
grpc_resolver_next(exec_ctx, resolver, &chand->resolver_result,
&chand->on_resolver_result_changed);
}
+ chand->client_channel_factory = client_channel_factory;
+ grpc_client_channel_factory_ref(client_channel_factory);
gpr_mu_unlock(&chand->mu);
}
diff --git a/src/core/ext/client_config/client_channel.h b/src/core/ext/client_config/client_channel.h
index 1e47ad34ad..abb5ac4d87 100644
--- a/src/core/ext/client_config/client_channel.h
+++ b/src/core/ext/client_config/client_channel.h
@@ -34,6 +34,7 @@
#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_CLIENT_CHANNEL_H
#define GRPC_CORE_EXT_CLIENT_CONFIG_CLIENT_CHANNEL_H
+#include "src/core/ext/client_config/client_channel_factory.h"
#include "src/core/ext/client_config/resolver.h"
#include "src/core/lib/channel/channel_stack.h"
@@ -46,12 +47,12 @@
extern const grpc_channel_filter grpc_client_channel_filter;
-/* post-construction initializer to let the client channel know which
- transport setup it should cancel upon destruction, or initiate when it needs
- a connection */
-void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx,
- grpc_channel_stack *channel_stack,
- grpc_resolver *resolver);
+/* Post-construction initializer to give the client channel its resolver
+ and factory. */
+void grpc_client_channel_finish_initialization(
+ grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
+ grpc_resolver *resolver,
+ grpc_client_channel_factory *client_channel_factory);
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
diff --git a/src/core/ext/client_config/lb_policy.c b/src/core/ext/client_config/lb_policy.c
index 8b980b2cca..903563ef6b 100644
--- a/src/core/ext/client_config/lb_policy.c
+++ b/src/core/ext/client_config/lb_policy.c
@@ -100,13 +100,11 @@ void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx,
}
int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_polling_entity *pollent,
- grpc_metadata_batch *initial_metadata,
- uint32_t initial_metadata_flags,
- grpc_connected_subchannel **target,
+ const grpc_lb_policy_pick_args *pick_args,
+ grpc_connected_subchannel **target, void **user_data,
grpc_closure *on_complete) {
- return policy->vtable->pick(exec_ctx, policy, pollent, initial_metadata,
- initial_metadata_flags, target, on_complete);
+ return policy->vtable->pick(exec_ctx, policy, pick_args, target, user_data,
+ on_complete);
}
void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
diff --git a/src/core/ext/client_config/lb_policy.h b/src/core/ext/client_config/lb_policy.h
index a2f5446fc6..37c93d707c 100644
--- a/src/core/ext/client_config/lb_policy.h
+++ b/src/core/ext/client_config/lb_policy.h
@@ -53,23 +53,38 @@ struct grpc_lb_policy {
grpc_pollset_set *interested_parties;
};
+/** 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;
+ /** See \a GRPC_INITIAL_METADATA_* in grpc_types.h */
+ uint32_t initial_metadata_flags;
+ /** Storage for LB token in \a initial_metadata, or NULL if not used */
+ grpc_linked_mdelem *lb_token_mdelem_storage;
+} grpc_lb_policy_pick_args;
+
struct grpc_lb_policy_vtable {
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
-
void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
- /** implement grpc_lb_policy_pick */
+ /** \see grpc_lb_policy_pick */
int (*pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_polling_entity *pollent,
- grpc_metadata_batch *initial_metadata,
- uint32_t initial_metadata_flags,
- grpc_connected_subchannel **target, grpc_closure *on_complete);
+ const grpc_lb_policy_pick_args *pick_args,
+ grpc_connected_subchannel **target, void **user_data,
+ grpc_closure *on_complete);
+
+ /** \see grpc_lb_policy_cancel_pick */
void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_connected_subchannel **target);
+
+ /** \see grpc_lb_policy_cancel_picks */
void (*cancel_picks)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
uint32_t initial_metadata_flags_mask,
uint32_t initial_metadata_flags_eq);
+ /** \see grpc_lb_policy_ping_one */
void (*ping_one)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_closure *closure);
@@ -83,8 +98,7 @@ struct grpc_lb_policy_vtable {
/** call notify when the connectivity state of a channel changes from *state.
Updates *state with the new state of the policy. Calling with a NULL \a
- state cancels the subscription.
- */
+ state cancels the subscription. */
void (*notify_on_state_change)(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *policy,
grpc_connectivity_state *state,
@@ -124,26 +138,34 @@ void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
void grpc_lb_policy_init(grpc_lb_policy *policy,
const grpc_lb_policy_vtable *vtable);
-/** Given initial metadata in \a initial_metadata, find an appropriate
- target for this rpc, and 'return' it by calling \a on_complete after setting
- \a target.
- Picking can be asynchronous. Any IO should be done under \a pollent. */
+/** Find an appropriate target for this call, based on \a pick_args.
+ Picking can be synchronous or asynchronous. In the synchronous case, when a
+ pick is readily available, it'll be returned in \a target and a non-zero
+ value will be returned.
+ In the asynchronous case, zero is returned and \a on_complete will be called
+ once \a target and \a user_data have been set. Any IO should be done under
+ \a pick_args->pollent. The opaque \a user_data output argument corresponds
+ to information that may need be propagated from the LB policy. It may be
+ NULL. Errors are signaled by receiving a NULL \a *target. */
int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_polling_entity *pollent,
- grpc_metadata_batch *initial_metadata,
- uint32_t initial_metadata_flags,
- grpc_connected_subchannel **target,
+ const grpc_lb_policy_pick_args *pick_args,
+ grpc_connected_subchannel **target, void **user_data,
grpc_closure *on_complete);
+/** Perform a connected subchannel ping (see \a grpc_connected_subchannel_ping)
+ against one of the connected subchannels managed by \a policy. */
void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_closure *closure);
+/** Cancel picks for \a target.
+ The \a on_complete callback of the pending picks will be invoked with \a
+ *target set to NULL. */
void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_connected_subchannel **target);
-/** Cancel all pending picks which have:
- (initial_metadata_flags & initial_metadata_flags_mask) ==
- initial_metadata_flags_eq */
+/** Cancel all pending picks for which their \a initial_metadata_flags (as given
+ in the call to \a grpc_lb_policy_pick) matches \a initial_metadata_flags_eq
+ when AND'd with \a initial_metadata_flags_mask */
void grpc_lb_policy_cancel_picks(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *policy,
uint32_t initial_metadata_flags_mask,
diff --git a/src/core/ext/client_config/lb_policy_factory.c b/src/core/ext/client_config/lb_policy_factory.c
index 70e46ef3cf..c17af91a09 100644
--- a/src/core/ext/client_config/lb_policy_factory.c
+++ b/src/core/ext/client_config/lb_policy_factory.c
@@ -31,8 +31,66 @@
*
*/
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
#include "src/core/ext/client_config/lb_policy_factory.h"
+grpc_lb_addresses* grpc_lb_addresses_create(size_t num_addresses) {
+ grpc_lb_addresses* addresses = gpr_malloc(sizeof(grpc_lb_addresses));
+ addresses->num_addresses = num_addresses;
+ const size_t addresses_size = sizeof(grpc_lb_address) * num_addresses;
+ addresses->addresses = gpr_malloc(addresses_size);
+ memset(addresses->addresses, 0, addresses_size);
+ return addresses;
+}
+
+grpc_lb_addresses* grpc_lb_addresses_copy(grpc_lb_addresses* addresses,
+ void* (*user_data_copy)(void*)) {
+ grpc_lb_addresses* new_addresses =
+ grpc_lb_addresses_create(addresses->num_addresses);
+ memcpy(new_addresses->addresses, addresses->addresses,
+ sizeof(grpc_lb_address) * addresses->num_addresses);
+ for (size_t i = 0; i < addresses->num_addresses; ++i) {
+ if (new_addresses->addresses[i].balancer_name != NULL) {
+ new_addresses->addresses[i].balancer_name =
+ gpr_strdup(new_addresses->addresses[i].balancer_name);
+ }
+ if (user_data_copy != NULL) {
+ new_addresses->addresses[i].user_data =
+ user_data_copy(new_addresses->addresses[i].user_data);
+ }
+ }
+ return new_addresses;
+}
+
+void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index,
+ void* address, size_t address_len,
+ bool is_balancer, char* balancer_name,
+ void* user_data) {
+ GPR_ASSERT(index < addresses->num_addresses);
+ grpc_lb_address* target = &addresses->addresses[index];
+ memcpy(target->address.addr, address, address_len);
+ target->address.len = address_len;
+ target->is_balancer = is_balancer;
+ target->balancer_name = balancer_name;
+ target->user_data = user_data;
+}
+
+void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses,
+ void (*user_data_destroy)(void*)) {
+ for (size_t i = 0; i < addresses->num_addresses; ++i) {
+ gpr_free(addresses->addresses[i].balancer_name);
+ if (user_data_destroy != NULL) {
+ user_data_destroy(addresses->addresses[i].user_data);
+ }
+ }
+ gpr_free(addresses->addresses);
+ gpr_free(addresses);
+}
+
void grpc_lb_policy_factory_ref(grpc_lb_policy_factory* factory) {
factory->vtable->ref(factory);
}
diff --git a/src/core/ext/client_config/lb_policy_factory.h b/src/core/ext/client_config/lb_policy_factory.h
index da1de3579a..54408c6308 100644
--- a/src/core/ext/client_config/lb_policy_factory.h
+++ b/src/core/ext/client_config/lb_policy_factory.h
@@ -36,9 +36,9 @@
#include "src/core/ext/client_config/client_channel_factory.h"
#include "src/core/ext/client_config/lb_policy.h"
-#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/resolve_address.h"
typedef struct grpc_lb_policy_factory grpc_lb_policy_factory;
typedef struct grpc_lb_policy_factory_vtable grpc_lb_policy_factory_vtable;
@@ -47,9 +47,53 @@ struct grpc_lb_policy_factory {
const grpc_lb_policy_factory_vtable *vtable;
};
+/** A resolved address alongside any LB related information associated with it.
+ * \a user_data, if not NULL, contains opaque data meant to be consumed by the
+ * gRPC LB policy. Note that no all LB policies support \a user_data as input.
+ * Those who don't will simply ignore it and will correspondingly return NULL in
+ * their namesake pick() output argument. */
+typedef struct grpc_lb_address {
+ grpc_resolved_address address;
+ bool is_balancer;
+ char *balancer_name; /* For secure naming. */
+ void *user_data;
+} grpc_lb_address;
+
+typedef struct grpc_lb_addresses {
+ size_t num_addresses;
+ grpc_lb_address *addresses;
+} grpc_lb_addresses;
+
+/** Returns a grpc_addresses struct with enough space for
+ * \a num_addresses addresses. */
+grpc_lb_addresses *grpc_lb_addresses_create(size_t num_addresses);
+
+/** Creates a copy of \a addresses. If \a user_data_copy is not NULL,
+ * it will be invoked to copy the \a user_data field of each address. */
+grpc_lb_addresses *grpc_lb_addresses_copy(grpc_lb_addresses *addresses,
+ void *(*user_data_copy)(void *));
+
+/** Sets the value of the address at index \a index of \a addresses.
+ * \a address is a socket address of length \a address_len.
+ * Takes ownership of \a balancer_name. */
+void grpc_lb_addresses_set_address(grpc_lb_addresses *addresses, size_t index,
+ void *address, size_t address_len,
+ bool is_balancer, char *balancer_name,
+ void *user_data);
+
+/** Destroys \a addresses. If \a user_data_destroy is not NULL, it will
+ * be invoked to destroy the \a user_data field of each address. */
+void grpc_lb_addresses_destroy(grpc_lb_addresses *addresses,
+ void (*user_data_destroy)(void *));
+
+/** Arguments passed to LB policies. */
+/* TODO(roth, ctiller): Consider replacing this struct with
+ grpc_channel_args. See comment in resolver_result.h for details. */
typedef struct grpc_lb_policy_args {
- grpc_resolved_addresses *addresses;
+ grpc_lb_addresses *addresses;
grpc_client_channel_factory *client_channel_factory;
+ /* Can be used to pass implementation-specific parameters to the LB policy. */
+ grpc_channel_args *additional_args;
} grpc_lb_policy_args;
struct grpc_lb_policy_factory_vtable {
diff --git a/src/core/ext/client_config/resolver_factory.h b/src/core/ext/client_config/resolver_factory.h
index f69bf79564..9ec5b9a70e 100644
--- a/src/core/ext/client_config/resolver_factory.h
+++ b/src/core/ext/client_config/resolver_factory.h
@@ -47,10 +47,7 @@ struct grpc_resolver_factory {
const grpc_resolver_factory_vtable *vtable;
};
-typedef struct grpc_resolver_args {
- grpc_uri *uri;
- grpc_client_channel_factory *client_channel_factory;
-} grpc_resolver_args;
+typedef struct grpc_resolver_args { grpc_uri *uri; } grpc_resolver_args;
struct grpc_resolver_factory_vtable {
void (*ref)(grpc_resolver_factory *factory);
diff --git a/src/core/ext/client_config/resolver_registry.c b/src/core/ext/client_config/resolver_registry.c
index e7a4abd568..b5308a140c 100644
--- a/src/core/ext/client_config/resolver_registry.c
+++ b/src/core/ext/client_config/resolver_registry.c
@@ -128,15 +128,13 @@ static grpc_resolver_factory *resolve_factory(const char *target,
return factory;
}
-grpc_resolver *grpc_resolver_create(
- const char *target, grpc_client_channel_factory *client_channel_factory) {
+grpc_resolver *grpc_resolver_create(const char *target) {
grpc_uri *uri = NULL;
grpc_resolver_factory *factory = resolve_factory(target, &uri);
grpc_resolver *resolver;
grpc_resolver_args args;
memset(&args, 0, sizeof(args));
args.uri = uri;
- args.client_channel_factory = client_channel_factory;
resolver = grpc_resolver_factory_create_resolver(factory, &args);
grpc_uri_destroy(uri);
return resolver;
diff --git a/src/core/ext/client_config/resolver_registry.h b/src/core/ext/client_config/resolver_registry.h
index 5ef1383cd3..92e248d548 100644
--- a/src/core/ext/client_config/resolver_registry.h
+++ b/src/core/ext/client_config/resolver_registry.h
@@ -55,8 +55,7 @@ void grpc_register_resolver_type(grpc_resolver_factory *factory);
If a resolver factory was found, use it to instantiate a resolver and
return it.
If a resolver factory was not found, return NULL. */
-grpc_resolver *grpc_resolver_create(
- const char *target, grpc_client_channel_factory *client_channel_factory);
+grpc_resolver *grpc_resolver_create(const char *target);
/** Find a resolver factory given a name and return an (owned-by-the-caller)
* reference to it */
diff --git a/src/core/ext/client_config/resolver_result.c b/src/core/ext/client_config/resolver_result.c
index c6c4166e83..59c9e7dc25 100644
--- a/src/core/ext/client_config/resolver_result.c
+++ b/src/core/ext/client_config/resolver_result.c
@@ -1,75 +1,87 @@
-/*
- *
- * 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.
- *
- */
+//
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
#include "src/core/ext/client_config/resolver_result.h"
#include <string.h>
#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/channel/channel_args.h"
struct grpc_resolver_result {
gpr_refcount refs;
- grpc_lb_policy *lb_policy;
+ grpc_lb_addresses* addresses;
+ char* lb_policy_name;
+ grpc_channel_args* lb_policy_args;
};
-grpc_resolver_result *grpc_resolver_result_create() {
- grpc_resolver_result *c = gpr_malloc(sizeof(*c));
- memset(c, 0, sizeof(*c));
- gpr_ref_init(&c->refs, 1);
- return c;
+grpc_resolver_result* grpc_resolver_result_create(
+ grpc_lb_addresses* addresses, const char* lb_policy_name,
+ grpc_channel_args* lb_policy_args) {
+ grpc_resolver_result* result = gpr_malloc(sizeof(*result));
+ memset(result, 0, sizeof(*result));
+ gpr_ref_init(&result->refs, 1);
+ result->addresses = addresses;
+ result->lb_policy_name = gpr_strdup(lb_policy_name);
+ result->lb_policy_args = lb_policy_args;
+ return result;
}
-void grpc_resolver_result_ref(grpc_resolver_result *c) { gpr_ref(&c->refs); }
+void grpc_resolver_result_ref(grpc_resolver_result* result) {
+ gpr_ref(&result->refs);
+}
-void grpc_resolver_result_unref(grpc_exec_ctx *exec_ctx,
- grpc_resolver_result *c) {
- if (gpr_unref(&c->refs)) {
- if (c->lb_policy != NULL) {
- GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "resolver_result");
- }
- gpr_free(c);
+void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx,
+ grpc_resolver_result* result) {
+ if (gpr_unref(&result->refs)) {
+ grpc_lb_addresses_destroy(result->addresses, NULL /* user_data_destroy */);
+ gpr_free(result->lb_policy_name);
+ grpc_channel_args_destroy(result->lb_policy_args);
+ gpr_free(result);
}
}
-void grpc_resolver_result_set_lb_policy(grpc_resolver_result *c,
- grpc_lb_policy *lb_policy) {
- GPR_ASSERT(c->lb_policy == NULL);
- if (lb_policy) {
- GRPC_LB_POLICY_REF(lb_policy, "resolver_result");
- }
- c->lb_policy = lb_policy;
+grpc_lb_addresses* grpc_resolver_result_get_addresses(
+ grpc_resolver_result* result) {
+ return result->addresses;
+}
+
+const char* grpc_resolver_result_get_lb_policy_name(
+ grpc_resolver_result* result) {
+ return result->lb_policy_name;
}
-grpc_lb_policy *grpc_resolver_result_get_lb_policy(grpc_resolver_result *c) {
- return c->lb_policy;
+grpc_channel_args* grpc_resolver_result_get_lb_policy_args(
+ grpc_resolver_result* result) {
+ return result->lb_policy_args;
}
diff --git a/src/core/ext/client_config/resolver_result.h b/src/core/ext/client_config/resolver_result.h
index 402f7dbd7e..d4118b90e8 100644
--- a/src/core/ext/client_config/resolver_result.h
+++ b/src/core/ext/client_config/resolver_result.h
@@ -1,52 +1,71 @@
-/*
- *
- * 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.
- *
- */
+//
+// 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.
+//
#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H
#define GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H
-#include "src/core/ext/client_config/lb_policy.h"
+#include "src/core/ext/client_config/lb_policy_factory.h"
+#include "src/core/lib/iomgr/resolve_address.h"
-/** Results reported from a grpc_resolver. */
+// TODO(roth, ctiller): In the long term, we are considering replacing
+// the resolver_result data structure with grpc_channel_args. The idea is
+// that the resolver will return a set of channel args that contains the
+// information that is currently in the resolver_result struct. For
+// example, there will be specific args indicating the set of addresses
+// and the name of the LB policy to instantiate. Note that if we did
+// this, we would probably want to change the data structure of
+// grpc_channel_args such to a hash table or AVL or some other data
+// structure that does not require linear search to find keys.
+
+/// Results reported from a grpc_resolver.
typedef struct grpc_resolver_result grpc_resolver_result;
-grpc_resolver_result *grpc_resolver_result_create();
-void grpc_resolver_result_ref(grpc_resolver_result *client_config);
-void grpc_resolver_result_unref(grpc_exec_ctx *exec_ctx,
- grpc_resolver_result *client_config);
+/// Takes ownership of \a addresses and \a lb_policy_args.
+grpc_resolver_result* grpc_resolver_result_create(
+ grpc_lb_addresses* addresses, const char* lb_policy_name,
+ grpc_channel_args* lb_policy_args);
+void grpc_resolver_result_ref(grpc_resolver_result* result);
+void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx,
+ grpc_resolver_result* result);
+
+/// Caller does NOT take ownership of result.
+grpc_lb_addresses* grpc_resolver_result_get_addresses(
+ grpc_resolver_result* result);
+
+/// Caller does NOT take ownership of result.
+const char* grpc_resolver_result_get_lb_policy_name(
+ grpc_resolver_result* result);
-void grpc_resolver_result_set_lb_policy(grpc_resolver_result *client_config,
- grpc_lb_policy *lb_policy);
-grpc_lb_policy *grpc_resolver_result_get_lb_policy(
- grpc_resolver_result *client_config);
+/// Caller does NOT take ownership of result.
+grpc_channel_args* grpc_resolver_result_get_lb_policy_args(
+ grpc_resolver_result* result);
#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H */
diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c
index df35904b85..96595a38dd 100644
--- a/src/core/ext/client_config/subchannel.c
+++ b/src/core/ext/client_config/subchannel.c
@@ -33,6 +33,7 @@
#include "src/core/ext/client_config/subchannel.h"
+#include <limits.h>
#include <string.h>
#include <grpc/support/alloc.h>
@@ -219,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%08x -> 0x%08x [%s]", c, purpose, old_val,
- 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;
}
@@ -347,21 +348,16 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
}
if (0 ==
strcmp(c->args->args[i].key, GRPC_ARG_MAX_RECONNECT_BACKOFF_MS)) {
- if (c->args->args[i].type == GRPC_ARG_INTEGER) {
- if (c->args->args[i].value.integer >= 0) {
- gpr_backoff_init(
- &c->backoff_state, GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER,
- GRPC_SUBCHANNEL_RECONNECT_JITTER,
- GPR_MIN(c->args->args[i].value.integer,
- GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS * 1000),
- c->args->args[i].value.integer);
- } else {
- gpr_log(GPR_ERROR, GRPC_ARG_MAX_RECONNECT_BACKOFF_MS
- " : must be non-negative");
- }
- } else {
- gpr_log(GPR_ERROR,
- GRPC_ARG_MAX_RECONNECT_BACKOFF_MS " : must be an integer");
+ const grpc_integer_options options = {-1, 0, INT_MAX};
+ const int value =
+ grpc_channel_arg_get_integer(&c->args->args[i], options);
+ if (value >= 0) {
+ gpr_backoff_init(
+ &c->backoff_state, GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER,
+ GRPC_SUBCHANNEL_RECONNECT_JITTER,
+ GPR_MIN(value,
+ GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS * 1000),
+ value);
}
}
}
@@ -504,14 +500,13 @@ static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *interested_parties,
grpc_connectivity_state *state,
grpc_closure *closure) {
- grpc_transport_op op;
+ grpc_transport_op *op = grpc_make_transport_op(NULL);
grpc_channel_element *elem;
- memset(&op, 0, sizeof(op));
- op.connectivity_state = state;
- op.on_connectivity_state_change = closure;
- op.bind_pollset_set = interested_parties;
+ op->connectivity_state = state;
+ op->on_connectivity_state_change = closure;
+ op->bind_pollset_set = interested_parties;
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
- elem->filter->start_transport_op(exec_ctx, elem, &op);
+ elem->filter->start_transport_op(exec_ctx, elem, op);
}
void grpc_connected_subchannel_notify_on_state_change(
@@ -525,12 +520,11 @@ void grpc_connected_subchannel_notify_on_state_change(
void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx,
grpc_connected_subchannel *con,
grpc_closure *closure) {
- grpc_transport_op op;
+ grpc_transport_op *op = grpc_make_transport_op(NULL);
grpc_channel_element *elem;
- memset(&op, 0, sizeof(op));
- op.send_ping = closure;
+ op->send_ping = closure;
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
- elem->filter->start_transport_op(exec_ctx, elem, &op);
+ elem->filter->start_transport_op(exec_ctx, elem, op);
}
static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
index af913d8a9d..36db8ab00d 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -76,9 +76,9 @@
* operations in progress over the old RR instance. This is done by
* decreasing the reference count on the old policy. The moment no more
* references are held on the old RR policy, it'll be destroyed and \a
- * 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().
+ * 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().
*
*
* Once a RR policy instance is in place (and getting updated as described),
@@ -96,6 +96,8 @@
* - Implement LB service forwarding (point 2c. in the doc's diagram).
*/
+#include <errno.h>
+
#include <string.h>
#include <grpc/byte_buffer_reader.h>
@@ -105,22 +107,50 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/client_config/client_channel_factory.h"
+#include "src/core/ext/client_config/lb_policy_factory.h"
#include "src/core/ext/client_config/lb_policy_registry.h"
#include "src/core/ext/client_config/parse_address.h"
#include "src/core/ext/lb_policy/grpclb/grpclb.h"
#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/static_metadata.h"
int grpc_lb_glb_trace = 0;
+/* add lb_token of selected subchannel (address) to the call's initial
+ * metadata */
+static void initial_metadata_add_lb_token(
+ grpc_metadata_batch *initial_metadata,
+ grpc_linked_mdelem *lb_token_mdelem_storage, grpc_mdelem *lb_token) {
+ GPR_ASSERT(lb_token_mdelem_storage != NULL);
+ GPR_ASSERT(lb_token != NULL);
+ grpc_metadata_batch_add_tail(initial_metadata, lb_token_mdelem_storage,
+ lb_token);
+}
+
typedef struct wrapped_rr_closure_arg {
/* the original closure. Usually a on_complete/notify cb for pick() and ping()
* calls against the internal RR instance, respectively. */
grpc_closure *wrapped_closure;
+ /* the pick's initial metadata, kept in order to append the LB token for the
+ * pick */
+ grpc_metadata_batch *initial_metadata;
+
+ /* the picked target, used to determine which LB token to add to the pick's
+ * initial metadata */
+ grpc_connected_subchannel **target;
+
+ /* the LB token associated with the pick */
+ grpc_mdelem *lb_token;
+
+ /* storage for the lb token initial metadata mdelem */
+ grpc_linked_mdelem *lb_token_mdelem_storage;
+
/* The RR instance related to the closure */
grpc_lb_policy *rr_policy;
@@ -141,9 +171,20 @@ static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg,
(intptr_t)wc_arg->rr_policy);
}
GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "wrapped_rr_closure");
+
+ /* if target is NULL, no pick has been made by the RR policy (eg, all
+ * addresses failed to connect). There won't be any user_data/token
+ * available */
+ if (wc_arg->target != NULL) {
+ initial_metadata_add_lb_token(wc_arg->initial_metadata,
+ wc_arg->lb_token_mdelem_storage,
+ GRPC_MDELEM_REF(wc_arg->lb_token));
+ }
}
GPR_ASSERT(wc_arg->wrapped_closure != NULL);
- grpc_exec_ctx_sched(exec_ctx, wc_arg->wrapped_closure, error, NULL);
+
+ grpc_exec_ctx_sched(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_REF(error),
+ NULL);
gpr_free(wc_arg->owning_pending_node);
}
@@ -164,6 +205,9 @@ typedef struct pending_pick {
/* the initial metadata for the pick. See grpc_lb_policy_pick() */
grpc_metadata_batch *initial_metadata;
+ /* storage for the lb token initial metadata mdelem */
+ grpc_linked_mdelem *lb_token_mdelem_storage;
+
/* bitmask passed to pick() and used for selective cancelling. See
* grpc_lb_policy_cancel_picks() */
uint32_t initial_metadata_flags;
@@ -180,20 +224,24 @@ typedef struct pending_pick {
wrapped_rr_closure_arg wrapped_on_complete_arg;
} pending_pick;
-static void add_pending_pick(pending_pick **root, grpc_polling_entity *pollent,
- grpc_metadata_batch *initial_metadata,
- uint32_t initial_metadata_flags,
+static void add_pending_pick(pending_pick **root,
+ const grpc_lb_policy_pick_args *pick_args,
grpc_connected_subchannel **target,
grpc_closure *on_complete) {
pending_pick *pp = gpr_malloc(sizeof(*pp));
memset(pp, 0, sizeof(pending_pick));
memset(&pp->wrapped_on_complete_arg, 0, sizeof(wrapped_rr_closure_arg));
pp->next = *root;
- pp->pollent = pollent;
+ pp->pollent = pick_args->pollent;
pp->target = target;
- pp->initial_metadata = initial_metadata;
- pp->initial_metadata_flags = initial_metadata_flags;
+ pp->initial_metadata = pick_args->initial_metadata;
+ pp->initial_metadata_flags = pick_args->initial_metadata_flags;
+ pp->lb_token_mdelem_storage = pick_args->lb_token_mdelem_storage;
pp->wrapped_on_complete_arg.wrapped_closure = on_complete;
+ pp->wrapped_on_complete_arg.target = target;
+ 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);
*root = pp;
@@ -252,6 +300,9 @@ typedef struct glb_lb_policy {
* response has arrived. */
grpc_grpclb_serverlist *serverlist;
+ /** addresses from \a serverlist */
+ grpc_lb_addresses *addresses;
+
/** list of picks that are waiting on RR's policy connectivity */
pending_pick *pending_picks;
@@ -279,58 +330,132 @@ struct rr_connectivity_data {
glb_lb_policy *glb_policy;
};
-static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx,
- const grpc_grpclb_serverlist *serverlist,
- glb_lb_policy *glb_policy) {
- /* TODO(dgq): support mixed ip version */
- GPR_ASSERT(serverlist != NULL && serverlist->num_servers > 0);
- char **host_ports = gpr_malloc(sizeof(char *) * serverlist->num_servers);
- for (size_t i = 0; i < serverlist->num_servers; ++i) {
- gpr_join_host_port(&host_ports[i], serverlist->servers[i]->ip_address,
- serverlist->servers[i]->port);
+static bool is_server_valid(const grpc_grpclb_server *server, size_t idx,
+ bool log) {
+ const grpc_grpclb_ip_address *ip = &server->ip_address;
+ if (server->port >> 16 != 0) {
+ if (log) {
+ gpr_log(GPR_ERROR,
+ "Invalid port '%d' at index %zu of serverlist. Ignoring.",
+ server->port, idx);
+ }
+ return false;
}
- size_t uri_path_len;
- char *concat_ipports = gpr_strjoin_sep(
- (const char **)host_ports, serverlist->num_servers, ",", &uri_path_len);
+ if (ip->size != 4 && ip->size != 16) {
+ if (log) {
+ gpr_log(GPR_ERROR,
+ "Expected IP to be 4 or 16 bytes, got %d at index %zu of "
+ "serverlist. Ignoring",
+ ip->size, idx);
+ }
+ return false;
+ }
+ return true;
+}
- grpc_lb_policy_args args;
- args.client_channel_factory = glb_policy->cc_factory;
- args.addresses = gpr_malloc(sizeof(grpc_resolved_addresses));
- args.addresses->naddrs = serverlist->num_servers;
- args.addresses->addrs =
- gpr_malloc(sizeof(grpc_resolved_address) * args.addresses->naddrs);
- size_t out_addrs_idx = 0;
+/* Returns addresses extracted from \a serverlist. */
+static grpc_lb_addresses *process_serverlist(
+ const grpc_grpclb_serverlist *serverlist) {
+ size_t num_valid = 0;
+ /* first pass: count how many are valid in order to allocate the necessary
+ * memory in a single block */
for (size_t i = 0; i < serverlist->num_servers; ++i) {
- grpc_uri uri;
- struct sockaddr_storage sa;
- size_t sa_len;
- uri.path = host_ports[i];
- if (parse_ipv4(&uri, &sa, &sa_len)) { /* TODO(dgq): add support for ipv6 */
- memcpy(args.addresses->addrs[out_addrs_idx].addr, &sa, sa_len);
- args.addresses->addrs[out_addrs_idx].len = sa_len;
- ++out_addrs_idx;
+ if (is_server_valid(serverlist->servers[i], i, true)) ++num_valid;
+ }
+ if (num_valid == 0) return NULL;
+
+ grpc_lb_addresses *lb_addresses = grpc_lb_addresses_create(num_valid);
+
+ /* second pass: actually populate the addresses and LB tokens (aka user data
+ * to the outside world) to be read by the RR policy during its creation.
+ * Given that the validity tests are very cheap, they are performed again
+ * instead of marking the valid ones during the first pass, as this would
+ * incurr in an allocation due to the arbitrary number of server */
+ size_t addr_idx = 0;
+ for (size_t sl_idx = 0; sl_idx < serverlist->num_servers; ++sl_idx) {
+ GPR_ASSERT(addr_idx < num_valid);
+ const grpc_grpclb_server *server = serverlist->servers[sl_idx];
+ if (!is_server_valid(serverlist->servers[sl_idx], sl_idx, false)) continue;
+
+ /* address processing */
+ const uint16_t netorder_port = htons((uint16_t)server->port);
+ /* the addresses are given in binary format (a in(6)_addr struct) in
+ * server->ip_address.bytes. */
+ const grpc_grpclb_ip_address *ip = &server->ip_address;
+ grpc_resolved_address addr;
+ memset(&addr, 0, sizeof(addr));
+ if (ip->size == 4) {
+ addr.len = sizeof(struct sockaddr_in);
+ struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr;
+ addr4->sin_family = AF_INET;
+ memcpy(&addr4->sin_addr, ip->bytes, ip->size);
+ addr4->sin_port = netorder_port;
+ } else if (ip->size == 16) {
+ addr.len = sizeof(struct sockaddr_in6);
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr;
+ addr6->sin6_family = AF_INET;
+ memcpy(&addr6->sin6_addr, ip->bytes, ip->size);
+ addr6->sin6_port = netorder_port;
+ }
+
+ /* lb token processing */
+ void *user_data;
+ if (server->has_load_balance_token) {
+ const size_t lb_token_size =
+ 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);
} else {
- gpr_log(GPR_ERROR, "Invalid LB service address '%s', ignoring.",
- host_ports[i]);
+ 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;
}
+
+ grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len,
+ false /* is_balancer */,
+ NULL /* balancer_name */, user_data);
+ ++addr_idx;
}
+ GPR_ASSERT(addr_idx == num_valid);
+
+ return lb_addresses;
+}
+
+/* A plugin for grpc_lb_addresses_destroy that unrefs the LB token metadata. */
+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) {
+ GPR_ASSERT(serverlist != NULL && serverlist->num_servers > 0);
+
+ grpc_lb_policy_args args;
+ memset(&args, 0, sizeof(args));
+ args.client_channel_factory = glb_policy->cc_factory;
+ args.addresses = process_serverlist(serverlist);
grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args);
- gpr_free(concat_ipports);
- for (size_t i = 0; i < serverlist->num_servers; i++) {
- gpr_free(host_ports[i]);
+ if (glb_policy->addresses != NULL) {
+ /* dispose of the previous version */
+ grpc_lb_addresses_destroy(glb_policy->addresses, lb_token_destroy);
}
- gpr_free(host_ports);
- gpr_free(args.addresses->addrs);
- gpr_free(args.addresses);
+ glb_policy->addresses = args.addresses;
+
return rr;
}
static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
grpc_error *error) {
- GRPC_ERROR_REF(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);
@@ -345,8 +470,8 @@ static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
exec_ctx, glb_policy->rr_policy, &glb_policy->rr_connectivity->state,
&glb_policy->rr_connectivity->on_change);
grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker,
- glb_policy->rr_connectivity->state, error,
- "rr_handover");
+ glb_policy->rr_connectivity->state,
+ GRPC_ERROR_REF(error), "rr_handover");
grpc_lb_policy_exit_idle(exec_ctx, glb_policy->rr_policy);
/* flush pending ops */
@@ -359,9 +484,12 @@ 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->pollent,
- pp->initial_metadata, pp->initial_metadata_flags,
- pp->target, &pp->wrapped_on_complete);
+ const grpc_lb_policy_pick_args pick_args = {
+ pp->pollent, pp->initial_metadata, pp->initial_metadata_flags,
+ pp->lb_token_mdelem_storage};
+ grpc_lb_policy_pick(exec_ctx, glb_policy->rr_policy, &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;
}
@@ -378,13 +506,13 @@ static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
&pping->wrapped_notify);
pping->wrapped_notify_arg.owning_pending_node = pping;
}
- GRPC_ERROR_UNREF(error);
}
-static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_error *error) {
+static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
rr_connectivity_data *rr_conn_data = arg;
glb_lb_policy *glb_policy = rr_conn_data->glb_policy;
+
if (rr_conn_data->state == GRPC_CHANNEL_SHUTDOWN) {
if (glb_policy->serverlist != NULL) {
/* a RR policy is shutting down but there's a serverlist available ->
@@ -398,8 +526,8 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
if (error == GRPC_ERROR_NONE) {
/* RR not shutting down. Mimic the RR's policy state */
grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker,
- rr_conn_data->state, error,
- "rr_connectivity_changed");
+ rr_conn_data->state, GRPC_ERROR_REF(error),
+ "glb_rr_connectivity_changed");
/* resubscribe */
grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy,
&rr_conn_data->state,
@@ -408,41 +536,63 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
gpr_free(rr_conn_data);
}
}
- GRPC_ERROR_UNREF(error);
}
static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
grpc_lb_policy_factory *factory,
grpc_lb_policy_args *args) {
+ /* Count the number of gRPC-LB addresses. There must be at least one.
+ * TODO(roth): For now, we ignore non-balancer addresses, but in the
+ * future, we may change the behavior such that we fall back to using
+ * the non-balancer addresses if we cannot reach any balancers. At that
+ * time, this should be changed to allow a list with no balancer addresses,
+ * since the resolver might fail to return a balancer address even when
+ * this is the right LB policy to use. */
+ size_t num_grpclb_addrs = 0;
+ for (size_t i = 0; i < args->addresses->num_addresses; ++i) {
+ if (args->addresses->addresses[i].is_balancer) ++num_grpclb_addrs;
+ }
+ if (num_grpclb_addrs == 0) return NULL;
+
glb_lb_policy *glb_policy = gpr_malloc(sizeof(*glb_policy));
memset(glb_policy, 0, sizeof(*glb_policy));
/* All input addresses in args->addresses come from a resolver that claims
- * they are LB services. It's the resolver's responsibility to make sure this
+ * they are LB services. It's the resolver's responsibility to make sure
+ * this
* policy is only instantiated and used in that case.
*
* Create a client channel over them to communicate with a LB service */
glb_policy->cc_factory = args->client_channel_factory;
GPR_ASSERT(glb_policy->cc_factory != NULL);
- if (args->addresses->naddrs == 0) {
- return NULL;
- }
- /* construct a target from the args->addresses, in the form
+ /* construct a target from the addresses in args, given in the form
* ipvX://ip1:port1,ip2:port2,...
* TODO(dgq): support mixed ip version */
- char **addr_strs = gpr_malloc(sizeof(char *) * args->addresses->naddrs);
- addr_strs[0] =
- grpc_sockaddr_to_uri((const struct sockaddr *)&args->addresses->addrs[0]);
- for (size_t i = 1; i < args->addresses->naddrs; i++) {
- GPR_ASSERT(grpc_sockaddr_to_string(
- &addr_strs[i],
- (const struct sockaddr *)&args->addresses->addrs[i],
- true) == 0);
+ char **addr_strs = gpr_malloc(sizeof(char *) * num_grpclb_addrs);
+ size_t addr_index = 0;
+ for (size_t i = 0; i < args->addresses->num_addresses; i++) {
+ if (args->addresses->addresses[i].user_data != NULL) {
+ gpr_log(GPR_ERROR,
+ "This LB policy doesn't support user data. It will be ignored");
+ }
+ if (args->addresses->addresses[i].is_balancer) {
+ if (addr_index == 0) {
+ addr_strs[addr_index++] = grpc_sockaddr_to_uri(
+ (const struct sockaddr *)&args->addresses->addresses[i]
+ .address.addr);
+ } else {
+ GPR_ASSERT(grpc_sockaddr_to_string(
+ &addr_strs[addr_index++],
+ (const struct sockaddr *)&args->addresses->addresses[i]
+ .address.addr,
+ true) == 0);
+ }
+ }
}
size_t uri_path_len;
- char *target_uri_str = gpr_strjoin_sep(
- (const char **)addr_strs, args->addresses->naddrs, ",", &uri_path_len);
+ char *target_uri_str = gpr_strjoin_sep((const char **)addr_strs,
+ num_grpclb_addrs, ",", &uri_path_len);
/* will pick using pick_first */
glb_policy->lb_channel = grpc_client_channel_factory_create_channel(
@@ -450,7 +600,7 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, NULL);
gpr_free(target_uri_str);
- for (size_t i = 0; i < args->addresses->naddrs; i++) {
+ for (size_t i = 0; i < num_grpclb_addrs; i++) {
gpr_free(addr_strs[i]);
}
gpr_free(addr_strs);
@@ -463,7 +613,7 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
rr_connectivity_data *rr_connectivity =
gpr_malloc(sizeof(rr_connectivity_data));
memset(rr_connectivity, 0, sizeof(rr_connectivity_data));
- grpc_closure_init(&rr_connectivity->on_change, rr_connectivity_changed,
+ grpc_closure_init(&rr_connectivity->on_change, glb_rr_connectivity_changed,
rr_connectivity);
rr_connectivity->glb_policy = glb_policy;
glb_policy->rr_connectivity = rr_connectivity;
@@ -486,6 +636,7 @@ static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
grpc_grpclb_destroy_serverlist(glb_policy->serverlist);
}
gpr_mu_destroy(&glb_policy->mu);
+ grpc_lb_addresses_destroy(glb_policy->addresses, lb_token_destroy);
gpr_free(glb_policy);
}
@@ -546,7 +697,6 @@ static void glb_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
*target = NULL;
grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete,
GRPC_ERROR_CANCELLED, NULL);
- gpr_free(pp);
} else {
pp->next = glb_policy->pending_picks;
glb_policy->pending_picks = pp;
@@ -576,7 +726,6 @@ static void glb_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
exec_ctx, pp->pollent, glb_policy->base.interested_parties);
grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete,
GRPC_ERROR_CANCELLED, NULL);
- gpr_free(pp);
} else {
pp->next = glb_policy->pending_picks;
glb_policy->pending_picks = pp;
@@ -603,12 +752,21 @@ static void glb_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
- grpc_polling_entity *pollent,
- grpc_metadata_batch *initial_metadata,
- uint32_t initial_metadata_flags,
- grpc_connected_subchannel **target,
+ const grpc_lb_policy_pick_args *pick_args,
+ grpc_connected_subchannel **target, void **user_data,
grpc_closure *on_complete) {
glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+
+ if (pick_args->lb_token_mdelem_storage == NULL) {
+ *target = NULL;
+ grpc_exec_ctx_sched(
+ exec_ctx, on_complete,
+ GRPC_ERROR_CREATE("No mdelem storage for the LB token. Load reporting "
+ "won't work without it. Failing"),
+ NULL);
+ return 1;
+ }
+
gpr_mu_lock(&glb_policy->mu);
int r;
@@ -620,29 +778,36 @@ static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
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);
- r = grpc_lb_policy_pick(exec_ctx, glb_policy->rr_policy, pollent,
- initial_metadata, initial_metadata_flags, target,
+
+ r = 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 (r != 0) {
- /* the call to grpc_lb_policy_pick has been sychronous. Unreffing the RR
- * policy and notify the original callback */
- glb_policy->wc_arg.wrapped_closure = NULL;
+ /* 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");
- grpc_exec_ctx_sched(exec_ctx, glb_policy->wc_arg.wrapped_closure,
- GRPC_ERROR_NONE, NULL);
+
+ /* 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));
}
} else {
- grpc_polling_entity_add_to_pollset_set(exec_ctx, pollent,
+ grpc_polling_entity_add_to_pollset_set(exec_ctx, pick_args->pollent,
glb_policy->base.interested_parties);
- add_pending_pick(&glb_policy->pending_picks, pollent, initial_metadata,
- initial_metadata_flags, target, on_complete);
+ add_pending_pick(&glb_policy->pending_picks, pick_args, target,
+ on_complete);
if (!glb_policy->started_picking) {
start_picking(exec_ctx, glb_policy);
@@ -702,9 +867,6 @@ typedef struct lb_client_data {
/* called once initial metadata's been sent */
grpc_closure md_sent;
- /* called once initial metadata's been received */
- grpc_closure md_rcvd;
-
/* called once the LoadBalanceRequest has been sent to the LB server. See
* src/proto/grpc/.../load_balancer.proto */
grpc_closure req_sent;
@@ -741,7 +903,6 @@ typedef struct lb_client_data {
} lb_client_data;
static void md_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
-static void md_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
static void close_sent_cb(grpc_exec_ctx *exec_ctx, void *arg,
@@ -756,7 +917,6 @@ static lb_client_data *lb_client_data_create(glb_lb_policy *glb_policy) {
gpr_mu_init(&lb_client->mu);
grpc_closure_init(&lb_client->md_sent, md_sent_cb, lb_client);
- grpc_closure_init(&lb_client->md_rcvd, md_recv_cb, lb_client);
grpc_closure_init(&lb_client->req_sent, req_sent_cb, lb_client);
grpc_closure_init(&lb_client->res_rcvd, res_recv_cb, lb_client);
grpc_closure_init(&lb_client->close_sent, close_sent_cb, lb_client);
@@ -855,23 +1015,6 @@ static void md_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_op ops[1];
memset(ops, 0, sizeof(ops));
grpc_op *op = ops;
- op->op = GRPC_OP_RECV_INITIAL_METADATA;
- op->data.recv_initial_metadata = &lb_client->initial_metadata_recv;
- op->flags = 0;
- op->reserved = NULL;
- op++;
- grpc_call_error call_error = grpc_call_start_batch_and_execute(
- exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
- &lb_client->md_rcvd);
- GPR_ASSERT(GRPC_CALL_OK == call_error);
-}
-
-static void md_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
- lb_client_data *lb_client = arg;
- GPR_ASSERT(lb_client->lb_call);
- grpc_op ops[1];
- memset(ops, 0, sizeof(ops));
- grpc_op *op = ops;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message = lb_client->request_payload;
@@ -886,11 +1029,18 @@ static void md_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
lb_client_data *lb_client = arg;
+ GPR_ASSERT(lb_client->lb_call);
- grpc_op ops[1];
+ grpc_op ops[2];
memset(ops, 0, sizeof(ops));
grpc_op *op = ops;
+ op->op = GRPC_OP_RECV_INITIAL_METADATA;
+ op->data.recv_initial_metadata = &lb_client->initial_metadata_recv;
+ op->flags = 0;
+ op->reserved = NULL;
+ op++;
+
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message = &lb_client->response_payload;
op->flags = 0;
@@ -909,8 +1059,7 @@ static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_op *op = ops;
if (lb_client->response_payload != NULL) {
/* Received data from the LB server. Look inside
- * lb_client->response_payload, for
- * a serverlist. */
+ * lb_client->response_payload, for a serverlist. */
grpc_byte_buffer_reader bbr;
grpc_byte_buffer_reader_init(&bbr, lb_client->response_payload);
gpr_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
@@ -947,7 +1096,7 @@ static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
} else {
/* unref the RR policy, eventually leading to its substitution with a
* new one constructed from the received serverlist (see
- * rr_connectivity_changed) */
+ * glb_rr_connectivity_changed) */
GRPC_LB_POLICY_UNREF(exec_ctx, lb_client->glb_policy->rr_policy,
"serverlist_received");
}
@@ -1010,8 +1159,8 @@ static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg,
lb_client->status, lb_client->status_details,
lb_client->status_details_capacity);
}
- /* TODO(dgq): deal with stream termination properly (fire up another one? fail
- * the original call?) */
+ /* TODO(dgq): deal with stream termination properly (fire up another one?
+ * fail the original call?) */
}
/* Code wiring the policy with the rest of the core */
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.c b/src/core/ext/lb_policy/grpclb/load_balancer_api.c
index f4720a1345..a8881004a0 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.c
+++ b/src/core/ext/lb_policy/grpclb/load_balancer_api.c
@@ -57,6 +57,7 @@ static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field,
if (dec_arg->first_pass) { /* count how many server do we have */
grpc_grpclb_server server;
if (!pb_decode(stream, grpc_lb_v1_Server_fields, &server)) {
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream));
return false;
}
dec_arg->num_servers++;
@@ -69,6 +70,7 @@ static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field,
gpr_malloc(sizeof(grpc_grpclb_server *) * dec_arg->num_servers);
}
if (!pb_decode(stream, grpc_lb_v1_Server_fields, server)) {
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(stream));
return false;
}
dec_arg->servers[dec_arg->decoding_idx++] = server;
@@ -118,6 +120,7 @@ grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse(
grpc_grpclb_response res;
memset(&res, 0, sizeof(grpc_grpclb_response));
if (!pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res)) {
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
return NULL;
}
grpc_grpclb_initial_response *initial_res =
@@ -145,6 +148,7 @@ grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
arg.first_pass = true;
status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res);
if (!status) {
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
return NULL;
}
@@ -152,6 +156,7 @@ grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
status =
pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields, &res);
if (!status) {
+ gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
return NULL;
}
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/lb_policy/grpclb/load_balancer_api.h
index 9726c87a37..c1e73d08ef 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.h
+++ b/src/core/ext/lb_policy/grpclb/load_balancer_api.h
@@ -45,6 +45,7 @@ extern "C" {
#define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128
+typedef grpc_lb_v1_Server_ip_address_t grpc_grpclb_ip_address;
typedef grpc_lb_v1_LoadBalanceRequest grpc_grpclb_request;
typedef grpc_lb_v1_InitialLoadBalanceResponse grpc_grpclb_initial_response;
typedef grpc_lb_v1_Server grpc_grpclb_server;
diff --git a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c b/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
index 52e11c40bb..afecb716fb 100644
--- a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+++ b/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
@@ -31,10 +31,11 @@
*
*/
/* Automatically generated nanopb constant definitions */
-/* Generated by nanopb-0.3.5-dev */
+/* Generated by nanopb-0.3.7-dev */
#include "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
+/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
@@ -72,8 +73,8 @@ const pb_field_t grpc_lb_v1_LoadBalanceResponse_fields[3] = {
};
const pb_field_t grpc_lb_v1_InitialLoadBalanceResponse_fields[3] = {
- PB_FIELD( 2, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v1_InitialLoadBalanceResponse, load_balancer_delegate, load_balancer_delegate, 0),
- PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval, load_balancer_delegate, &grpc_lb_v1_Duration_fields),
+ PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v1_InitialLoadBalanceResponse, load_balancer_delegate, load_balancer_delegate, 0),
+ PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, grpc_lb_v1_InitialLoadBalanceResponse, client_stats_report_interval, load_balancer_delegate, &grpc_lb_v1_Duration_fields),
PB_LAST_FIELD
};
@@ -84,7 +85,7 @@ const pb_field_t grpc_lb_v1_ServerList_fields[3] = {
};
const pb_field_t grpc_lb_v1_Server_fields[5] = {
- PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, grpc_lb_v1_Server, ip_address, ip_address, 0),
+ PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, grpc_lb_v1_Server, ip_address, ip_address, 0),
PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, port, ip_address, 0),
PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, load_balance_token, port, 0),
PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, grpc_lb_v1_Server, drop_request, load_balance_token, 0),
@@ -116,3 +117,4 @@ PB_STATIC_ASSERT((pb_membersize(grpc_lb_v1_LoadBalanceRequest, initial_request)
#endif
+/* @@protoc_insertion_point(eof) */
diff --git a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h b/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
index 46fe588f72..53fed22bae 100644
--- a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
+++ b/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
@@ -31,11 +31,12 @@
*
*/
/* Automatically generated nanopb header */
-/* Generated by nanopb-0.3.5-dev */
+/* Generated by nanopb-0.3.7-dev */
-#ifndef GRPC_CORE_EXT_LB_POLICY_GRPCLB_PROTO_GRPC_LB_V1_LOAD_BALANCER_PB_H
-#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_PROTO_GRPC_LB_V1_LOAD_BALANCER_PB_H
+#ifndef PB_GRPC_LB_V1_LOAD_BALANCER_PB_H_INCLUDED
+#define PB_GRPC_LB_V1_LOAD_BALANCER_PB_H_INCLUDED
#include "third_party/nanopb/pb.h"
+/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
@@ -52,6 +53,7 @@ typedef struct _grpc_lb_v1_ClientStats {
int64_t client_rpc_errors;
bool has_dropped_requests;
int64_t dropped_requests;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_ClientStats) */
} grpc_lb_v1_ClientStats;
typedef struct _grpc_lb_v1_Duration {
@@ -59,22 +61,26 @@ typedef struct _grpc_lb_v1_Duration {
int64_t seconds;
bool has_nanos;
int32_t nanos;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_Duration) */
} grpc_lb_v1_Duration;
typedef struct _grpc_lb_v1_InitialLoadBalanceRequest {
bool has_name;
char name[128];
+/* @@protoc_insertion_point(struct:grpc_lb_v1_InitialLoadBalanceRequest) */
} grpc_lb_v1_InitialLoadBalanceRequest;
+typedef PB_BYTES_ARRAY_T(16) grpc_lb_v1_Server_ip_address_t;
typedef struct _grpc_lb_v1_Server {
bool has_ip_address;
- char ip_address[46];
+ grpc_lb_v1_Server_ip_address_t ip_address;
bool has_port;
int32_t port;
bool has_load_balance_token;
- char load_balance_token[64];
+ char load_balance_token[65];
bool has_drop_request;
bool drop_request;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_Server) */
} grpc_lb_v1_Server;
typedef struct _grpc_lb_v1_InitialLoadBalanceResponse {
@@ -82,6 +88,7 @@ typedef struct _grpc_lb_v1_InitialLoadBalanceResponse {
char load_balancer_delegate[64];
bool has_client_stats_report_interval;
grpc_lb_v1_Duration client_stats_report_interval;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_InitialLoadBalanceResponse) */
} grpc_lb_v1_InitialLoadBalanceResponse;
typedef struct _grpc_lb_v1_LoadBalanceRequest {
@@ -89,12 +96,14 @@ typedef struct _grpc_lb_v1_LoadBalanceRequest {
grpc_lb_v1_InitialLoadBalanceRequest initial_request;
bool has_client_stats;
grpc_lb_v1_ClientStats client_stats;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_LoadBalanceRequest) */
} grpc_lb_v1_LoadBalanceRequest;
typedef struct _grpc_lb_v1_ServerList {
pb_callback_t servers;
bool has_expiration_interval;
grpc_lb_v1_Duration expiration_interval;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_ServerList) */
} grpc_lb_v1_ServerList;
typedef struct _grpc_lb_v1_LoadBalanceResponse {
@@ -102,6 +111,7 @@ typedef struct _grpc_lb_v1_LoadBalanceResponse {
grpc_lb_v1_InitialLoadBalanceResponse initial_response;
bool has_server_list;
grpc_lb_v1_ServerList server_list;
+/* @@protoc_insertion_point(struct:grpc_lb_v1_LoadBalanceResponse) */
} grpc_lb_v1_LoadBalanceResponse;
/* Default values for struct fields */
@@ -114,7 +124,7 @@ typedef struct _grpc_lb_v1_LoadBalanceResponse {
#define grpc_lb_v1_LoadBalanceResponse_init_default {false, grpc_lb_v1_InitialLoadBalanceResponse_init_default, false, grpc_lb_v1_ServerList_init_default}
#define grpc_lb_v1_InitialLoadBalanceResponse_init_default {false, "", false, grpc_lb_v1_Duration_init_default}
#define grpc_lb_v1_ServerList_init_default {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_default}
-#define grpc_lb_v1_Server_init_default {false, "", false, 0, false, "", false, 0}
+#define grpc_lb_v1_Server_init_default {false, {0, {0}}, false, 0, false, "", false, 0}
#define grpc_lb_v1_Duration_init_zero {false, 0, false, 0}
#define grpc_lb_v1_LoadBalanceRequest_init_zero {false, grpc_lb_v1_InitialLoadBalanceRequest_init_zero, false, grpc_lb_v1_ClientStats_init_zero}
#define grpc_lb_v1_InitialLoadBalanceRequest_init_zero {false, ""}
@@ -122,7 +132,7 @@ typedef struct _grpc_lb_v1_LoadBalanceResponse {
#define grpc_lb_v1_LoadBalanceResponse_init_zero {false, grpc_lb_v1_InitialLoadBalanceResponse_init_zero, false, grpc_lb_v1_ServerList_init_zero}
#define grpc_lb_v1_InitialLoadBalanceResponse_init_zero {false, "", false, grpc_lb_v1_Duration_init_zero}
#define grpc_lb_v1_ServerList_init_zero {{{NULL}, NULL}, false, grpc_lb_v1_Duration_init_zero}
-#define grpc_lb_v1_Server_init_zero {false, "", false, 0, false, "", false, 0}
+#define grpc_lb_v1_Server_init_zero {false, {0, {0}}, false, 0, false, "", false, 0}
/* Field tags (for use in manual encoding/decoding) */
#define grpc_lb_v1_ClientStats_total_requests_tag 1
@@ -135,8 +145,8 @@ typedef struct _grpc_lb_v1_LoadBalanceResponse {
#define grpc_lb_v1_Server_port_tag 2
#define grpc_lb_v1_Server_load_balance_token_tag 3
#define grpc_lb_v1_Server_drop_request_tag 4
-#define grpc_lb_v1_InitialLoadBalanceResponse_load_balancer_delegate_tag 2
-#define grpc_lb_v1_InitialLoadBalanceResponse_client_stats_report_interval_tag 3
+#define grpc_lb_v1_InitialLoadBalanceResponse_load_balancer_delegate_tag 1
+#define grpc_lb_v1_InitialLoadBalanceResponse_client_stats_report_interval_tag 2
#define grpc_lb_v1_LoadBalanceRequest_initial_request_tag 1
#define grpc_lb_v1_LoadBalanceRequest_client_stats_tag 2
#define grpc_lb_v1_ServerList_servers_tag 1
@@ -161,7 +171,8 @@ extern const pb_field_t grpc_lb_v1_Server_fields[5];
#define grpc_lb_v1_ClientStats_size 33
#define grpc_lb_v1_LoadBalanceResponse_size (98 + grpc_lb_v1_ServerList_size)
#define grpc_lb_v1_InitialLoadBalanceResponse_size 90
-#define grpc_lb_v1_Server_size 127
+/* grpc_lb_v1_ServerList_size depends on runtime parameters */
+#define grpc_lb_v1_Server_size 98
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
@@ -174,5 +185,6 @@ extern const pb_field_t grpc_lb_v1_Server_fields[5];
#ifdef __cplusplus
} /* extern "C" */
#endif
+/* @@protoc_insertion_point(eof) */
#endif
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 9decf70692..09df92dd99 100644
--- a/src/core/ext/lb_policy/pick_first/pick_first.c
+++ b/src/core/ext/lb_policy/pick_first/pick_first.c
@@ -199,10 +199,8 @@ static void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
- grpc_polling_entity *pollent,
- grpc_metadata_batch *initial_metadata,
- uint32_t initial_metadata_flags,
- grpc_connected_subchannel **target,
+ const grpc_lb_policy_pick_args *pick_args,
+ grpc_connected_subchannel **target, void **user_data,
grpc_closure *on_complete) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp;
@@ -225,13 +223,13 @@ 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, pollent,
+ 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 = pollent;
+ pp->pollent = pick_args->pollent;
pp->target = target;
- pp->initial_metadata_flags = initial_metadata_flags;
+ pp->initial_metadata_flags = pick_args->initial_metadata_flags;
pp->on_complete = on_complete;
p->pending_picks = pp;
gpr_mu_unlock(&p->mu);
@@ -443,20 +441,34 @@ static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(args->addresses != NULL);
GPR_ASSERT(args->client_channel_factory != NULL);
- if (args->addresses->naddrs == 0) return NULL;
+ /* Find the number of backend addresses. We ignore balancer
+ * addresses, since we don't know how to handle them. */
+ size_t num_addrs = 0;
+ for (size_t i = 0; i < args->addresses->num_addresses; i++) {
+ if (!args->addresses->addresses[i].is_balancer) ++num_addrs;
+ }
+ if (num_addrs == 0) return NULL;
pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
memset(p, 0, sizeof(*p));
- p->subchannels =
- gpr_malloc(sizeof(grpc_subchannel *) * args->addresses->naddrs);
- memset(p->subchannels, 0, sizeof(*p->subchannels) * args->addresses->naddrs);
+ p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * num_addrs);
+ memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs);
grpc_subchannel_args sc_args;
size_t subchannel_idx = 0;
- for (size_t i = 0; i < args->addresses->naddrs; i++) {
+ for (size_t i = 0; i < args->addresses->num_addresses; i++) {
+ /* Skip balancer addresses, since we only know how to handle backends. */
+ if (args->addresses->addresses[i].is_balancer) continue;
+
+ if (args->addresses->addresses[i].user_data != NULL) {
+ gpr_log(GPR_ERROR,
+ "This LB policy doesn't support user data. It will be ignored");
+ }
+
memset(&sc_args, 0, sizeof(grpc_subchannel_args));
- sc_args.addr = (struct sockaddr *)(args->addresses->addrs[i].addr);
- sc_args.addr_len = (size_t)args->addresses->addrs[i].len;
+ sc_args.addr =
+ (struct sockaddr *)(&args->addresses->addresses[i].address.addr);
+ sc_args.addr_len = args->addresses->addresses[i].address.len;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
exec_ctx, args->client_channel_factory, &sc_args);
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c
index 7bcf608ab9..0feb0740a2 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -66,6 +66,7 @@
#include "src/core/ext/client_config/lb_policy_registry.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/transport/static_metadata.h"
typedef struct round_robin_lb_policy round_robin_lb_policy;
@@ -76,15 +77,32 @@ int grpc_lb_round_robin_trace = 0;
* Once a pick is available, \a target is updated and \a on_complete called. */
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). */
+ void **user_data;
+
+ /* bitmask passed to pick() and used for selective cancelling. See
+ * grpc_lb_policy_cancel_picks() */
uint32_t initial_metadata_flags;
+
+ /* output argument where to store the pick()ed connected subchannel, or NULL
+ * upon error. */
grpc_connected_subchannel **target;
+
+ /* to be invoked once the pick() has completed (regardless of success) */
grpc_closure *on_complete;
} pending_pick;
/** List of subchannels in a connectivity READY state */
typedef struct ready_list {
grpc_subchannel *subchannel;
+ /* references namesake entry in subchannel_data */
+ void *user_data;
struct ready_list *next;
struct ready_list *prev;
} ready_list;
@@ -102,12 +120,17 @@ typedef struct {
ready_list *ready_list_node;
/** last observed connectivity */
grpc_connectivity_state connectivity_state;
+ /** the subchannel's target user data */
+ void *user_data;
} subchannel_data;
struct round_robin_lb_policy {
/** base policy: must be first */
grpc_lb_policy base;
+ /** total number of addresses received at creation time */
+ size_t num_addresses;
+
/** all our subchannels */
size_t num_subchannels;
subchannel_data **subchannels;
@@ -166,16 +189,19 @@ static void advance_last_picked_locked(round_robin_lb_policy *p) {
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG, "[READYLIST] ADVANCED LAST PICK. NOW AT NODE %p (SC %p)",
- p->ready_list_last_pick, p->ready_list_last_pick->subchannel);
+ (void *)p->ready_list_last_pick,
+ (void *)p->ready_list_last_pick->subchannel);
}
}
/** Prepends (relative to the root at p->ready_list) the connected subchannel \a
* csc to the list of ready subchannels. */
static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
- grpc_subchannel *sc) {
+ subchannel_data *sd) {
ready_list *new_elem = gpr_malloc(sizeof(ready_list));
- new_elem->subchannel = sc;
+ memset(new_elem, 0, sizeof(ready_list));
+ new_elem->subchannel = sd->subchannel;
+ new_elem->user_data = sd->user_data;
if (p->ready_list.prev == NULL) {
/* first element */
new_elem->next = &p->ready_list;
@@ -189,7 +215,8 @@ static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
p->ready_list.prev = new_elem;
}
if (grpc_lb_round_robin_trace) {
- gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, sc);
+ gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (Conn. SC %p)",
+ (void *)new_elem, (void *)sd->subchannel);
}
return new_elem;
}
@@ -216,8 +243,8 @@ static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
}
if (grpc_lb_round_robin_trace) {
- gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", node,
- node->subchannel);
+ gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", (void *)node,
+ (void *)node->subchannel);
}
node->next = NULL;
@@ -229,9 +256,8 @@ static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
static void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
- size_t i;
ready_list *elem;
- for (i = 0; i < p->num_subchannels; i++) {
+ for (size_t i = 0; i < p->num_subchannels; i++) {
subchannel_data *sd = p->subchannels[i];
GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
gpr_free(sd);
@@ -251,6 +277,7 @@ static void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
gpr_free(elem);
elem = tmp;
}
+
gpr_free(p);
}
@@ -337,7 +364,7 @@ static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
p->started_picking = 1;
if (grpc_lb_round_robin_trace) {
- gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%" PRIuPTR, p,
+ gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%" PRIuPTR, (void *)p,
p->num_subchannels);
}
@@ -361,38 +388,43 @@ static void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
- grpc_polling_entity *pollent,
- grpc_metadata_batch *initial_metadata,
- uint32_t initial_metadata_flags,
- grpc_connected_subchannel **target,
+ const grpc_lb_policy_pick_args *pick_args,
+ grpc_connected_subchannel **target, void **user_data,
grpc_closure *on_complete) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
pending_pick *pp;
ready_list *selected;
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) {
+ *user_data = selected->user_data;
+ }
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG,
- "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)", *target,
- selected);
+ "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)",
+ (void *)*target, (void *)selected);
}
/* only advance the last picked pointer if the selection was used */
advance_last_picked_locked(p);
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, pollent,
+ 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 = pollent;
+ pp->pollent = pick_args->pollent;
pp->target = target;
pp->on_complete = on_complete;
- pp->initial_metadata_flags = initial_metadata_flags;
+ pp->initial_metadata_flags = pick_args->initial_metadata_flags;
+ pp->user_data = user_data;
p->pending_picks = pp;
gpr_mu_unlock(&p->mu);
return 0;
@@ -421,7 +453,7 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
"connecting_ready");
/* add the newly connected subchannel to the list of connected ones.
* Note that it goes to the "end of the line". */
- sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel);
+ sd->ready_list_node = add_connected_sc_locked(p, sd);
/* at this point we know there's at least one suitable subchannel. Go
* ahead and pick one and notify the pending suitors in
* p->pending_picks. This preemtively replicates rr_pick()'s actions. */
@@ -433,12 +465,16 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
}
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
+
*pp->target =
grpc_subchannel_get_connected_subchannel(selected->subchannel);
+ if (pp->user_data != NULL) {
+ *pp->user_data = selected->user_data;
+ }
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG,
"[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
- selected->subchannel, selected);
+ (void *)selected->subchannel, (void *)selected);
}
grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
p->base.interested_parties);
@@ -571,19 +607,31 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(args->addresses != NULL);
GPR_ASSERT(args->client_channel_factory != NULL);
+ /* Find the number of backend addresses. We ignore balancer
+ * addresses, since we don't know how to handle them. */
+ size_t num_addrs = 0;
+ for (size_t i = 0; i < args->addresses->num_addresses; i++) {
+ if (!args->addresses->addresses[i].is_balancer) ++num_addrs;
+ }
+ if (num_addrs == 0) return NULL;
+
round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
memset(p, 0, sizeof(*p));
- p->subchannels =
- gpr_malloc(sizeof(*p->subchannels) * args->addresses->naddrs);
- memset(p->subchannels, 0, sizeof(*p->subchannels) * args->addresses->naddrs);
+ p->num_addresses = num_addrs;
+ p->subchannels = gpr_malloc(sizeof(*p->subchannels) * num_addrs);
+ memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs);
grpc_subchannel_args sc_args;
size_t subchannel_idx = 0;
- for (size_t i = 0; i < args->addresses->naddrs; i++) {
+ for (size_t i = 0; i < args->addresses->num_addresses; i++) {
+ /* Skip balancer addresses, since we only know how to handle backends. */
+ if (args->addresses->addresses[i].is_balancer) continue;
+
memset(&sc_args, 0, sizeof(grpc_subchannel_args));
- sc_args.addr = (struct sockaddr *)(args->addresses->addrs[i].addr);
- sc_args.addr_len = (size_t)args->addresses->addrs[i].len;
+ sc_args.addr =
+ (struct sockaddr *)(&args->addresses->addresses[i].address.addr);
+ sc_args.addr_len = args->addresses->addresses[i].address.len;
grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
exec_ctx, args->client_channel_factory, &sc_args);
@@ -595,12 +643,14 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
sd->policy = p;
sd->index = subchannel_idx;
sd->subchannel = subchannel;
+ sd->user_data = args->addresses->addresses[i].user_data;
++subchannel_idx;
grpc_closure_init(&sd->connectivity_changed_closure,
rr_connectivity_changed, sd);
}
}
if (subchannel_idx == 0) {
+ /* couldn't create any subchannel. Bail out */
gpr_free(p->subchannels);
gpr_free(p);
return NULL;
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c
index 79682e78b5..1b85d2d634 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/resolver/dns/native/dns_resolver.c
@@ -37,7 +37,6 @@
#include <grpc/support/host_port.h>
#include <grpc/support/string_util.h>
-#include "src/core/ext/client_config/lb_policy_registry.h"
#include "src/core/ext/client_config/resolver_registry.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/timer.h"
@@ -58,8 +57,6 @@ typedef struct {
char *name;
/** default port to use */
char *default_port;
- /** subchannel factory */
- grpc_client_channel_factory *client_channel_factory;
/** load balancing policy name */
char *lb_policy_name;
@@ -166,24 +163,20 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
dns_resolver *r = arg;
grpc_resolver_result *result = NULL;
- grpc_lb_policy *lb_policy;
gpr_mu_lock(&r->mu);
GPR_ASSERT(r->resolving);
r->resolving = 0;
- grpc_resolved_addresses *addresses = r->addresses;
- if (addresses != NULL) {
- grpc_lb_policy_args lb_policy_args;
- result = grpc_resolver_result_create();
- memset(&lb_policy_args, 0, sizeof(lb_policy_args));
- lb_policy_args.addresses = addresses;
- lb_policy_args.client_channel_factory = r->client_channel_factory;
- lb_policy =
- grpc_lb_policy_create(exec_ctx, r->lb_policy_name, &lb_policy_args);
- if (lb_policy != NULL) {
- grpc_resolver_result_set_lb_policy(result, lb_policy);
- GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
+ if (r->addresses != NULL) {
+ grpc_lb_addresses *addresses =
+ grpc_lb_addresses_create(r->addresses->naddrs);
+ for (size_t i = 0; i < r->addresses->naddrs; ++i) {
+ grpc_lb_addresses_set_address(
+ addresses, i, &r->addresses->addrs[i].addr,
+ r->addresses->addrs[i].len, false /* is_balancer */,
+ NULL /* balancer_name */, NULL /* user_data */);
}
- grpc_resolved_addresses_destroy(addresses);
+ grpc_resolved_addresses_destroy(r->addresses);
+ result = grpc_resolver_result_create(addresses, r->lb_policy_name, NULL);
} else {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
@@ -244,7 +237,6 @@ static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
if (r->resolved_result) {
grpc_resolver_result_unref(exec_ctx, r->resolved_result);
}
- grpc_client_channel_factory_unref(exec_ctx, r->client_channel_factory);
gpr_free(r->name);
gpr_free(r->default_port);
gpr_free(r->lb_policy_name);
@@ -271,10 +263,8 @@ static grpc_resolver *dns_create(grpc_resolver_args *args,
grpc_resolver_init(&r->base, &dns_resolver_vtable);
r->name = gpr_strdup(path);
r->default_port = gpr_strdup(default_port);
- r->client_channel_factory = args->client_channel_factory;
gpr_backoff_init(&r->backoff_state, BACKOFF_MULTIPLIER, BACKOFF_JITTER,
BACKOFF_MIN_SECONDS * 1000, BACKOFF_MAX_SECONDS * 1000);
- grpc_client_channel_factory_ref(r->client_channel_factory);
r->lb_policy_name = gpr_strdup(lb_policy_name);
return &r->base;
}
diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
index 3807522d2b..ced4fb024c 100644
--- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
@@ -40,7 +40,6 @@
#include <grpc/support/port_platform.h>
#include <grpc/support/string_util.h>
-#include "src/core/ext/client_config/lb_policy_registry.h"
#include "src/core/ext/client_config/parse_address.h"
#include "src/core/ext/client_config/resolver_registry.h"
#include "src/core/lib/iomgr/resolve_address.h"
@@ -52,18 +51,16 @@ typedef struct {
grpc_resolver base;
/** refcount */
gpr_refcount refs;
- /** subchannel factory */
- grpc_client_channel_factory *client_channel_factory;
/** load balancing policy name */
char *lb_policy_name;
/** the addresses that we've 'resolved' */
- grpc_resolved_addresses *addresses;
+ grpc_lb_addresses *addresses;
/** mutex guarding the rest of the state */
gpr_mu mu;
/** have we published? */
- int published;
+ bool published;
/** pending next completion, or NULL */
grpc_closure *next_completion;
/** target result address for next completion */
@@ -102,7 +99,7 @@ static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver) {
sockaddr_resolver *r = (sockaddr_resolver *)resolver;
gpr_mu_lock(&r->mu);
- r->published = 0;
+ r->published = false;
sockaddr_maybe_finish_next_locked(exec_ctx, r);
gpr_mu_unlock(&r->mu);
}
@@ -122,17 +119,10 @@ static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
sockaddr_resolver *r) {
if (r->next_completion != NULL && !r->published) {
- grpc_resolver_result *result = grpc_resolver_result_create();
- grpc_lb_policy_args lb_policy_args;
- memset(&lb_policy_args, 0, sizeof(lb_policy_args));
- lb_policy_args.addresses = r->addresses;
- lb_policy_args.client_channel_factory = r->client_channel_factory;
- grpc_lb_policy *lb_policy =
- grpc_lb_policy_create(exec_ctx, r->lb_policy_name, &lb_policy_args);
- grpc_resolver_result_set_lb_policy(result, lb_policy);
- GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr");
- r->published = 1;
- *r->target_result = result;
+ r->published = true;
+ *r->target_result = grpc_resolver_result_create(
+ grpc_lb_addresses_copy(r->addresses, NULL /* user_data_copy */),
+ r->lb_policy_name, NULL);
grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL;
}
@@ -141,8 +131,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
sockaddr_resolver *r = (sockaddr_resolver *)gr;
gpr_mu_destroy(&r->mu);
- grpc_client_channel_factory_unref(exec_ctx, r->client_channel_factory);
- grpc_resolved_addresses_destroy(r->addresses);
+ grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */);
gpr_free(r->lb_policy_name);
gpr_free(r);
}
@@ -175,7 +164,7 @@ static void do_nothing(void *ignored) {}
static grpc_resolver *sockaddr_create(
grpc_resolver_args *args, const char *default_lb_policy_name,
int parse(grpc_uri *uri, struct sockaddr_storage *dst, size_t *len)) {
- int errors_found = 0; /* GPR_FALSE */
+ bool errors_found = false;
sockaddr_resolver *r;
gpr_slice path_slice;
gpr_slice_buffer path_parts;
@@ -216,21 +205,18 @@ static grpc_resolver *sockaddr_create(
gpr_slice_buffer_init(&path_parts);
gpr_slice_split(path_slice, ",", &path_parts);
- r->addresses = gpr_malloc(sizeof(grpc_resolved_addresses));
- r->addresses->naddrs = path_parts.count;
- r->addresses->addrs =
- gpr_malloc(sizeof(grpc_resolved_address) * r->addresses->naddrs);
-
- for (size_t i = 0; i < r->addresses->naddrs; i++) {
+ r->addresses = grpc_lb_addresses_create(path_parts.count);
+ for (size_t i = 0; i < r->addresses->num_addresses; i++) {
grpc_uri ith_uri = *args->uri;
char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII);
ith_uri.path = part_str;
- if (!parse(&ith_uri,
- (struct sockaddr_storage *)(&r->addresses->addrs[i].addr),
- &r->addresses->addrs[i].len)) {
- errors_found = 1; /* GPR_TRUE */
+ if (!parse(&ith_uri, (struct sockaddr_storage *)(&r->addresses->addresses[i]
+ .address.addr),
+ &r->addresses->addresses[i].address.len)) {
+ errors_found = true;
}
gpr_free(part_str);
+ r->addresses->addresses[i].is_balancer = lb_enabled;
if (errors_found) break;
}
@@ -238,7 +224,7 @@ static grpc_resolver *sockaddr_create(
gpr_slice_unref(path_slice);
if (errors_found) {
gpr_free(r->lb_policy_name);
- grpc_resolved_addresses_destroy(r->addresses);
+ grpc_lb_addresses_destroy(r->addresses, NULL /* user_data_destroy */);
gpr_free(r);
return NULL;
}
@@ -246,8 +232,6 @@ static grpc_resolver *sockaddr_create(
gpr_ref_init(&r->refs, 1);
gpr_mu_init(&r->mu);
grpc_resolver_init(&r->base, &sockaddr_resolver_vtable);
- r->client_channel_factory = args->client_channel_factory;
- grpc_client_channel_factory_ref(r->client_channel_factory);
return &r->base;
}
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create.c b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
index cbaa75a90a..ddc00bd79f 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
@@ -160,7 +160,6 @@ typedef struct {
grpc_client_channel_factory base;
gpr_refcount refs;
grpc_channel_args *merge_args;
- grpc_channel *master;
} client_channel_factory;
static void client_channel_factory_ref(
@@ -173,10 +172,6 @@ static void client_channel_factory_unref(
grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory) {
client_channel_factory *f = (client_channel_factory *)cc_factory;
if (gpr_unref(&f->refs)) {
- if (f->master != NULL) {
- GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master,
- "client_channel_factory");
- }
grpc_channel_args_destroy(f->merge_args);
gpr_free(f);
}
@@ -210,15 +205,15 @@ static grpc_channel *client_channel_factory_create_channel(
grpc_channel *channel = grpc_channel_create(exec_ctx, target, final_args,
GRPC_CLIENT_CHANNEL, NULL);
grpc_channel_args_destroy(final_args);
- grpc_resolver *resolver = grpc_resolver_create(target, &f->base);
+ grpc_resolver *resolver = grpc_resolver_create(target);
if (!resolver) {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
"client_channel_factory_create_channel");
return NULL;
}
- grpc_client_channel_set_resolver(
- exec_ctx, grpc_channel_get_channel_stack(channel), resolver);
+ grpc_client_channel_finish_initialization(
+ exec_ctx, grpc_channel_get_channel_stack(channel), resolver, &f->base);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create_channel");
return channel;
@@ -250,12 +245,8 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
grpc_channel *channel = client_channel_factory_create_channel(
&exec_ctx, &f->base, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, NULL);
- if (channel != NULL) {
- f->master = channel;
- GRPC_CHANNEL_INTERNAL_REF(f->master, "grpc_insecure_channel_create");
- }
- grpc_client_channel_factory_unref(&exec_ctx, &f->base);
+ grpc_client_channel_factory_unref(&exec_ctx, &f->base);
grpc_exec_ctx_finish(&exec_ctx);
return channel != NULL ? channel : grpc_lame_client_channel_create(
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
index 9e2bdd758f..f36fbbfc57 100644
--- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
@@ -220,7 +220,6 @@ typedef struct {
gpr_refcount refs;
grpc_channel_args *merge_args;
grpc_channel_security_connector *security_connector;
- grpc_channel *master;
} client_channel_factory;
static void client_channel_factory_ref(
@@ -235,10 +234,6 @@ static void client_channel_factory_unref(
if (gpr_unref(&f->refs)) {
GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base,
"client_channel_factory");
- if (f->master != NULL) {
- GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, f->master,
- "client_channel_factory");
- }
grpc_channel_args_destroy(f->merge_args);
gpr_free(f);
}
@@ -276,10 +271,10 @@ static grpc_channel *client_channel_factory_create_channel(
GRPC_CLIENT_CHANNEL, NULL);
grpc_channel_args_destroy(final_args);
- grpc_resolver *resolver = grpc_resolver_create(target, &f->base);
+ grpc_resolver *resolver = grpc_resolver_create(target);
if (resolver != NULL) {
- grpc_client_channel_set_resolver(
- exec_ctx, grpc_channel_get_channel_stack(channel), resolver);
+ grpc_client_channel_finish_initialization(
+ exec_ctx, grpc_channel_get_channel_stack(channel), resolver, &f->base);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create");
} else {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
@@ -356,10 +351,6 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
grpc_channel *channel = client_channel_factory_create_channel(
&exec_ctx, &f->base, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, NULL);
- if (channel != NULL) {
- f->master = channel;
- GRPC_CHANNEL_INTERNAL_REF(f->master, "grpc_secure_channel_create");
- }
grpc_client_channel_factory_unref(&exec_ctx, &f->base);
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_plugin.c b/src/core/ext/transport/chttp2/transport/chttp2_plugin.c
index 7d5279b9da..bd87253ed3 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_plugin.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_plugin.c
@@ -36,14 +36,11 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/transport/metadata.h"
-extern int grpc_http_write_state_trace;
-
void grpc_chttp2_plugin_init(void) {
grpc_chttp2_base64_encode_and_huffman_compress =
grpc_chttp2_base64_encode_and_huffman_compress_impl;
grpc_register_tracer("http", &grpc_http_trace);
grpc_register_tracer("flowctl", &grpc_flowctl_trace);
- grpc_register_tracer("http_write_state", &grpc_http_write_state_trace);
}
void grpc_chttp2_plugin_shutdown(void) {}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 00999e3b94..d46656ce81 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -33,6 +33,7 @@
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
@@ -46,6 +47,7 @@
#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/workqueue.h"
#include "src/core/lib/profiling/timers.h"
@@ -63,40 +65,27 @@
#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 initiate_writing(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 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,
- const char *reason);
+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);
@@ -105,56 +94,28 @@ static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_error *error);
-/** Perform a transport_op */
-static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, void *transport_op);
-
-/** 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);
-
-/** Add endpoint from this transport to pollset */
-static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_ignored, void *pollset);
-static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_ignored,
- void *pollset_set);
+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 finish_global_actions(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t);
-
-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,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s,
- void *byte_stream);
+ 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);
/*******************************************************************************
@@ -165,39 +126,33 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) {
size_t i;
- gpr_mu_lock(&t->executor.mu);
-
- GPR_ASSERT(t->ep == NULL);
+ 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);
- gpr_mu_unlock(&t->executor.mu);
- gpr_mu_destroy(&t->executor.mu);
+ 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;
@@ -205,37 +160,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,
@@ -251,74 +209,67 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->base.vtable = &vtable;
t->ep = ep;
- /* one ref is for destroy, the other for when ep becomes NULL */
- gpr_ref_init(&t->refs, 2);
- /* ref is dropped at transport close() */
- gpr_ref_init(&t->shutdown_ep_refs, 1);
- gpr_mu_init(&t->executor.mu);
+ /* one ref is for destroy */
+ gpr_ref_init(&t->refs, 1);
+ 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->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->parsing_action, parsing_action, t);
- grpc_closure_init(&t->initiate_writing, initiate_writing, t);
+ gpr_slice_buffer_init(&t->outbuf);
+ grpc_chttp2_hpack_compressor_init(&t->hpack_compressor);
- 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_closure_init(&t->write_action_begin_locked, write_action_begin_locked,
+ t);
+ 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);
+
+ grpc_chttp2_goaway_parser_init(&t->goaway_parser);
+ grpc_chttp2_hpack_parser_init(&t->hpack_parser);
- grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
- &t->writing);
gpr_slice_buffer_init(&t->read_buffer);
- if (is_client) {
- gpr_slice_buffer_add(
- &t->global.qbuf,
- gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
- grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "initial_write");
- }
/* 8 is a random stab in the dark as to a good initial size: it's small enough
that it shouldn't waste memory for infrequently used connections, yet
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->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 */
if (is_client) {
@@ -332,701 +283,430 @@ 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 if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
- gpr_log(GPR_ERROR, "%s: must be an integer",
- GRPC_ARG_MAX_CONCURRENT_STREAMS);
- } else {
- push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
- (uint32_t)channel_args->args[i].value.integer);
- }
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) {
- if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
- gpr_log(GPR_ERROR, "%s: must be an integer",
- GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER);
- } else if ((t->global.next_stream_id & 1) !=
- (channel_args->args[i].value.integer & 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");
- } else {
- t->global.next_stream_id =
- (uint32_t)channel_args->args[i].value.integer;
+ 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->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->next_stream_id & 1, is_client ? "client" : "server");
+ } else {
+ t->next_stream_id = (uint32_t)value;
+ }
}
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) {
- if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
- gpr_log(GPR_ERROR, "%s: must be an integer",
- GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
- } else if (channel_args->args[i].value.integer <= 5) {
- gpr_log(GPR_ERROR, "%s: must be at least 5",
- GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
- } else {
- t->global.stream_lookahead =
- (uint32_t)channel_args->args[i].value.integer;
- }
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) {
- if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
- gpr_log(GPR_ERROR, "%s: must be an integer",
- GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
- } else if (channel_args->args[i].value.integer < 0) {
- gpr_log(GPR_ERROR, "%s: must be non-negative",
- GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
- } else {
- push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
- (uint32_t)channel_args->args[i].value.integer);
+ const grpc_integer_options options = {-1, 5, INT_MAX};
+ const int value =
+ grpc_channel_arg_get_integer(&channel_args->args[i], options);
+ if (value >= 0) {
+ t->stream_lookahead = (uint32_t)value;
}
} else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER)) {
- if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
- gpr_log(GPR_ERROR, "%s: must be an integer",
- GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
- } else if (channel_args->args[i].value.integer < 0) {
- gpr_log(GPR_ERROR, "%s: must be non-negative",
- GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
- } else {
- grpc_chttp2_hpack_compressor_set_max_usable_size(
- &t->writing.hpack_compressor,
- (uint32_t)channel_args->args[i].value.integer);
- }
- } else if (0 == strcmp(channel_args->args[i].key,
- GRPC_ARG_MAX_METADATA_SIZE)) {
- if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
- gpr_log(GPR_ERROR, "%s: must be an integer",
- GRPC_ARG_MAX_METADATA_SIZE);
- } else if (channel_args->args[i].value.integer < 0) {
- gpr_log(GPR_ERROR, "%s: must be non-negative",
- GRPC_ARG_MAX_METADATA_SIZE);
- } else {
- push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
- (uint32_t)channel_args->args[i].value.integer);
+ 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) {
+ 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;
+ }
}
}
}
}
+
+ grpc_chttp2_initiate_write(exec_ctx, t, false, "init");
}
-static void destroy_transport_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_ignored,
- void *arg_ignored) {
+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"));
+ 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_chttp2_run_with_global_lock(exec_ctx, t, NULL, destroy_transport_locked,
- NULL, 0);
- UNREF_TRANSPORT(exec_ctx, t, "destroy");
-}
-
-/** block grpc_endpoint_shutdown being called until a paired
- allow_endpoint_shutdown is made */
-static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) {
- GPR_ASSERT(t->ep);
- 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)) {
- if (t->ep) {
- grpc_endpoint_shutdown(exec_ctx, t->ep);
- }
- }
-}
-
-static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t) {
- grpc_endpoint_destroy(exec_ctx, t->ep);
- t->ep = NULL;
- /* safe because we'll still have the ref for write */
- UNREF_TRANSPORT(exec_ctx, t, "disconnect");
+ grpc_combiner_execute(exec_ctx, t->combiner,
+ grpc_closure_create(destroy_transport_locked, t),
+ 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);
- }
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");
- if (t->ep) {
- 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");
}
}
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,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s,
- void *arg_ignored) {
- grpc_chttp2_register_stream(t, s);
-}
-
static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_stream_refcount *refcount,
const void *server_data) {
+ GPR_TIMER_BEGIN("init_stream", 0);
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
memset(s, 0, sizeof(*s));
+ s->t = t;
s->refcount = refcount;
/* 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_chttp2_run_with_global_lock(exec_ctx, t, s, finish_init_stream_locked,
- NULL, 0);
+ GPR_TIMER_END("init_stream", 0);
return 0;
}
-static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, void *arg) {
+static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
+ grpc_error *error) {
grpc_byte_stream *bs;
+ grpc_chttp2_stream *s = sp;
+ grpc_chttp2_transport *t = s->t;
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))) {
- incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
+ 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);
- gpr_free(arg);
+ gpr_free(s->destroy_stream_arg);
}
static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, void *and_free_memory) {
+ GPR_TIMER_BEGIN("destroy_stream", 0);
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
- grpc_chttp2_run_with_global_lock(exec_ctx, t, s, destroy_stream_locked,
- and_free_memory, 0);
+ s->destroy_stream_arg = and_free_memory;
+ grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s);
+ 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) {
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_WRITING_INACTIVE:
- return "INACTIVE";
- case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
- return "REQUESTED[p=0]";
- case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
- return "REQUESTED[p=1]";
- 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);
- }
- t->executor.write_state = state;
-}
-
-static void finish_global_actions(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t) {
- grpc_chttp2_executor_action_header *hdr;
- grpc_chttp2_executor_action_header *next;
-
- GPR_TIMER_BEGIN("finish_global_actions", 0);
-
- for (;;) {
- check_read_ops(exec_ctx, &t->global);
-
- gpr_mu_lock(&t->executor.mu);
- if (t->executor.pending_actions_head != NULL) {
- hdr = t->executor.pending_actions_head;
- t->executor.pending_actions_head = t->executor.pending_actions_tail =
- NULL;
- gpr_mu_unlock(&t->executor.mu);
- while (hdr != NULL) {
- GPR_TIMER_BEGIN("chttp2:locked_action", 0);
- hdr->action(exec_ctx, t, hdr->stream, hdr->arg);
- GPR_TIMER_END("chttp2:locked_action", 0);
- next = hdr->next;
- gpr_free(hdr);
- UNREF_TRANSPORT(exec_ctx, t, "pending_action");
- hdr = next;
- }
- continue;
- } else {
- t->executor.global_active = false;
- switch (t->executor.write_state) {
- case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
- set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "unlocking");
- REF_TRANSPORT(t, "initiate_writing");
- gpr_mu_unlock(&t->executor.mu);
- grpc_exec_ctx_sched(
- exec_ctx, &t->initiate_writing, GRPC_ERROR_NONE,
- t->ep != NULL ? grpc_endpoint_get_workqueue(t->ep) : NULL);
- break;
- case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
- start_writing(exec_ctx, t);
- gpr_mu_unlock(&t->executor.mu);
- break;
- case GRPC_CHTTP2_WRITING_INACTIVE:
- case GRPC_CHTTP2_WRITING:
- case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
- case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
- case GRPC_CHTTP2_WRITE_SCHEDULED:
- gpr_mu_unlock(&t->executor.mu);
- break;
- }
- }
- break;
- }
-
- GPR_TIMER_END("finish_global_actions", 0);
+ 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;
}
-void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *optional_stream,
- grpc_chttp2_locked_action action,
- void *arg, size_t sizeof_arg) {
- grpc_chttp2_executor_action_header *hdr;
-
- GPR_TIMER_BEGIN("grpc_chttp2_run_with_global_lock", 0);
-
- REF_TRANSPORT(t, "run_global");
- gpr_mu_lock(&t->executor.mu);
-
- for (;;) {
- if (!t->executor.global_active) {
- t->executor.global_active = 1;
- gpr_mu_unlock(&t->executor.mu);
-
- GPR_TIMER_BEGIN("chttp2:locked_action", 0);
- action(exec_ctx, t, optional_stream, arg);
- GPR_TIMER_END("chttp2:locked_action", 0);
-
- finish_global_actions(exec_ctx, t);
- } else {
- gpr_mu_unlock(&t->executor.mu);
-
- hdr = gpr_malloc(sizeof(*hdr) + sizeof_arg);
- hdr->stream = optional_stream;
- hdr->action = action;
- if (sizeof_arg == 0) {
- hdr->arg = arg;
- } else {
- hdr->arg = hdr + 1;
- memcpy(hdr->arg, arg, sizeof_arg);
- }
-
- gpr_mu_lock(&t->executor.mu);
- if (!t->executor.global_active) {
- /* global lock was released while allocating memory: release & retry */
- gpr_free(hdr);
- continue;
- }
- hdr->next = NULL;
- if (t->executor.pending_actions_head != NULL) {
- t->executor.pending_actions_tail =
- t->executor.pending_actions_tail->next = hdr;
- } else {
- t->executor.pending_actions_tail = t->executor.pending_actions_head =
- hdr;
- }
- REF_TRANSPORT(t, "pending_action");
- gpr_mu_unlock(&t->executor.mu);
- }
- break;
- }
-
- UNREF_TRANSPORT(exec_ctx, t, "run_global");
-
- GPR_TIMER_END("grpc_chttp2_run_with_global_lock", 0);
-}
-
-/*******************************************************************************
- * 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) {
- /* Perform state checks, and transition to a scheduled state if appropriate.
- Each time we finish the global lock execution, we check if we need to
- write. If we do:
- - (if there is a poller surrounding the write) schedule
- initiate_writing, which locks and calls initiate_writing_locked to...
- - 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_WRITING_INACTIVE:
- set_write_state(t, covered_by_poller
- ? GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER
- : GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
- reason);
+ GPR_TIMER_BEGIN("grpc_chttp2_initiate_write", 0);
+
+ switch (t->write_state) {
+ case GRPC_CHTTP2_WRITE_STATE_IDLE:
+ set_write_state(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_WRITE_REQUESTED_WITH_POLLER:
- /* nothing to do: write already requested */
+ case GRPC_CHTTP2_WRITE_STATE_WRITING:
+ set_write_state(
+ 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_REQUESTED_NO_POLLER:
+ case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE:
if (covered_by_poller) {
- /* upgrade to note poller is available to cover the write */
- set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER, reason);
+ set_write_state(
+ t, GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER,
+ reason);
}
break;
- case GRPC_CHTTP2_WRITE_SCHEDULED:
- /* nothing to do: write already scheduled */
- 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);
+ case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER:
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);
- }
- break;
- }
-}
-
-static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
- GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED ||
- t->executor.write_state == GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER);
- if (!t->closed &&
- grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
- set_write_state(t, GRPC_CHTTP2_WRITING, "start_writing");
- REF_TRANSPORT(t, "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, "Nothing to write");
- if (t->ep && !t->endpoint_reading) {
- destroy_endpoint(exec_ctx, t);
- }
}
-}
-
-static void initiate_writing_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused,
- void *arg_ignored) {
- start_writing(exec_ctx, t);
- UNREF_TRANSPORT(exec_ctx, t, "initiate_writing");
-}
-
-static void initiate_writing(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_error *error) {
- grpc_chttp2_run_with_global_lock(exec_ctx, arg, NULL, initiate_writing_locked,
- NULL, 0);
+ GPR_TIMER_END("grpc_chttp2_initiate_write", 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);
+ 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);
}
}
-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_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(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(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);
}
-/* 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,
- const char *reason) {
- grpc_chttp2_stream_global *stream_global;
- while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
- &stream_global)) {
- if (error == GRPC_ERROR_NONE && reason != NULL) {
- /* create error object. */
- error = GRPC_ERROR_CREATE(reason);
- }
- 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(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);
}
-static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_ignored,
- void *a) {
- grpc_error *error = a;
+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);
+}
- allow_endpoint_shutdown_locked(exec_ctx, t);
+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;
if (error != GRPC_ERROR_NONE) {
drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
}
- grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
-
- end_waiting_for_write(exec_ctx, t, error, NULL);
+ grpc_chttp2_end_write(exec_ctx, t, GRPC_ERROR_REF(error));
- switch (t->executor.write_state) {
- case GRPC_CHTTP2_WRITING_INACTIVE:
- case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
- case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
- case GRPC_CHTTP2_WRITE_SCHEDULED:
+ switch (t->write_state) {
+ case GRPC_CHTTP2_WRITE_STATE_IDLE:
GPR_UNREACHABLE_CODE(break);
- case GRPC_CHTTP2_WRITING:
- set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "terminate_writing");
+ case GRPC_CHTTP2_WRITE_STATE_WRITING:
+ GPR_TIMER_MARK("state=writing", 0);
+ set_write_state(t, GRPC_CHTTP2_WRITE_STATE_IDLE, "finish writing");
break;
- case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
- set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
- "terminate_writing");
+ case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE:
+ GPR_TIMER_MARK("state=writing_stale_no_poller", 0);
+ set_write_state(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_WRITING_STALE_NO_POLLER:
- set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
- "terminate_writing");
+ case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER:
+ GPR_TIMER_MARK("state=writing_stale_with_poller", 0);
+ set_write_state(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;
}
- if (t->ep && !t->endpoint_reading) {
- destroy_endpoint(exec_ctx, t);
- }
-
- UNREF_TRANSPORT(exec_ctx, t, "writing");
-}
-
-void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
- void *transport_writing, grpc_error *error) {
- grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
- grpc_chttp2_run_with_global_lock(
- exec_ctx, t, NULL, terminate_writing_with_lock, GRPC_ERROR_REF(error), 0);
+ GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing");
+ GPR_TIMER_END("terminate_writing_with_lock", 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,
@@ -1036,61 +716,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));
}
}
@@ -1102,104 +770,188 @@ 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 do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
+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) {
+ ssize_t notify_offset = s->fetching_slice_end_offset;
+ if (notify_offset <= 0) {
+ 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 = (size_t)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 perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
+static void add_fetched_slice_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, void *stream_op) {
+ 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) {}
+
+static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
+ grpc_error *error_ignored) {
GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
grpc_transport_stream_op *op = stream_op;
- grpc_chttp2_transport_global *transport_global = &t->global;
- grpc_chttp2_stream_global *stream_global = &s->global;
+ grpc_chttp2_transport *t = op->transport_private.args[0];
+ grpc_chttp2_stream *s = op->transport_private.args[1];
+
+ if (grpc_http_trace) {
+ char *str = grpc_transport_stream_op_string(op);
+ gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s", str);
+ gpr_free(str);
+ }
grpc_closure *on_complete = op->on_complete;
if (on_complete == NULL) {
on_complete = grpc_closure_create(do_nothing, NULL);
}
+
+ if (grpc_http_trace) {
+ gpr_log(GPR_DEBUG, " on_complete = %p", on_complete);
+ }
+
/* 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(
@@ -1209,63 +961,75 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
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(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->fetching_slice_end_offset =
+ (ssize_t)s->flow_controlled_buffer.length + (ssize_t)len;
+ s->complete_fetch_covered_by_poller = op->covered_by_poller;
+ if (flags & GRPC_WRITE_BUFFER_HINT) {
+ s->fetching_slice_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(
@@ -1275,135 +1039,129 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
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(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(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(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(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, "perform_stream_op");
}
static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_transport_stream_op *op) {
+ GPR_TIMER_BEGIN("perform_stream_op", 0);
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
- grpc_chttp2_run_with_global_lock(exec_ctx, t, s, perform_stream_op_locked, op,
- sizeof(*op));
+
+ 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, "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");
}
-static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, void *opaque_8bytes) {
+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 = &t->global;
- for (ping = transport_global->pings.next; ping != &transport_global->pings;
- ping = ping->next) {
+ 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;
}
}
-}
-
-void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- const uint8_t *opaque_8bytes) {
- grpc_chttp2_run_with_global_lock(
- exec_ctx, TRANSPORT_FROM_PARSING(transport_parsing), NULL,
- ack_ping_locked, (void *)opaque_8bytes, 8);
+ 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,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused,
- void *stream_op) {
+ void *stream_op,
+ grpc_error *error_ignored) {
grpc_transport_op *op = stream_op;
+ 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;
- }
-
- grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
-
if (op->on_connectivity_state_change != NULL) {
grpc_connectivity_state_notify_on_state_change(
exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state,
@@ -1411,15 +1169,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) {
@@ -1429,11 +1187,11 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
}
if (op->bind_pollset) {
- add_to_pollset_locked(exec_ctx, t, NULL, op->bind_pollset);
+ grpc_endpoint_add_to_pollset(exec_ctx, t->ep, op->bind_pollset);
}
if (op->bind_pollset_set) {
- add_to_pollset_set_locked(exec_ctx, t, NULL, op->bind_pollset_set);
+ grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, op->bind_pollset_set);
}
if (op->send_ping) {
@@ -1443,144 +1201,131 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
if (close_transport != GRPC_ERROR_NONE) {
close_transport_locked(exec_ctx, t, close_transport);
}
+
+ grpc_closure_run(exec_ctx, op->on_consumed, GRPC_ERROR_NONE);
+
+ 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;
- grpc_chttp2_run_with_global_lock(
- exec_ctx, t, NULL, perform_transport_op_locked, op, sizeof(*op));
+ 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);
+ 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) {
- 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, NULL, NULL, bs);
- }
- 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) {
+ gpr_log(GPR_DEBUG, "discard %p", bs);
+ 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) {
- incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
- }
- 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;
- }
+ 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) {
+ gpr_log(GPR_DEBUG, "discard %p", bs);
+ incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
}
- 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, NULL, NULL, bs);
- }
- 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->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) {
+ gpr_log(GPR_DEBUG, "discard %p", bs);
+ incoming_byte_stream_destroy_locked(exec_ctx, bs, 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");
+ }
}
}
-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(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,
@@ -1610,23 +1355,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 =
@@ -1637,25 +1379,20 @@ 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(transport_global, stream_global);
+ if (due_to_error != GRPC_ERROR_NONE && !s->seen_error) {
+ s->seen_error = true;
}
- 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(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,
@@ -1663,23 +1400,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(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);
@@ -1698,11 +1435,11 @@ static void add_error(grpc_error *error, grpc_error **refs, size_t *nrefs) {
}
static grpc_error *removal_error(grpc_error *extra_error,
- grpc_chttp2_stream_global *stream_global) {
+ grpc_chttp2_stream *s) {
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) {
@@ -1714,73 +1451,71 @@ static grpc_error *removal_error(grpc_error *extra_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);
+ s->fetching_send_message = NULL;
+ grpc_chttp2_complete_closure_step(
+ 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_initial_metadata_finished, GRPC_ERROR_REF(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, 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->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(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));
+ }
+ 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;
@@ -1788,16 +1523,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. */
@@ -1862,23 +1598,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);
@@ -1888,38 +1623,39 @@ 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);
}
@@ -1934,20 +1670,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);
}
}
@@ -1955,45 +1694,17 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
* INPUT PROCESSING - PARSING
*/
-static void reading_action_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused, void *arg);
-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,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused, void *arg);
-static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused, void *arg);
-
-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 */
- grpc_chttp2_run_with_global_lock(exec_ctx, tp, NULL, reading_action_locked,
- GRPC_ERROR_REF(error), 0);
-}
-
-static void reading_action_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused, void *arg) {
- grpc_chttp2_transport_global *transport_global = &t->global;
- grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
- grpc_error *error = arg;
-
- 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, error, NULL);
- } else {
- post_reading_action_locked(exec_ctx, t, s_unused, arg);
- }
+ GPR_TIMER_BEGIN("reading_action", 0);
+ grpc_chttp2_transport *t = tp;
+ grpc_combiner_execute(exec_ctx, t->combiner, &t->read_action_locked,
+ GRPC_ERROR_REF(error), false);
+ GPR_TIMER_END("reading_action", 0);
}
static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
@@ -2023,169 +1734,110 @@ 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));
- }
- for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) {
- GRPC_ERROR_UNREF(errors[i]);
- }
- GPR_TIMER_END("reading_action.parse", 0);
- grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked, err,
- 0);
-}
-
-static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused, void *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, t, NULL, op);
- 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, s_unused, arg);
-}
-
-static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused,
- void *arg) {
- grpc_error *error = arg;
+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);
+
+ 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);
+ }
+
+ GPR_TIMER_BEGIN("post_reading_action_locked", 0);
bool keep_reading = false;
if (error == GRPC_ERROR_NONE && t->closed) {
error = GRPC_ERROR_CREATE("Transport closed");
}
if (error != GRPC_ERROR_NONE) {
- 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);
- }
drop_connection(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));
- }
- if (t->executor.write_state == GRPC_CHTTP2_WRITING_INACTIVE && t->ep) {
- destroy_endpoint(exec_ctx, t);
- }
} 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);
- GRPC_ERROR_UNREF(error);
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");
}
+
+ 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);
}
/*******************************************************************************
* POLLSET STUFF
*/
-static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused, void *pollset) {
- if (t->ep) {
- grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset);
- }
-}
-
-static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_unused,
- void *pollset_set) {
- if (t->ep) {
- grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set);
- }
-}
-
static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_pollset *pollset) {
- /* TODO(ctiller): keep pollset alive */
- grpc_chttp2_run_with_global_lock(exec_ctx, (grpc_chttp2_transport *)gt,
- (grpc_chttp2_stream *)gs,
- add_to_pollset_locked, pollset, 0);
+ grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+ grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset);
}
static void set_pollset_set(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_pollset_set *pollset_set) {
- grpc_chttp2_run_with_global_lock(exec_ctx, (grpc_chttp2_transport *)gt,
- (grpc_chttp2_stream *)gs,
- add_to_pollset_set_locked, pollset_set, 0);
+ grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+ grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set);
}
/*******************************************************************************
@@ -2197,19 +1849,21 @@ static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
if (gpr_unref(&bs->refs)) {
GRPC_ERROR_UNREF(bs->error);
gpr_slice_buffer_destroy(&bs->slices);
+ gpr_mu_destroy(&bs->slice_mu);
gpr_free(bs);
}
}
-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;
}
@@ -2222,58 +1876,50 @@ 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");
}
}
-typedef struct {
- grpc_chttp2_incoming_byte_stream *byte_stream;
- gpr_slice *slice;
- size_t max_size_hint;
- grpc_closure *on_complete;
-} incoming_byte_stream_next_arg;
-
static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s,
- void *argp) {
- incoming_byte_stream_next_arg *arg = argp;
- grpc_chttp2_incoming_byte_stream *bs =
- (grpc_chttp2_incoming_byte_stream *)arg->byte_stream;
- grpc_chttp2_transport_global *transport_global = &bs->transport->global;
- grpc_chttp2_stream_global *stream_global = &bs->stream->global;
+ void *argp,
+ grpc_error *error_ignored) {
+ grpc_chttp2_incoming_byte_stream *bs = argp;
+ grpc_chttp2_transport *t = bs->transport;
+ grpc_chttp2_stream *s = bs->stream;
if (bs->is_tail) {
- incoming_byte_stream_update_flow_control(exec_ctx, transport_global,
- stream_global, arg->max_size_hint,
- bs->slices.length);
+ 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, t, s, bs->next_action.max_size_hint, cur_length);
}
+ gpr_mu_lock(&bs->slice_mu);
if (bs->slices.count > 0) {
- *arg->slice = gpr_slice_buffer_take_first(&bs->slices);
- grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_NONE, NULL);
+ *bs->next_action.slice = gpr_slice_buffer_take_first(&bs->slices);
+ 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, arg->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 = arg->on_complete;
- bs->next = arg->slice;
+ bs->on_next = bs->next_action.on_complete;
+ bs->next = bs->next_action.slice;
}
+ gpr_mu_unlock(&bs->slice_mu);
incoming_byte_stream_unref(exec_ctx, bs);
}
@@ -2281,13 +1927,18 @@ static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
gpr_slice *slice, size_t max_size_hint,
grpc_closure *on_complete) {
+ GPR_TIMER_BEGIN("incoming_byte_stream_next", 0);
grpc_chttp2_incoming_byte_stream *bs =
(grpc_chttp2_incoming_byte_stream *)byte_stream;
- incoming_byte_stream_next_arg arg = {bs, slice, max_size_hint, on_complete};
gpr_ref(&bs->refs);
- grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
- incoming_byte_stream_next_locked, &arg,
- sizeof(arg));
+ bs->next_action.slice = slice;
+ bs->next_action.max_size_hint = max_size_hint;
+ 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->combiner,
+ &bs->next_action.closure, GRPC_ERROR_NONE, false);
+ GPR_TIMER_END("incoming_byte_stream_next", 0);
return 0;
}
@@ -2295,141 +1946,101 @@ static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream);
static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s,
- void *byte_stream) {
+ void *byte_stream,
+ 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);
}
static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream) {
+ GPR_TIMER_BEGIN("incoming_byte_stream_destroy", 0);
grpc_chttp2_incoming_byte_stream *bs =
(grpc_chttp2_incoming_byte_stream *)byte_stream;
- grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
- incoming_byte_stream_destroy_locked, bs, 0);
-}
-
-typedef struct {
- grpc_chttp2_incoming_byte_stream *byte_stream;
- gpr_slice slice;
-} incoming_byte_stream_push_arg;
-
-static void incoming_byte_stream_push_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s,
- void *argp) {
- incoming_byte_stream_push_arg *arg = argp;
- grpc_chttp2_incoming_byte_stream *bs = arg->byte_stream;
- if (bs->on_next != NULL) {
- *bs->next = arg->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, arg->slice);
- }
- incoming_byte_stream_unref(exec_ctx, bs);
+ grpc_closure_init(&bs->destroy_action, incoming_byte_stream_destroy_locked,
+ bs);
+ grpc_combiner_execute(exec_ctx, bs->transport->combiner, &bs->destroy_action,
+ GRPC_ERROR_NONE, false);
+ GPR_TIMER_END("incoming_byte_stream_destroy", 0);
}
-void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_incoming_byte_stream *bs,
- gpr_slice slice) {
- incoming_byte_stream_push_arg arg = {bs, slice};
- gpr_ref(&bs->refs);
- grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
- incoming_byte_stream_push_locked, &arg,
- sizeof(arg));
-}
-
-typedef struct {
- grpc_chttp2_incoming_byte_stream *bs;
- grpc_error *error;
-} bs_fail_args;
-
-static bs_fail_args *make_bs_fail_args(grpc_chttp2_incoming_byte_stream *bs,
- grpc_error *error) {
- bs_fail_args *a = gpr_malloc(sizeof(*a));
- a->bs = bs;
- a->error = error;
- return a;
-}
-
-static void incoming_byte_stream_finished_failed_locked(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
- void *argp) {
- bs_fail_args *a = argp;
- grpc_chttp2_incoming_byte_stream *bs = a->bs;
- grpc_error *error = a->error;
- gpr_free(a);
+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;
- incoming_byte_stream_unref(exec_ctx, bs);
}
-static void incoming_byte_stream_finished_ok_locked(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s,
- void *argp) {
- grpc_chttp2_incoming_byte_stream *bs = argp;
- incoming_byte_stream_unref(exec_ctx, bs);
+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->remaining_bytes < GPR_SLICE_LENGTH(slice)) {
+ incoming_byte_stream_publish_error(
+ exec_ctx, bs, GRPC_ERROR_CREATE("Too many bytes in stream"));
+ } else {
+ 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);
}
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) {
- if (from_parsing_thread) {
- if (error == GRPC_ERROR_NONE) {
- grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
- incoming_byte_stream_finished_ok_locked,
- bs, 0);
- } else {
- grpc_chttp2_run_with_global_lock(
- exec_ctx, bs->transport, bs->stream,
- incoming_byte_stream_finished_failed_locked,
- make_bs_fail_args(bs, error), 0);
- }
- } else {
- if (error == GRPC_ERROR_NONE) {
- incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
- bs->stream, bs);
- } else {
- incoming_byte_stream_finished_failed_locked(
- exec_ctx, bs->transport, bs->stream, make_bs_fail_args(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);
}
+ 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;
}
@@ -2438,40 +2049,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,
@@ -2479,26 +2080,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,
@@ -2523,8 +2116,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);
@@ -2561,10 +2152,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..1bb6ed82b1 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, 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 d67c014e54..3263c99bde 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -48,35 +48,30 @@
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/ext/transport/chttp2/transport/stream_map.h"
+#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/endpoint.h"
#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 */
@@ -151,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 {
+ size_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;
@@ -160,18 +161,86 @@ 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;
+ gpr_slice *slice;
+ size_t max_size_hint;
+ grpc_closure *on_complete;
+ } next_action;
+ grpc_closure destroy_action;
+ 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 */
@@ -182,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? */
@@ -200,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 */
@@ -255,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;
@@ -272,142 +303,38 @@ 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;
};
-typedef void (*grpc_chttp2_locked_action)(grpc_exec_ctx *ctx,
- grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, void *arg);
-
-typedef struct grpc_chttp2_executor_action_header {
- grpc_chttp2_stream *stream;
- grpc_chttp2_locked_action action;
- struct grpc_chttp2_executor_action_header *next;
- void *arg;
-} grpc_chttp2_executor_action_header;
-
typedef enum {
- /** no writing activity */
- GRPC_CHTTP2_WRITING_INACTIVE,
- /** write has been requested, but not scheduled yet */
- GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
- GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
- /** 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 {
- gpr_mu mu;
-
- /** 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;
+ GRPC_METADATA_NOT_PUBLISHED,
+ GRPC_METADATA_SYNTHESIZED_FROM_FAKE,
+ GRPC_METADATA_PUBLISHED_FROM_WIRE,
+ GPRC_METADATA_PUBLISHED_AT_CLOSE
+} grpc_published_metadata_method;
- grpc_chttp2_executor_action_header *pending_actions_head;
- grpc_chttp2_executor_action_header *pending_actions_tail;
- } executor;
-
- /** 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];
-
- /** 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;
- /** closure to actually do parsing */
- grpc_closure parsing_action;
- /** closure to initiate writing */
- grpc_closure initiate_writing;
-
- /** 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;
@@ -417,20 +344,21 @@ 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 fetching_slice_end_offset;
+ 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;
@@ -450,90 +378,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_stream_refcount *refcount;
- grpc_chttp2_stream_global global;
- grpc_chttp2_stream_writing writing;
- grpc_chttp2_stream_parsing parsing;
+ 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:
@@ -549,168 +431,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_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);
-
-void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *transport,
- grpc_chttp2_stream *optional_stream,
- grpc_chttp2_locked_action action,
- void *arg, size_t sizeof_arg);
+ 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 \
@@ -801,57 +586,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 482cd55c44..bc12515b0c 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -45,223 +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(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(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(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(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;
@@ -269,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:
@@ -294,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;
@@ -321,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;
@@ -425,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);
@@ -468,175 +269,164 @@ 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) {
+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,
- transport_parsing->incoming_window);
+ t->incoming_frame_size, t->incoming_window);
grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
}
- if (incoming_frame_size > stream_parsing->incoming_window) {
+ if (incoming_frame_size > s->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, s->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);
+ 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);
+ if (s == NULL) {
+ return init_skip_frame_parser(exec_ctx, t, 0);
}
- stream_parsing->stats.incoming.framing_bytes += 9;
- if (stream_parsing->received_close) {
- return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+ s->stats.incoming.framing_bytes += 9;
+ if (s->read_closed) {
+ return init_skip_frame_parser(exec_ctx, t, 0);
}
if (err == GRPC_ERROR_NONE) {
- err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing);
+ err = update_incoming_window(exec_ctx, t, s);
}
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);
}
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;
+ 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;
}
@@ -644,23 +434,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) {
@@ -677,306 +466,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 2eb5f5f632..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,314 +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);
+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_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_writable_stream(grpc_chttp2_transport *t,
+ grpc_chttp2_stream **s) {
+ return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITABLE);
}
-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;
+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_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);
+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);
}
-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_have_writing_streams(grpc_chttp2_transport *t) {
+ return !stream_list_empty(t, GRPC_CHTTP2_LIST_WRITING);
}
-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;
+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_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);
+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_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;
+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_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);
+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_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;
+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_list_add_check_read_ops(
- 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_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);
-}
-
-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);
-}
-
-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;
-}
-
-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);
-}
-
-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;
-}
-
-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);
-}
-
-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);
-}
-
-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;
-}
-
-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);
-}
-
-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;
-}
-
-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 311b26e354..bc490569b7 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -40,346 +40,215 @@
#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;
+}
-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 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;
+}
- GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0);
+static void update_list(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s, size_t send_bytes,
+ grpc_chttp2_write_cb **list, grpc_error *error) {
+ grpc_chttp2_write_cb *cb = *list;
+ *list = NULL;
+ while (cb) {
+ grpc_chttp2_write_cb *next = cb->next;
+ if (cb->call_at_byte <= send_bytes) {
+ finish_write_cb(exec_ctx, t, s, cb, GRPC_ERROR_REF(error));
+ } else {
+ cb->call_at_byte -= send_bytes;
+ add_to_write_list(list, cb);
+ }
+ cb = next;
+ }
+}
- transport_writing->max_frame_size =
- transport_global->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE];
+bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t) {
+ grpc_chttp2_stream *s;
- /* simple writes are queued to qbuf, and flushed here */
- gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
- GPR_ASSERT(transport_global->qbuf.count == 0);
+ GPR_TIMER_BEGIN("grpc_chttp2_begin_write", 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]);
-
- 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;
}
- 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");
+ /* simple writes are queued to qbuf, and flushed here */
+ gpr_slice_buffer_move_into(&t->qbuf, &t->outbuf);
+ GPR_ASSERT(t->qbuf.count == 0);
+
+ grpc_chttp2_hpack_compressor_set_max_table_size(
+ &t->hpack_compressor,
+ t->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+
+ 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;
-
- stream_writing->id = stream_global->id;
- stream_writing->read_closed = stream_global->read_closed;
+ while (grpc_chttp2_list_pop_writable_stream(t, &s)) {
+ bool sent_initial_metadata = s->sent_initial_metadata;
+ bool now_writing = false;
- GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing,
- outgoing_window, stream_global,
- outgoing_window);
+ 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));
- 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;
- } else {
- grpc_chttp2_list_add_stalled_by_transport(transport_writing,
- stream_writing);
+ if (s->send_trailing_metadata != NULL &&
+ s->fetching_send_message == NULL &&
+ s->flow_controlled_buffer.length == 0) {
+ 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);
-
- 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("grpc_chttp2_begin_write", 0);
- 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) {
- grpc_chttp2_stream_writing *stream_writing;
- grpc_chttp2_stream_global *stream_global;
+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;
- 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");
- }
-
- 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, 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_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/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index 79ceeb66b3..3a56b1ff20 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -271,3 +271,21 @@ int grpc_channel_args_compare(const grpc_channel_args *a,
}
return 0;
}
+
+int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options) {
+ if (arg->type != GRPC_ARG_INTEGER) {
+ gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
+ return options.default_value;
+ }
+ if (arg->value.integer < options.min_value) {
+ gpr_log(GPR_ERROR, "%s ignored: it must be >= %d", arg->key,
+ options.min_value);
+ return options.default_value;
+ }
+ if (arg->value.integer > options.max_value) {
+ gpr_log(GPR_ERROR, "%s ignored: it must be <= %d", arg->key,
+ options.max_value);
+ return options.default_value;
+ }
+ return arg->value.integer;
+}
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index aec61ee7c6..586a296d1f 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -89,4 +89,12 @@ uint32_t grpc_channel_args_compression_algorithm_get_states(
int grpc_channel_args_compare(const grpc_channel_args *a,
const grpc_channel_args *b);
+typedef struct grpc_integer_options {
+ int default_value; // Return this if value is outside of expected bounds.
+ int min_value;
+ int max_value;
+} grpc_integer_options;
+/** Returns the value of \a arg, subject to the contraints in \a options. */
+int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options);
+
#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H */
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 98f304f2da..0655b9353f 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -32,6 +32,7 @@
*/
#include "src/core/lib/channel/channel_stack.h"
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <stdlib.h>
@@ -270,21 +271,27 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) {
sizeof(grpc_call_stack)));
}
+static void destroy_op(grpc_exec_ctx *exec_ctx, void *op, grpc_error *error) {
+ gpr_free(op);
+}
+
void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
grpc_call_element *cur_elem) {
- grpc_transport_stream_op op;
- memset(&op, 0, sizeof(op));
- op.cancel_error = GRPC_ERROR_CANCELLED;
- grpc_call_next_op(exec_ctx, cur_elem, &op);
+ grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
+ memset(op, 0, sizeof(*op));
+ op->cancel_error = GRPC_ERROR_CANCELLED;
+ op->on_complete = grpc_closure_create(destroy_op, op);
+ grpc_call_next_op(exec_ctx, cur_elem, op);
}
void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *cur_elem,
grpc_status_code status,
gpr_slice *optional_message) {
- grpc_transport_stream_op op;
- memset(&op, 0, sizeof(op));
- grpc_transport_stream_op_add_cancellation_with_message(&op, status,
+ grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
+ memset(op, 0, sizeof(*op));
+ op->on_complete = grpc_closure_create(destroy_op, op);
+ grpc_transport_stream_op_add_cancellation_with_message(op, status,
optional_message);
- grpc_call_next_op(exec_ctx, cur_elem, &op);
+ grpc_call_next_op(exec_ctx, cur_elem, op);
}
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 134180e619..0981d59f63 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -60,7 +60,7 @@ typedef struct call_data {
/** If true, contents of \a compression_algorithm are authoritative */
int has_compression_algorithm;
- grpc_transport_stream_op send_op;
+ grpc_transport_stream_op *send_op;
uint32_t send_length;
uint32_t send_flags;
gpr_slice incoming_slice;
@@ -199,11 +199,11 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
calld->send_flags);
- calld->send_op.send_message = &calld->replacement_stream.base;
- calld->post_send = calld->send_op.on_complete;
- calld->send_op.on_complete = &calld->send_done;
+ calld->send_op->send_message = &calld->replacement_stream.base;
+ calld->post_send = calld->send_op->on_complete;
+ calld->send_op->on_complete = &calld->send_done;
- grpc_call_next_op(exec_ctx, elem, &calld->send_op);
+ grpc_call_next_op(exec_ctx, elem, calld->send_op);
}
static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
@@ -220,7 +220,7 @@ static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
static void continue_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
call_data *calld = elem->call_data;
- while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message,
+ while (grpc_byte_stream_next(exec_ctx, calld->send_op->send_message,
&calld->incoming_slice, ~(size_t)0,
&calld->got_slice)) {
gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
@@ -243,7 +243,7 @@ static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
}
if (op->send_message != NULL && !skip_compression(elem) &&
0 == (op->send_message->flags & GRPC_WRITE_NO_COMPRESS)) {
- calld->send_op = *op;
+ calld->send_op = op;
calld->send_length = op->send_message->length;
calld->send_flags = op->send_message->flags;
continue_send_message(exec_ctx, elem);
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
new file mode 100644
index 0000000000..6613785dea
--- /dev/null
+++ b/src/core/lib/channel/message_size_filter.c
@@ -0,0 +1,165 @@
+//
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "src/core/lib/channel/message_size_filter.h"
+
+#include <limits.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/channel/channel_args.h"
+
+// The protobuf library will (by default) start warning at 100 megs.
+#define DEFAULT_MAX_MESSAGE_LENGTH (4 * 1024 * 1024)
+
+typedef struct call_data {
+ // Receive closures are chained: we inject this closure as the
+ // recv_message_ready up-call on transport_stream_op, and remember to
+ // call our next_recv_message_ready member after handling it.
+ grpc_closure recv_message_ready;
+ // Used by recv_message_ready.
+ grpc_byte_stream** recv_message;
+ // Original recv_message_ready callback, invoked after our own.
+ grpc_closure* next_recv_message_ready;
+} call_data;
+
+typedef struct channel_data {
+ size_t max_send_size;
+ size_t max_recv_size;
+} channel_data;
+
+// Callback invoked when we receive a message. Here we check the max
+// receive message size.
+static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data,
+ grpc_error* error) {
+ grpc_call_element* elem = user_data;
+ call_data* calld = elem->call_data;
+ channel_data* chand = elem->channel_data;
+ if (*calld->recv_message != NULL &&
+ (*calld->recv_message)->length > chand->max_recv_size) {
+ char* message_string;
+ gpr_asprintf(
+ &message_string, "Received message larger than max (%u vs. %lu)",
+ (*calld->recv_message)->length, (unsigned long)chand->max_recv_size);
+ gpr_slice message = gpr_slice_from_copied_string(message_string);
+ gpr_free(message_string);
+ grpc_call_element_send_cancel_with_message(
+ exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, &message);
+ }
+ // Invoke the next callback.
+ grpc_exec_ctx_sched(exec_ctx, calld->next_recv_message_ready, error, NULL);
+}
+
+// Start transport op.
+static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
+ grpc_call_element* elem,
+ grpc_transport_stream_op* op) {
+ call_data* calld = elem->call_data;
+ channel_data* chand = elem->channel_data;
+ // Check max send message size.
+ if (op->send_message != NULL &&
+ op->send_message->length > chand->max_send_size) {
+ char* message_string;
+ gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %lu)",
+ op->send_message->length, (unsigned long)chand->max_send_size);
+ gpr_slice message = gpr_slice_from_copied_string(message_string);
+ gpr_free(message_string);
+ grpc_call_element_send_cancel_with_message(
+ exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, &message);
+ }
+ // Inject callback for receiving a message.
+ if (op->recv_message_ready != NULL) {
+ calld->next_recv_message_ready = op->recv_message_ready;
+ calld->recv_message = op->recv_message;
+ op->recv_message_ready = &calld->recv_message_ready;
+ }
+ // Chain to the next filter.
+ grpc_call_next_op(exec_ctx, elem, op);
+}
+
+// Constructor for call_data.
+static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
+ grpc_call_element* elem,
+ grpc_call_element_args* args) {
+ call_data* calld = elem->call_data;
+ calld->next_recv_message_ready = NULL;
+ grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem);
+ return GRPC_ERROR_NONE;
+}
+
+// Destructor for call_data.
+static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
+ const grpc_call_final_info* final_info,
+ void* ignored) {}
+
+// Constructor for channel_data.
+static void init_channel_elem(grpc_exec_ctx* exec_ctx,
+ grpc_channel_element* elem,
+ grpc_channel_element_args* args) {
+ GPR_ASSERT(!args->is_last);
+ channel_data* chand = elem->channel_data;
+ memset(chand, 0, sizeof(*chand));
+ chand->max_send_size = DEFAULT_MAX_MESSAGE_LENGTH;
+ chand->max_recv_size = DEFAULT_MAX_MESSAGE_LENGTH;
+ const grpc_integer_options options = {DEFAULT_MAX_MESSAGE_LENGTH, 0, INT_MAX};
+ for (size_t i = 0; i < args->channel_args->num_args; ++i) {
+ if (strcmp(args->channel_args->args[i].key,
+ GRPC_ARG_MAX_SEND_MESSAGE_LENGTH) == 0) {
+ chand->max_send_size = (size_t)grpc_channel_arg_get_integer(
+ &args->channel_args->args[i], options);
+ }
+ if (strcmp(args->channel_args->args[i].key,
+ GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH) == 0) {
+ chand->max_recv_size = (size_t)grpc_channel_arg_get_integer(
+ &args->channel_args->args[i], options);
+ }
+ }
+}
+
+// Destructor for channel_data.
+static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
+ grpc_channel_element* elem) {}
+
+const grpc_channel_filter grpc_message_size_filter = {
+ start_transport_stream_op,
+ grpc_channel_next_op,
+ sizeof(call_data),
+ init_call_elem,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
+ destroy_call_elem,
+ sizeof(channel_data),
+ init_channel_elem,
+ destroy_channel_elem,
+ grpc_call_next_get_peer,
+ "message_size"};
diff --git a/src/core/lib/channel/message_size_filter.h b/src/core/lib/channel/message_size_filter.h
new file mode 100644
index 0000000000..a88ff7f81a
--- /dev/null
+++ b/src/core/lib/channel/message_size_filter.h
@@ -0,0 +1,39 @@
+//
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H
+#define GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H
+
+#include "src/core/lib/channel/channel_stack.h"
+
+extern const grpc_channel_filter grpc_message_size_filter;
+
+#endif /* GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H */
diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c
index 0b6c3b2539..2c84e82aca 100644
--- a/src/core/lib/iomgr/closure.c
+++ b/src/core/lib/iomgr/closure.c
@@ -35,19 +35,25 @@
#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;
closure->cb_arg = cb_arg;
}
+void grpc_closure_list_init(grpc_closure_list *closure_list) {
+ closure_list->head = closure_list->tail = NULL;
+}
+
void grpc_closure_list_append(grpc_closure_list *closure_list,
grpc_closure *closure, grpc_error *error) {
if (closure == NULL) {
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;
@@ -60,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);
@@ -106,3 +112,11 @@ 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);
+ 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 08e59a168e..2b4b271eaa 100644
--- a/src/core/lib/iomgr/closure.h
+++ b/src/core/lib/iomgr/closure.h
@@ -37,6 +37,7 @@
#include <grpc/support/port_platform.h>
#include <stdbool.h>
#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/support/mpscq.h"
struct grpc_closure;
typedef struct grpc_closure grpc_closure;
@@ -60,6 +61,14 @@ typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg,
/** A closure over a grpc_iomgr_cb_func. */
struct grpc_closure {
+ /** Once queued, next indicates the next queued closure; before then, scratch
+ * space */
+ union {
+ grpc_closure *next;
+ gpr_mpscq_node atm_next;
+ uintptr_t scratch;
+ } next_data;
+
/** Bound callback. */
grpc_iomgr_cb_func cb;
@@ -67,14 +76,10 @@ struct grpc_closure {
void *cb_arg;
/** Once queued, the result of the closure. Before then: scratch space */
- grpc_error *error;
-
- /** Once queued, next indicates the next queued closure; before then, scratch
- * space */
union {
- grpc_closure *next;
+ grpc_error *error;
uintptr_t scratch;
- } next_data;
+ } error_data;
};
/** Initializes \a closure with \a cb and \a cb_arg. */
@@ -87,6 +92,8 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg);
#define GRPC_CLOSURE_LIST_INIT \
{ NULL, NULL }
+void grpc_closure_list_init(grpc_closure_list *list);
+
/** add \a closure to the end of \a list
and set \a closure's result to \a error */
void grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure,
@@ -102,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
new file mode 100644
index 0000000000..48806abc38
--- /dev/null
+++ b/src/core/lib/iomgr/combiner.c
@@ -0,0 +1,324 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/combiner.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/workqueue.h"
+#include "src/core/lib/profiling/timers.h"
+
+int grpc_combiner_trace = 0;
+
+#define GRPC_COMBINER_TRACE(fn) \
+ do { \
+ if (grpc_combiner_trace) { \
+ fn; \
+ } \
+ } while (0)
+
+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
+ gpr_atm state;
+ // number of elements in the list that are covered by a poller: if >0, we can
+ // offload safely
+ gpr_atm covered_by_poller;
+ bool time_to_execute_final_list;
+ bool final_list_covered_by_poller;
+ grpc_closure_list final_list;
+ 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->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;
+ lock->final_list_covered_by_poller = false;
+ gpr_atm_no_barrier_store(&lock->state, 1);
+ gpr_atm_no_barrier_store(&lock->covered_by_poller, 0);
+ gpr_mpscq_init(&lock->queue);
+ 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;
+}
+
+static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) {
+ GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p really_destroy", lock));
+ GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0);
+ gpr_mpscq_destroy(&lock->queue);
+ GRPC_WORKQUEUE_UNREF(exec_ctx, lock->optional_workqueue, "combiner");
+ gpr_free(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);
+ GRPC_COMBINER_TRACE(gpr_log(
+ GPR_DEBUG, "C:%p really_destroy old_state=%" PRIdPTR, lock, old_state));
+ if (old_state == 1) {
+ really_destroy(exec_ctx, 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 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 (lock->next_combiner_on_this_exec_ctx == NULL) {
+ exec_ctx->last_combiner = lock;
+ }
+}
+
+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, 2);
+ 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 & 1); // 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->covered_by_poller, 1);
+ }
+ gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next);
+ if (last == 1) {
+ // code will be written when the exec_ctx calls
+ // grpc_combiner_continue_exec_ctx
+ push_last_on_exec_ctx(exec_ctx, lock);
+ }
+ GPR_TIMER_END("combiner.execute", 0);
+}
+
+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;
+ }
+}
+
+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;
+ }
+
+ GRPC_COMBINER_TRACE(
+ 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;
+ }
+
+ 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 inconsistant 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;
+ }
+ 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->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);
+ }
+ }
+
+ 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, -2);
+ GRPC_COMBINER_TRACE(
+ gpr_log(GPR_DEBUG, "C:%p finish old_state=%" PRIdPTR, lock, 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)) {
+ lock->time_to_execute_final_list = true;
+ }
+ break;
+ case 3: // had one count, one unorphaned --> unlocked unorphaned
+ GPR_TIMER_END("combiner.continue_exec_ctx", 0);
+ return true;
+ case 2: // and one count, one orphaned --> unlocked and orphaned
+ really_destroy(exec_ctx, lock);
+ GPR_TIMER_END("combiner.continue_exec_ctx", 0);
+ return true;
+ case 1:
+ case 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);
+ }
+ 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,
+ grpc_error *error) {
+ grpc_combiner_execute_finally(exec_ctx, exec_ctx->active_combiner, closure,
+ GRPC_ERROR_REF(error), false);
+}
+
+void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
+ grpc_closure *closure, grpc_error *error,
+ bool covered_by_poller) {
+ GRPC_COMBINER_TRACE(gpr_log(
+ 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,
+ false);
+ GPR_TIMER_END("combiner.execute_finally", 0);
+ return;
+ }
+
+ if (grpc_closure_list_empty(lock->final_list)) {
+ gpr_atm_full_fetch_add(&lock->state, 2);
+ }
+ 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);
+}
diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h
new file mode 100644
index 0000000000..d04eeed83a
--- /dev/null
+++ b/src/core/lib/iomgr/combiner.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_COMBINER_H
+#define GRPC_CORE_LIB_IOMGR_COMBINER_H
+
+#include <stddef.h>
+
+#include <grpc/support/atm.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/support/mpscq.h"
+
+// Provides serialized access to some resource.
+// Each action queued on a combiner is executed serially in a borrowed thread.
+// The actual thread executing actions may change over time (but there will only
+// every be one at a time).
+
+// Initialize the lock, with an optional workqueue to shift load to when
+// necessary
+grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue);
+// Destroy the lock
+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,
+ bool covered_by_poller);
+// Execute \a action within the lock just prior to unlocking.
+void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
+ grpc_closure *closure, grpc_error *error,
+ bool covered_by_poller);
+
+bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx);
+
+extern int grpc_combiner_trace;
+
+#endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */
diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c
index 149c55663c..45ef75e04d 100644
--- a/src/core/lib/iomgr/error.c
+++ b/src/core/lib/iomgr/error.c
@@ -265,7 +265,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);
@@ -332,7 +332,7 @@ grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child) {
return new;
}
-static const char *no_error_string = "null";
+static const char *no_error_string = "\"No Error\"";
static const char *oom_error_string = "\"Out of memory\"";
static const char *cancelled_error_string = "\"Cancelled\"";
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
index 6c769accdb..2ab3ef9f40 100644
--- a/src/core/lib/iomgr/error.h
+++ b/src/core/lib/iomgr/error.h
@@ -123,9 +123,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 eba347125e..42c0ae2dcd 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -152,14 +152,13 @@ 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))
@@ -185,8 +184,11 @@ 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;
+ gpr_atm poller_count;
+ gpr_mu workqueue_read_mu;
+ gpr_mpscq workqueue_items;
+ gpr_atm workqueue_item_count;
+ grpc_wakeup_fd workqueue_wakeup_fd;
/* The fd of the underlying epoll set */
int epoll_fd;
@@ -275,6 +277,8 @@ 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;
+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 +293,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 +306,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 +349,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 +357,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 +511,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 +533,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 +553,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 +702,40 @@ static void polling_island_unlock_pair(polling_island *p, polling_island *q) {
}
}
+static void workqueue_maybe_wakeup(polling_island *pi) {
+ bool force_wakeup = false;
+ 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);
+ if (force_wakeup || 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 +760,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 +772,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 +1122,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 +1376,26 @@ 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) {
+ 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 +1450,10 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
PI_ADD_REF(pi, "ps_work");
gpr_mu_unlock(&pollset->mu);
- do {
+ 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 +1485,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 +1512,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);
@@ -1531,6 +1638,8 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_fd *fd) {
+ GPR_TIMER_BEGIN("pollset_add_fd", 0);
+
grpc_error *error = GRPC_ERROR_NONE;
gpr_mu_lock(&pollset->mu);
@@ -1643,6 +1752,8 @@ retry:
gpr_mu_unlock(&pollset->mu);
GRPC_LOG_IF_ERROR("pollset_add_fd", error);
+
+ GPR_TIMER_END("pollset_add_fd", 0);
}
/*******************************************************************************
@@ -1864,6 +1975,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_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..b84a56018f 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -1236,6 +1236,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
*/
@@ -1273,6 +1299,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_posix.c b/src/core/lib/iomgr/ev_posix.c
index 6536672685..26618f8d55 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -258,4 +258,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..a3c40e8092 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,47 @@ 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;
+ }
+ continue;
+ }
+ if (grpc_combiner_continue_exec_ctx(exec_ctx)) {
+ continue;
+ }
+ 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);
+ GPR_TIMER_END("grpc_exec_ctx_flush", 0);
+ return true;
}
}
GPR_TIMER_END("grpc_exec_ctx_flush", 0);
@@ -86,12 +116,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 917f332f03..91029f5fba 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -40,8 +40,8 @@
/** A workqueue represents a list of work to be executed asynchronously.
Forward declared here to avoid a circular dependency with workqueue.h. */
-struct grpc_workqueue;
typedef struct grpc_workqueue grpc_workqueue;
+typedef struct grpc_combiner grpc_combiner;
#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER
/** Execution context.
@@ -66,13 +66,23 @@ typedef struct grpc_workqueue grpc_workqueue;
*/
struct grpc_exec_ctx {
grpc_closure_list closure_list;
+ grpc_workqueue *stealing_from_workqueue;
+ grpc_closure *stolen_closure;
+ /** currently active combiner: updated only via combiner.c */
+ grpc_combiner *active_combiner;
+ 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, 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;
@@ -83,8 +93,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 974d5ae479..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
@@ -379,15 +379,21 @@ static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
}
if (!tcp_flush(tcp, &error)) {
+ if (grpc_tcp_trace) {
+ gpr_log(GPR_DEBUG, "write: delayed");
+ }
grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
} else {
cb = tcp->write_cb;
tcp->write_cb = NULL;
- GPR_TIMER_BEGIN("tcp_handle_write.cb", 0);
- cb->cb(exec_ctx, cb->cb_arg, error);
- GPR_TIMER_END("tcp_handle_write.cb", 0);
+ if (grpc_tcp_trace) {
+ const char *str = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "write: %s", str);
+ grpc_error_free_string(str);
+ }
+
+ grpc_closure_run(exec_ctx, cb, error);
TCP_UNREF(exec_ctx, tcp, "write");
- GRPC_ERROR_UNREF(error);
}
}
@@ -425,8 +431,16 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
if (!tcp_flush(tcp, &error)) {
TCP_REF(tcp, "write");
tcp->write_cb = cb;
+ if (grpc_tcp_trace) {
+ gpr_log(GPR_DEBUG, "write: delayed");
+ }
grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
} else {
+ if (grpc_tcp_trace) {
+ const char *str = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "write: %s", str);
+ grpc_error_free_string(str);
+ }
grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
}
diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h
index 7156e490d7..5b96d1d851 100644
--- a/src/core/lib/iomgr/workqueue.h
+++ b/src/core/lib/iomgr/workqueue.h
@@ -40,20 +40,12 @@
#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
/* grpc_workqueue is forward declared in exec_ctx.h */
-/* Deprecated: do not use.
- This has *already* been removed in a future commit. */
-void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
-
/* Reference counting functions. Use the macro's always
(GRPC_WORKQUEUE_{REF,UNREF}).
@@ -62,20 +54,20 @@ void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
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 e0d6dac230..0000000000
--- a/src/core/lib/iomgr/workqueue_posix.c
+++ /dev/null
@@ -1,151 +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"
-
-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_mu_init(&(*workqueue)->mu);
- (*workqueue)->closure_list.head = (*workqueue)->closure_list.tail = NULL;
- 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);
- 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_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
- grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd);
-}
-
-#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
-void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
- const char *reason) {
- 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);
-#else
-void grpc_workqueue_ref(grpc_workqueue *workqueue) {
-#endif
- gpr_ref(&workqueue->refs);
-}
-
-#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) {
- 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);
-#else
-void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
-#endif
- if (gpr_unref(&workqueue->refs)) {
- workqueue_destroy(exec_ctx, workqueue);
- }
-}
-
-void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
- gpr_mu_lock(&workqueue->mu);
- grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
- gpr_mu_unlock(&workqueue->mu);
-}
-
-static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
- grpc_workqueue *workqueue = arg;
-
- if (error != GRPC_ERROR_NONE) {
- gpr_mu_destroy(&workqueue->mu);
- /* 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_free(workqueue);
- } else {
- gpr_mu_lock(&workqueue->mu);
- grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
- error = grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd);
- gpr_mu_unlock(&workqueue->mu);
- 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);
- }
- }
-}
-
-void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
- grpc_closure *closure, grpc_error *error) {
- grpc_error *push_error = GRPC_ERROR_NONE;
- gpr_mu_lock(&workqueue->mu);
- if (grpc_closure_list_empty(workqueue->closure_list)) {
- push_error = grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
- }
- grpc_closure_list_append(&workqueue->closure_list, closure, error);
- if (push_error != GRPC_ERROR_NONE) {
- const char *msg = grpc_error_string(push_error);
- gpr_log(GPR_ERROR, "Failed to push to workqueue: %s", msg);
- grpc_error_free_string(msg);
- grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
- }
- gpr_mu_unlock(&workqueue->mu);
-}
-
-#endif /* GPR_POSIX_SOCKET */
diff --git a/src/core/lib/iomgr/workqueue_windows.c b/src/core/lib/iomgr/workqueue_windows.c
index 23e2dea185..5c93d3c59e 100644
--- a/src/core/lib/iomgr/workqueue_windows.c
+++ b/src/core/lib/iomgr/workqueue_windows.c
@@ -42,15 +42,17 @@
// context, which is at least correct, if not performant or in the spirit of
// workqueues.
-void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
-
#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
-void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
- const char *reason) {}
+grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file,
+ int line, const char *reason) {
+ return workqueue;
+}
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
const char *file, int line, const char *reason) {}
#else
-void grpc_workqueue_ref(grpc_workqueue *workqueue) {}
+grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue) {
+ return workqueue;
+}
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
#endif
diff --git a/src/core/lib/profiling/basic_timers.c b/src/core/lib/profiling/basic_timers.c
index 51813d0461..bdf9af2339 100644
--- a/src/core/lib/profiling/basic_timers.c
+++ b/src/core/lib/profiling/basic_timers.c
@@ -83,6 +83,7 @@ static int g_shutdown;
static gpr_thd_id g_writing_thread;
static __thread int g_thread_id;
static int g_next_thread_id;
+static int g_writing_enabled = 1;
static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) {
if (list->head == NULL) {
@@ -177,7 +178,7 @@ static void flush_logs(gpr_timer_log_list *list) {
}
}
-static void finish_writing() {
+static void finish_writing(void) {
pthread_mutex_lock(&g_mu);
g_shutdown = 1;
pthread_cond_signal(&g_cv);
@@ -230,6 +231,10 @@ static void gpr_timers_log_add(const char *tagstr, marker_type type,
int important, const char *file, int line) {
gpr_timer_entry *entry;
+ if (!g_writing_enabled) {
+ return;
+ }
+
if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) {
rotate_log();
}
@@ -261,6 +266,8 @@ void gpr_timer_end(const char *tagstr, int important, const char *file,
gpr_timers_log_add(tagstr, END, important, file, line);
}
+void gpr_timer_set_enabled(int enabled) { g_writing_enabled = enabled; }
+
/* Basic profiler specific API functions. */
void gpr_timers_global_init(void) {}
@@ -272,4 +279,6 @@ void gpr_timers_global_init(void) {}
void gpr_timers_global_destroy(void) {}
void gpr_timers_set_log_filename(const char *filename) {}
+
+void gpr_timer_set_enabled(int enabled) {}
#endif /* GRPC_BASIC_PROFILER */
diff --git a/src/core/lib/profiling/timers.h b/src/core/lib/profiling/timers.h
index c8567e8137..621cdbf656 100644
--- a/src/core/lib/profiling/timers.h
+++ b/src/core/lib/profiling/timers.h
@@ -50,6 +50,8 @@ void gpr_timer_end(const char *tagstr, int important, const char *file,
void gpr_timers_set_log_filename(const char *filename);
+void gpr_timer_set_enabled(int enabled);
+
#if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
/* No profiling. No-op all the things. */
#define GPR_TIMER_MARK(tag, important) \
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.c b/src/core/lib/security/credentials/plugin/plugin_credentials.c
index 824ff081dc..905de3723e 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.c
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.c
@@ -37,6 +37,7 @@
#include "src/core/lib/surface/api_trace.h"
+#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
@@ -71,17 +72,33 @@ static void plugin_md_request_metadata_ready(void *request,
error_details);
} else {
size_t i;
+ bool seen_illegal_header = false;
grpc_credentials_md *md_array = NULL;
- if (num_md > 0) {
+ for (i = 0; i < num_md; i++) {
+ if (!grpc_header_key_is_legal(md[i].key, strlen(md[i].key))) {
+ gpr_log(GPR_ERROR, "Plugin added invalid metadata key: %s", md[i].key);
+ seen_illegal_header = true;
+ break;
+ } else if (!grpc_is_binary_header(md[i].key, strlen(md[i].key)) &&
+ !grpc_header_nonbin_value_is_legal(md[i].value,
+ md[i].value_length)) {
+ gpr_log(GPR_ERROR, "Plugin added invalid metadata value.");
+ seen_illegal_header = true;
+ break;
+ }
+ }
+ if (seen_illegal_header) {
+ r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR,
+ "Illegal metadata");
+ } else if (num_md > 0) {
md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md));
for (i = 0; i < num_md; i++) {
md_array[i].key = gpr_slice_from_copied_string(md[i].key);
md_array[i].value =
gpr_slice_from_copied_buffer(md[i].value, md[i].value_length);
}
- }
- r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK, NULL);
- if (md_array != NULL) {
+ r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK,
+ NULL);
for (i = 0; i < num_md; i++) {
gpr_slice_unref(md_array[i].key);
gpr_slice_unref(md_array[i].value);
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index 2a1bf4d4e3..b366d1410f 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -40,6 +40,7 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/transport/security_connector.h"
@@ -218,6 +219,8 @@ static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data,
static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op *op) {
+ GPR_TIMER_BEGIN("auth_start_transport_op", 0);
+
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
@@ -258,12 +261,14 @@ static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector_check_call_host(
exec_ctx, chand->security_connector, call_host, chand->auth_context,
on_host_checked, elem);
+ GPR_TIMER_END("auth_start_transport_op", 0);
return; /* early exit */
}
}
/* pass control down the stack */
grpc_call_next_op(exec_ctx, elem, op);
+ GPR_TIMER_END("auth_start_transport_op", 0);
}
/* Constructor for call_data */
diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c
index 0169ccd9ef..acb0113ea8 100644
--- a/src/core/lib/security/transport/secure_endpoint.c
+++ b/src/core/lib/security/transport/secure_endpoint.c
@@ -38,6 +38,7 @@
#include <grpc/support/slice_buffer.h>
#include <grpc/support/sync.h>
#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/security/transport/tsi_error.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/tsi/transport_security_interface.h"
@@ -248,6 +249,8 @@ static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur,
static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
gpr_slice_buffer *slices, grpc_closure *cb) {
+ GPR_TIMER_BEGIN("secure_endpoint.endpoint_write", 0);
+
unsigned i;
tsi_result result = TSI_OK;
secure_endpoint *ep = (secure_endpoint *)secure_ep;
@@ -323,10 +326,12 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
exec_ctx, cb,
grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result),
NULL);
+ GPR_TIMER_END("secure_endpoint.endpoint_write", 0);
return;
}
grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb);
+ GPR_TIMER_END("secure_endpoint.endpoint_write", 0);
}
static void endpoint_shutdown(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index def16c8229..b2c6815af8 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -48,7 +48,7 @@ typedef struct call_data {
up-call on transport_op, and remember to call our on_done_recv member after
handling it. */
grpc_closure auth_on_recv;
- grpc_transport_stream_op transport_op;
+ grpc_transport_stream_op *transport_op;
grpc_metadata_array md;
const grpc_metadata *consumed_md;
size_t num_consumed_md;
@@ -106,6 +106,10 @@ static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) {
return md;
}
+static void destroy_op(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+ gpr_free(arg);
+}
+
/* called from application code */
static void on_md_processing_done(
void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md,
@@ -131,21 +135,22 @@ static void on_md_processing_done(
grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE, NULL);
} else {
gpr_slice message;
- grpc_transport_stream_op close_op;
- memset(&close_op, 0, sizeof(close_op));
+ grpc_transport_stream_op *close_op = gpr_malloc(sizeof(*close_op));
+ memset(close_op, 0, sizeof(*close_op));
grpc_metadata_array_destroy(&calld->md);
error_details = error_details != NULL
? error_details
: "Authentication metadata processing failed.";
message = gpr_slice_from_copied_string(error_details);
- calld->transport_op.send_initial_metadata = NULL;
- if (calld->transport_op.send_message != NULL) {
- grpc_byte_stream_destroy(&exec_ctx, calld->transport_op.send_message);
- calld->transport_op.send_message = NULL;
+ calld->transport_op->send_initial_metadata = NULL;
+ if (calld->transport_op->send_message != NULL) {
+ grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message);
+ calld->transport_op->send_message = NULL;
}
- calld->transport_op.send_trailing_metadata = NULL;
- grpc_transport_stream_op_add_close(&close_op, status, &message);
- grpc_call_next_op(&exec_ctx, elem, &close_op);
+ calld->transport_op->send_trailing_metadata = NULL;
+ close_op->on_complete = grpc_closure_create(destroy_op, close_op);
+ grpc_transport_stream_op_add_close(close_op, status, &message);
+ grpc_call_next_op(&exec_ctx, elem, close_op);
grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv,
grpc_error_set_int(GRPC_ERROR_CREATE(error_details),
GRPC_ERROR_INT_GRPC_STATUS, status),
@@ -182,7 +187,7 @@ static void set_recv_ops_md_callbacks(grpc_call_element *elem,
calld->recv_initial_metadata = op->recv_initial_metadata;
calld->on_done_recv = op->recv_initial_metadata_ready;
op->recv_initial_metadata_ready = &calld->auth_on_recv;
- calld->transport_op = *op;
+ calld->transport_op = op;
}
}
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/mpscq.c b/src/core/lib/support/mpscq.c
new file mode 100644
index 0000000000..5b9323275a
--- /dev/null
+++ b/src/core/lib/support/mpscq.c
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/mpscq.h"
+
+#include <grpc/support/log.h>
+
+void gpr_mpscq_init(gpr_mpscq *q) {
+ gpr_atm_no_barrier_store(&q->head, (gpr_atm)&q->stub);
+ q->tail = &q->stub;
+ gpr_atm_no_barrier_store(&q->stub.next, (gpr_atm)NULL);
+}
+
+void gpr_mpscq_destroy(gpr_mpscq *q) {
+ GPR_ASSERT(gpr_atm_no_barrier_load(&q->head) == (gpr_atm)&q->stub);
+ GPR_ASSERT(q->tail == &q->stub);
+}
+
+void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n) {
+ gpr_atm_no_barrier_store(&n->next, (gpr_atm)NULL);
+ gpr_mpscq_node *prev =
+ (gpr_mpscq_node *)gpr_atm_full_xchg(&q->head, (gpr_atm)n);
+ gpr_atm_rel_store(&prev->next, (gpr_atm)n);
+}
+
+gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) {
+ gpr_mpscq_node *tail = q->tail;
+ gpr_mpscq_node *next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next);
+ if (tail == &q->stub) {
+ // indicates the list is actually (ephemerally) empty
+ if (next == NULL) return NULL;
+ q->tail = next;
+ tail = next;
+ next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next);
+ }
+ if (next != NULL) {
+ q->tail = next;
+ return tail;
+ }
+ gpr_mpscq_node *head = (gpr_mpscq_node *)gpr_atm_acq_load(&q->head);
+ if (tail != head) {
+ // indicates a retry is in order: we're still adding
+ return NULL;
+ }
+ gpr_mpscq_push(q, &q->stub);
+ next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next);
+ if (next != NULL) {
+ q->tail = next;
+ return tail;
+ }
+ // indicates a retry is in order: we're still adding
+ return NULL;
+}
diff --git a/src/core/lib/iomgr/workqueue_posix.h b/src/core/lib/support/mpscq.h
index 0f26ba58e2..977a117952 100644
--- a/src/core/lib/iomgr/workqueue_posix.h
+++ b/src/core/lib/support/mpscq.h
@@ -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,28 +31,35 @@
*
*/
-#ifndef GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H
-#define GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H
+#ifndef GRPC_CORE_LIB_SUPPORT_MPSCQ_H
+#define GRPC_CORE_LIB_SUPPORT_MPSCQ_H
-#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+#include <grpc/support/atm.h>
+#include <stddef.h>
-struct grpc_fd;
+// Multiple-producer single-consumer lock free queue, based upon the
+// implementation from Dmitry Vyukov here:
+// http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
-struct grpc_workqueue {
- gpr_refcount refs;
+// List node (include this in a data structure at the top, and add application
+// fields after it - to simulate inheritance)
+typedef struct gpr_mpscq_node { gpr_atm next; } gpr_mpscq_node;
- gpr_mu mu;
- grpc_closure_list closure_list;
+// Actual queue type
+typedef struct gpr_mpscq {
+ gpr_atm head;
+ // make sure head & tail don't share a cacheline
+ char padding[GPR_CACHELINE_SIZE];
+ gpr_mpscq_node *tail;
+ gpr_mpscq_node stub;
+} gpr_mpscq;
- grpc_wakeup_fd wakeup_fd;
- struct grpc_fd *wakeup_read_fd;
+void gpr_mpscq_init(gpr_mpscq *q);
+void gpr_mpscq_destroy(gpr_mpscq *q);
+// Push a node
+void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n);
+// Pop a node (returns NULL if no node is ready - which doesn't indicate that
+// the queue is empty!!)
+gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q);
- 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 */
+#endif /* GRPC_CORE_LIB_SUPPORT_MPSCQ_H */
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 772681109a..6b2badf71b 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -109,6 +109,10 @@ typedef struct batch_control {
uint8_t recv_message;
uint8_t recv_final_op;
uint8_t is_notify_tag_closure;
+
+ /* TODO(ctiller): now that this is inlined, figure out how much of the above
+ state can be eliminated */
+ grpc_transport_stream_op op;
} batch_control;
struct grpc_call {
@@ -226,33 +230,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++) {
@@ -261,78 +265,79 @@ grpc_call *grpc_call_create(
}
}
call->send_deadline =
- gpr_convert_clock_type(send_deadline, GPR_CLOCK_MONOTONIC);
- GRPC_CHANNEL_INTERNAL_REF(channel, "call");
+ gpr_convert_clock_type(args->send_deadline, GPR_CLOCK_MONOTONIC);
+ 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, CALL_STACK_FROM_CALL(call));
+ args->server_transport_data, CALL_STACK_FROM_CALL(call));
if (error != GRPC_ERROR_NONE) {
intptr_t status;
- if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status))
+ if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status)) {
status = GRPC_STATUS_UNKNOWN;
+ }
const char *error_str =
grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION);
close_with_status(&exec_ctx, call, (grpc_status_code)status,
error_str == NULL ? "unknown error" : error_str);
- GRPC_ERROR_UNREF(error);
}
- if (cq != NULL) {
+ if (args->cq != NULL) {
GPR_ASSERT(
- pollset_set_alternative == NULL &&
+ args->pollset_set_alternative == NULL &&
"Only one of 'cq' and 'pollset_set_alternative' should be non-NULL.");
- GRPC_CQ_INTERNAL_REF(cq, "bind");
+ GRPC_CQ_INTERNAL_REF(args->cq, "bind");
call->pollent =
- grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq));
+ grpc_polling_entity_create_from_pollset(grpc_cq_pollset(args->cq));
}
- if (pollset_set_alternative != NULL) {
- call->pollent =
- grpc_polling_entity_create_from_pollset_set(pollset_set_alternative);
+ if (args->pollset_set_alternative != NULL) {
+ call->pollent = grpc_polling_entity_create_from_pollset_set(
+ args->pollset_set_alternative);
}
if (!grpc_polling_entity_is_empty(&call->pollent)) {
grpc_call_stack_set_pollset_or_pollset_set(
&exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
}
- if (parent_call != NULL) {
- GRPC_CALL_INTERNAL_REF(parent_call, "child");
+ gpr_timespec send_deadline = args->send_deadline;
+ 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);
}
if (gpr_time_cmp(send_deadline, gpr_inf_future(send_deadline.clock_type)) !=
0) {
@@ -340,7 +345,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,
@@ -778,6 +783,7 @@ typedef struct termination_closure {
grpc_error *error;
grpc_closure *op_closure;
enum { TC_CANCEL, TC_CLOSE } type;
+ grpc_transport_stream_op op;
} termination_closure;
static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
@@ -797,26 +803,24 @@ static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
}
static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
- grpc_transport_stream_op op;
termination_closure *tc = tcp;
- memset(&op, 0, sizeof(op));
- op.cancel_error = tc->error;
+ memset(&tc->op, 0, sizeof(tc->op));
+ tc->op.cancel_error = tc->error;
/* reuse closure to catch completion */
grpc_closure_init(&tc->closure, done_termination, tc);
- op.on_complete = &tc->closure;
- execute_op(exec_ctx, tc->call, &op);
+ tc->op.on_complete = &tc->closure;
+ execute_op(exec_ctx, tc->call, &tc->op);
}
static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
- grpc_transport_stream_op op;
termination_closure *tc = tcp;
- memset(&op, 0, sizeof(op));
- op.close_error = tc->error;
+ memset(&tc->op, 0, sizeof(tc->op));
+ tc->op.close_error = tc->error;
/* reuse closure to catch completion */
grpc_closure_init(&tc->closure, done_termination, tc);
- tc->op_closure = op.on_complete;
- op.on_complete = &tc->closure;
- execute_op(exec_ctx, tc->call, &op);
+ tc->op_closure = tc->op.on_complete;
+ tc->op.on_complete = &tc->closure;
+ execute_op(exec_ctx, tc->call, &tc->op);
}
static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
@@ -1086,9 +1090,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 &
@@ -1097,7 +1106,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);
}
}
@@ -1160,17 +1169,6 @@ static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl,
if (gpr_unref(&bctl->steps_to_complete)) {
post_batch_completion(exec_ctx, bctl);
}
- } else if (call->receiving_stream->length >
- grpc_channel_get_max_message_length(call->channel)) {
- cancel_with_status(exec_ctx, call, GRPC_STATUS_INTERNAL,
- "Max message size exceeded");
- grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
- call->receiving_stream = NULL;
- *call->receiving_buffer = NULL;
- call->receiving_message = 0;
- if (gpr_unref(&bctl->steps_to_complete)) {
- post_batch_completion(exec_ctx, bctl);
- }
} else {
call->test_only_last_message_flags = call->receiving_stream->flags;
if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
@@ -1254,6 +1252,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;
@@ -1261,9 +1267,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);
@@ -1356,8 +1361,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);
@@ -1370,7 +1374,6 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
grpc_call *call, const grpc_op *ops,
size_t nops, void *notify_tag,
int is_notify_tag_closure) {
- grpc_transport_stream_op stream_op;
size_t i;
const grpc_op *op;
batch_control *bctl;
@@ -1384,8 +1387,6 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag);
- memset(&stream_op, 0, sizeof(stream_op));
-
/* TODO(ctiller): this feels like it could be made lock-free */
gpr_mu_lock(&call->mu);
bctl = allocate_batch_control(call);
@@ -1394,6 +1395,10 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
bctl->notify_tag = notify_tag;
bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
+ 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");
bctl->error = GRPC_ERROR_NONE;
@@ -1471,9 +1476,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
}
/* TODO(ctiller): just make these the same variable? */
call->metadata_batch[0][0].deadline = call->send_deadline;
- stream_op.send_initial_metadata =
+ stream_op->send_initial_metadata =
&call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */];
- stream_op.send_initial_metadata_flags = op->flags;
+ stream_op->send_initial_metadata_flags = op->flags;
break;
case GRPC_OP_SEND_MESSAGE:
if (!are_write_flags_valid(op->flags)) {
@@ -1493,7 +1498,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
grpc_slice_buffer_stream_init(
&call->sending_stream,
&op->data.send_message->data.raw.slice_buffer, op->flags);
- stream_op.send_message = &call->sending_stream.base;
+ stream_op->send_message = &call->sending_stream.base;
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
/* Flag validation: currently allow no flags */
@@ -1511,7 +1516,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
}
bctl->send_final_op = 1;
call->sent_final_op = 1;
- stream_op.send_trailing_metadata =
+ stream_op->send_trailing_metadata =
&call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
@@ -1558,7 +1563,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
- stream_op.send_trailing_metadata =
+ stream_op->send_trailing_metadata =
&call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
break;
case GRPC_OP_RECV_INITIAL_METADATA:
@@ -1576,9 +1581,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
grpc_closure_init(&call->receiving_initial_metadata_ready,
receiving_initial_metadata_ready, bctl);
bctl->recv_initial_metadata = 1;
- stream_op.recv_initial_metadata =
+ stream_op->recv_initial_metadata =
&call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
- stream_op.recv_initial_metadata_ready =
+ stream_op->recv_initial_metadata_ready =
&call->receiving_initial_metadata_ready;
num_completion_callbacks_needed++;
break;
@@ -1595,10 +1600,10 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->receiving_message = 1;
bctl->recv_message = 1;
call->receiving_buffer = op->data.recv_message;
- stream_op.recv_message = &call->receiving_stream;
+ stream_op->recv_message = &call->receiving_stream;
grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready,
bctl);
- stream_op.recv_message_ready = &call->receiving_stream_ready;
+ stream_op->recv_message_ready = &call->receiving_stream_ready;
num_completion_callbacks_needed++;
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
@@ -1624,9 +1629,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->final_op.client.status_details_capacity =
op->data.recv_status_on_client.status_details_capacity;
bctl->recv_final_op = 1;
- stream_op.recv_trailing_metadata =
+ stream_op->recv_trailing_metadata =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
- stream_op.collect_stats =
+ stream_op->collect_stats =
&call->final_info.stats.transport_stream_stats;
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
@@ -1647,9 +1652,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->final_op.server.cancelled =
op->data.recv_close_on_server.cancelled;
bctl->recv_final_op = 1;
- stream_op.recv_trailing_metadata =
+ stream_op->recv_trailing_metadata =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
- stream_op.collect_stats =
+ stream_op->collect_stats =
&call->final_info.stats.transport_stream_stats;
break;
}
@@ -1661,12 +1666,12 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
}
gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed);
- stream_op.context = call->context;
+ stream_op->context = call->context;
grpc_closure_init(&bctl->finish_batch, finish_batch, bctl);
- stream_op.on_complete = &bctl->finish_batch;
+ stream_op->on_complete = &bctl->finish_batch;
gpr_mu_unlock(&call->mu);
- execute_op(exec_ctx, call, &stream_op);
+ execute_op(exec_ctx, call, stream_op);
done:
GPR_TIMER_END("grpc_call_start_batch", 0);
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 6d2b1c4935..92d783b78d 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -64,7 +64,6 @@ typedef struct registered_call {
struct grpc_channel {
int is_client;
- uint32_t max_message_length;
grpc_compression_options compression_options;
grpc_mdelem *default_authority;
@@ -80,9 +79,6 @@ struct grpc_channel {
#define CHANNEL_FROM_TOP_ELEM(top_elem) \
CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem))
-/* the protobuf library will (by default) start warning at 100megs */
-#define DEFAULT_MAX_MESSAGE_LENGTH (4 * 1024 * 1024)
-
static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error);
@@ -114,21 +110,10 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = NULL;
- channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
grpc_compression_options_init(&channel->compression_options);
if (args) {
for (size_t i = 0; i < args->num_args; i++) {
- if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) {
- if (args->args[i].type != GRPC_ARG_INTEGER) {
- gpr_log(GPR_ERROR, "%s ignored: it must be an integer",
- GRPC_ARG_MAX_MESSAGE_LENGTH);
- } else if (args->args[i].value.integer < 0) {
- gpr_log(GPR_ERROR, "%s ignored: it must be >= 0",
- GRPC_ARG_MAX_MESSAGE_LENGTH);
- } else {
- channel->max_message_length = (uint32_t)args->args[i].value.integer;
- }
- } else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
+ if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
if (args->args[i].type != GRPC_ARG_STRING) {
gpr_log(GPR_ERROR, "%s ignored: it must be a string",
GRPC_ARG_DEFAULT_AUTHORITY);
@@ -208,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,
@@ -334,14 +331,13 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
}
void grpc_channel_destroy(grpc_channel *channel) {
- grpc_transport_op op;
+ grpc_transport_op *op = grpc_make_transport_op(NULL);
grpc_channel_element *elem;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel));
- memset(&op, 0, sizeof(op));
- op.disconnect_with_error = GRPC_ERROR_CREATE("Channel Destroyed");
+ op->disconnect_with_error = GRPC_ERROR_CREATE("Channel Destroyed");
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
- elem->filter->start_transport_op(&exec_ctx, elem, &op);
+ elem->filter->start_transport_op(&exec_ctx, elem, op);
GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "channel");
@@ -371,7 +367,3 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
return grpc_mdelem_from_metadata_strings(GRPC_MDSTR_GRPC_STATUS,
grpc_mdstr_from_string(tmp));
}
-
-uint32_t grpc_channel_get_max_message_length(grpc_channel *channel) {
- return channel->max_message_length;
-}
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 4c62974346..23cc8656ca 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -64,7 +64,6 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
The returned elem is owned by the caller. */
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
int status_code);
-uint32_t grpc_channel_get_max_message_length(grpc_channel *channel);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
diff --git a/src/core/lib/surface/channel_ping.c b/src/core/lib/surface/channel_ping.c
index 9818f9d2f2..0d2f01a649 100644
--- a/src/core/lib/surface/channel_ping.c
+++ b/src/core/lib/surface/channel_ping.c
@@ -61,19 +61,20 @@ static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq,
void *tag, void *reserved) {
- grpc_transport_op op;
+ GRPC_API_TRACE("grpc_channel_ping(channel=%p, cq=%p, tag=%p, reserved=%p)", 4,
+ (channel, cq, tag, reserved));
+ grpc_transport_op *op = grpc_make_transport_op(NULL);
ping_result *pr = gpr_malloc(sizeof(*pr));
grpc_channel_element *top_elem =
grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GPR_ASSERT(reserved == NULL);
- memset(&op, 0, sizeof(op));
pr->tag = tag;
pr->cq = cq;
grpc_closure_init(&pr->closure, ping_done, pr);
- op.send_ping = &pr->closure;
- op.bind_pollset = grpc_cq_pollset(cq);
+ op->send_ping = &pr->closure;
+ op->bind_pollset = grpc_cq_pollset(cq);
grpc_cq_begin_op(cq, tag);
- top_elem->filter->start_transport_op(&exec_ctx, top_elem, &op);
+ top_elem->filter->start_transport_op(&exec_ctx, top_elem, op);
grpc_exec_ctx_finish(&exec_ctx);
}
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 3049284f68..e9d840df77 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 5397913a21..3cbbaa7b0c 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -45,8 +45,10 @@
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/channel/http_client_filter.h"
#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/channel/message_size_filter.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/http/parser.h"
+#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/profiling/timers.h"
@@ -98,6 +100,15 @@ static bool maybe_add_http_filter(grpc_channel_stack_builder *builder,
static void register_builtin_channel_init() {
grpc_channel_init_register_stage(
+ GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+ prepend_filter, (void *)&grpc_message_size_filter);
+ grpc_channel_init_register_stage(
+ GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
+ prepend_filter, (void *)&grpc_message_size_filter);
+ grpc_channel_init_register_stage(
+ GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
+ (void *)&grpc_message_size_filter);
+ grpc_channel_init_register_stage(
GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, prepend_filter,
(void *)&grpc_compress_filter);
grpc_channel_init_register_stage(
@@ -165,12 +176,17 @@ void grpc_init(void) {
grpc_register_tracer("http1", &grpc_http1_trace);
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/lame_client.c b/src/core/lib/surface/lame_client.c
index 19b78369dd..d32c884e8e 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -97,14 +97,14 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx_sched(exec_ctx, op->on_connectivity_state_change,
GRPC_ERROR_NONE, NULL);
}
- if (op->on_consumed != NULL) {
- grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
- }
if (op->send_ping != NULL) {
grpc_exec_ctx_sched(exec_ctx, op->send_ping,
GRPC_ERROR_CREATE("lame client channel"), NULL);
}
GRPC_ERROR_UNREF(op->disconnect_with_error);
+ if (op->on_consumed != NULL) {
+ grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
+ }
}
static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 55e6d99057..cec3e3ce97 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;
@@ -273,23 +275,21 @@ static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg,
}
static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
- bool send_goaway, grpc_error *send_disconnect) {
- grpc_transport_op op;
- struct shutdown_cleanup_args *sc;
+ int send_goaway, grpc_error *send_disconnect) {
+ struct shutdown_cleanup_args *sc = gpr_malloc(sizeof(*sc));
+ grpc_closure_init(&sc->closure, shutdown_cleanup, sc);
+ grpc_transport_op *op = grpc_make_transport_op(&sc->closure);
grpc_channel_element *elem;
- memset(&op, 0, sizeof(op));
- op.send_goaway = send_goaway;
- sc = gpr_malloc(sizeof(*sc));
+ 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;
- op.disconnect_with_error = send_disconnect;
- grpc_closure_init(&sc->closure, shutdown_cleanup, sc);
- op.on_consumed = &sc->closure;
+ op->goaway_message = &sc->slice;
+ op->goaway_status = GRPC_STATUS_OK;
+ op->disconnect_with_error = send_disconnect;
elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
- elem->filter->start_transport_op(exec_ctx, elem, &op);
+ elem->filter->start_transport_op(exec_ctx, elem, op);
}
static void channel_broadcaster_shutdown(grpc_exec_ctx *exec_ctx,
@@ -432,7 +432,8 @@ static void finish_destroy_channel(grpc_exec_ctx *exec_ctx, void *cd,
server_unref(exec_ctx, server);
}
-static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) {
+static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand,
+ grpc_error *error) {
if (is_channel_orphaned(chand)) return;
GPR_ASSERT(chand->server != NULL);
orphan_channel(chand);
@@ -441,14 +442,20 @@ 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;
- grpc_transport_op op;
- memset(&op, 0, sizeof(op));
- op.set_accept_stream = true;
- op.on_consumed = &chand->finish_destroy_channel_closure;
+ 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;
grpc_channel_next_op(exec_ctx,
grpc_channel_stack_element(
grpc_channel_get_channel_stack(chand->channel), 0),
- &op);
+ op);
}
static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
@@ -769,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,
@@ -825,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));
@@ -845,17 +860,16 @@ static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd,
channel_data *chand = cd;
grpc_server *server = chand->server;
if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
- grpc_transport_op op;
- memset(&op, 0, sizeof(op));
- op.on_connectivity_state_change = &chand->channel_connectivity_changed,
- op.connectivity_state = &chand->connectivity_state;
+ grpc_transport_op *op = grpc_make_transport_op(NULL);
+ op->on_connectivity_state_change = &chand->channel_connectivity_changed,
+ op->connectivity_state = &chand->connectivity_state;
grpc_channel_next_op(exec_ctx,
grpc_channel_stack_element(
grpc_channel_get_channel_stack(chand->channel), 0),
- &op);
+ op);
} else {
gpr_mu_lock(&server->mu_global);
- destroy_channel(exec_ctx, chand);
+ destroy_channel(exec_ctx, chand, GRPC_ERROR_REF(error));
gpr_mu_unlock(&server->mu_global);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "connectivity");
}
@@ -1119,7 +1133,7 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
size_t slots;
uint32_t probes;
uint32_t max_probes = 0;
- grpc_transport_op op;
+ grpc_transport_op *op = NULL;
channel =
grpc_channel_create(exec_ctx, NULL, args, GRPC_SERVER_CHANNEL, transport);
@@ -1179,16 +1193,16 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
gpr_mu_unlock(&s->mu_global);
GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity");
- memset(&op, 0, sizeof(op));
- op.set_accept_stream = true;
- op.set_accept_stream_fn = accept_stream;
- op.set_accept_stream_user_data = chand;
- op.on_connectivity_state_change = &chand->channel_connectivity_changed;
- op.connectivity_state = &chand->connectivity_state;
+ op = grpc_make_transport_op(NULL);
+ op->set_accept_stream = true;
+ op->set_accept_stream_fn = accept_stream;
+ op->set_accept_stream_user_data = chand;
+ op->on_connectivity_state_change = &chand->channel_connectivity_changed;
+ op->connectivity_state = &chand->connectivity_state;
if (gpr_atm_acq_load(&s->shutdown_flag) != 0) {
- op.disconnect_with_error = GRPC_ERROR_CREATE("Server shutdown");
+ op->disconnect_with_error = GRPC_ERROR_CREATE("Server shutdown");
}
- grpc_transport_perform_op(exec_ctx, transport, &op);
+ grpc_transport_perform_op(exec_ctx, transport, op);
}
void done_published_shutdown(grpc_exec_ctx *exec_ctx, void *done_arg,
diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h
index fb6e4d60c5..2a4e65c7ce 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/metadata.c b/src/core/lib/transport/metadata.c
index 0677f29766..4b40c275ad 100644
--- a/src/core/lib/transport/metadata.c
+++ b/src/core/lib/transport/metadata.c
@@ -278,7 +278,7 @@ static void ref_md_locked(mdtab_shard *shard,
internal_metadata *md DEBUG_ARGS) {
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "ELM REF:%p:%d->%d: '%s' = '%s'", md,
+ "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
gpr_atm_no_barrier_load(&md->refcnt),
gpr_atm_no_barrier_load(&md->refcnt) + 1,
grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
@@ -566,7 +566,7 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey,
shard->elems[idx] = md;
gpr_mu_init(&md->mu_user_data);
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
- gpr_log(GPR_DEBUG, "ELM NEW:%p:%d: '%s' = '%s'", md,
+ gpr_log(GPR_DEBUG, "ELM NEW:%p:%zu: '%s' = '%s'", (void *)md,
gpr_atm_no_barrier_load(&md->refcnt),
grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
@@ -639,7 +639,7 @@ grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
if (is_mdelem_static(gmd)) return gmd;
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "ELM REF:%p:%d->%d: '%s' = '%s'", md,
+ "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
gpr_atm_no_barrier_load(&md->refcnt),
gpr_atm_no_barrier_load(&md->refcnt) + 1,
grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
@@ -649,7 +649,7 @@ grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
this function - meaning that no adjustment to mdtab_free is necessary,
simplifying the logic here to be just an atomic increment */
/* use C assert to have this removed in opt builds */
- assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
+ GPR_ASSERT(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
return gmd;
}
@@ -660,14 +660,16 @@ void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
if (is_mdelem_static(gmd)) return;
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
+ "ELM UNREF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
gpr_atm_no_barrier_load(&md->refcnt),
gpr_atm_no_barrier_load(&md->refcnt) - 1,
grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
- if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
+ const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1);
+ GPR_ASSERT(prev_refcount >= 1);
+ if (1 == prev_refcount) {
/* once the refcount hits zero, some other thread can come along and
free md at any time: it's unsafe from this point on to access it */
mdtab_shard *shard =
@@ -676,10 +678,12 @@ void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
}
}
-const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
+const char *grpc_mdstr_as_c_string(const grpc_mdstr *s) {
return (const char *)GPR_SLICE_START_PTR(s->slice);
}
+size_t grpc_mdstr_length(const grpc_mdstr *s) { return GRPC_MDSTR_LENGTH(s); }
+
grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
internal_string *s = (internal_string *)gs;
if (is_mdstr_static(gs)) return gs;
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index 2b0921c8d7..71eff0acf2 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -147,7 +147,7 @@ void grpc_mdelem_unref(grpc_mdelem *md);
/* Recover a char* from a grpc_mdstr. The returned string is null terminated.
Does not promise that the returned string has no embedded nulls however. */
-const char *grpc_mdstr_as_c_string(grpc_mdstr *s);
+const char *grpc_mdstr_as_c_string(const grpc_mdstr *s);
#define GRPC_MDSTR_LENGTH(s) (GPR_SLICE_LENGTH(s->slice))
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index 857c3909d2..b951218130 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -32,18 +32,23 @@
*/
#include "src/core/lib/transport/transport.h"
+
+#include <string.h>
+
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
+
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/transport_impl.h"
#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, val, 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
@@ -54,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, val, 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) {
@@ -247,3 +253,51 @@ void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op,
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, status);
add_error(op, &op->close_error, error);
}
+
+typedef struct {
+ grpc_closure outer_on_complete;
+ grpc_closure *inner_on_complete;
+ grpc_transport_op op;
+} made_transport_op;
+
+static void destroy_made_transport_op(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ made_transport_op *op = arg;
+ grpc_exec_ctx_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error),
+ NULL);
+ gpr_free(op);
+}
+
+grpc_transport_op *grpc_make_transport_op(grpc_closure *on_complete) {
+ made_transport_op *op = gpr_malloc(sizeof(*op));
+ grpc_closure_init(&op->outer_on_complete, destroy_made_transport_op, op);
+ op->inner_on_complete = on_complete;
+ memset(&op->op, 0, sizeof(op->op));
+ 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 26ed6cb839..50253ebad1 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -100,6 +100,11 @@ void grpc_transport_move_one_way_stats(grpc_transport_one_way_stats *from,
void grpc_transport_move_stats(grpc_transport_stream_stats *from,
grpc_transport_stream_stats *to);
+typedef struct {
+ grpc_closure closure;
+ void *args[2];
+} grpc_transport_private_op_data;
+
/* Transport stream op: a set of operations to perform on a transport
against a single stream */
typedef struct grpc_transport_stream_op {
@@ -108,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;
@@ -149,6 +158,12 @@ typedef struct grpc_transport_stream_op {
/* Indexes correspond to grpc_context_index enum values */
grpc_call_context_element *context;
+
+ /***************************************************************************
+ * remaining fields are initialized and used at the discretion of the
+ * transport implementation */
+
+ grpc_transport_private_op_data transport_private;
} grpc_transport_stream_op;
/** Transport op: a set of operations to perform on a transport as a whole */
@@ -182,6 +197,12 @@ typedef struct grpc_transport_op {
grpc_pollset_set *bind_pollset_set;
/** send a ping, call this back if not NULL */
grpc_closure *send_ping;
+
+ /***************************************************************************
+ * remaining fields are initialized and used at the discretion of the
+ * transport implementation */
+
+ grpc_transport_private_op_data transport_private;
} grpc_transport_op;
/* Returns the amount of memory required to store a grpc_stream for this
@@ -235,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
@@ -273,6 +295,14 @@ void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, grpc_transport *transport);
char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
grpc_transport *transport);
+/* 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
}
#endif
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
index 138591db2a..f350e55b34 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,14 +73,14 @@ 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;
+ bool first = true;
gpr_strvec b;
gpr_strvec_init(&b);
if (op->send_initial_metadata != NULL) {
if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
- first = 0;
+ first = false;
gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{"));
put_metadata_list(&b, *op->send_initial_metadata);
gpr_strvec_add(&b, gpr_strdup("}"));
@@ -87,7 +88,7 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
if (op->send_message != NULL) {
if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
- first = 0;
+ first = false;
gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d",
op->send_message->flags, op->send_message->length);
gpr_strvec_add(&b, tmp);
@@ -95,7 +96,7 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
if (op->send_trailing_metadata != NULL) {
if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
- first = 0;
+ first = false;
gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{"));
put_metadata_list(&b, *op->send_trailing_metadata);
gpr_strvec_add(&b, gpr_strdup("}"));
@@ -103,25 +104,25 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
if (op->recv_initial_metadata != NULL) {
if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
- first = 0;
+ first = false;
gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA"));
}
if (op->recv_message != NULL) {
if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
- first = 0;
+ first = false;
gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE"));
}
if (op->recv_trailing_metadata != NULL) {
if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
- first = 0;
+ first = false;
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;
+ first = false;
const char *msg = grpc_error_string(op->cancel_error);
gpr_asprintf(&tmp, "CANCEL:%s", msg);
grpc_error_free_string(msg);
@@ -130,7 +131,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;
+ first = false;
const char *msg = grpc_error_string(op->close_error);
gpr_asprintf(&tmp, "CLOSE:%s", msg);
grpc_error_free_string(msg);
@@ -143,6 +144,82 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
return out;
}
+char *grpc_transport_op_string(grpc_transport_op *op) {
+ char *tmp;
+ char *out;
+ bool first = true;
+
+ gpr_strvec b;
+ gpr_strvec_init(&b);
+
+ if (op->on_connectivity_state_change != NULL) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = false;
+ if (op->connectivity_state != NULL) {
+ gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:from=%s",
+ op->on_connectivity_state_change,
+ grpc_connectivity_state_name(*op->connectivity_state));
+ gpr_strvec_add(&b, tmp);
+ } else {
+ gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:unsubscribe",
+ op->on_connectivity_state_change);
+ gpr_strvec_add(&b, tmp);
+ }
+ }
+
+ if (op->disconnect_with_error != GRPC_ERROR_NONE) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = false;
+ const char *err = grpc_error_string(op->disconnect_with_error);
+ gpr_asprintf(&tmp, "DISCONNECT:%s", err);
+ gpr_strvec_add(&b, tmp);
+ grpc_error_free_string(err);
+ }
+
+ if (op->send_goaway) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = false;
+ char *msg = op->goaway_message == NULL
+ ? "null"
+ : gpr_dump_slice(*op->goaway_message,
+ GPR_DUMP_ASCII | GPR_DUMP_HEX);
+ gpr_asprintf(&tmp, "SEND_GOAWAY:status=%d:msg=%s", op->goaway_status, msg);
+ if (op->goaway_message != NULL) gpr_free(msg);
+ gpr_strvec_add(&b, tmp);
+ }
+
+ if (op->set_accept_stream) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = false;
+ gpr_asprintf(&tmp, "SET_ACCEPT_STREAM:%p(%p,...)", op->set_accept_stream_fn,
+ op->set_accept_stream_user_data);
+ gpr_strvec_add(&b, tmp);
+ }
+
+ if (op->bind_pollset != NULL) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = false;
+ gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET"));
+ }
+
+ if (op->bind_pollset_set != NULL) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = false;
+ gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET_SET"));
+ }
+
+ if (op->send_ping != NULL) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = false;
+ gpr_strvec_add(&b, gpr_strdup("SEND_PING"));
+ }
+
+ out = gpr_strvec_flatten(&b, NULL);
+ gpr_strvec_destroy(&b);
+
+ return out;
+}
+
void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
grpc_call_element *elem, grpc_transport_stream_op *op) {
char *str = grpc_transport_stream_op_string(op);
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 1a014da3b8..2980b16c56 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -52,7 +52,9 @@ static void do_plugin_list_init(void) {
}
ServerBuilder::ServerBuilder()
- : max_message_size_(-1), generic_service_(nullptr) {
+ : max_receive_message_size_(-1),
+ max_send_message_size_(-1),
+ generic_service_(nullptr) {
gpr_once_init(&once_init_plugin_list, do_plugin_list_init);
for (auto it = g_plugin_factory_list->begin();
it != g_plugin_factory_list->end(); it++) {
@@ -160,8 +162,11 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
}
(*plugin)->UpdateChannelArguments(&args);
}
- if (max_message_size_ > 0) {
- args.SetInt(GRPC_ARG_MAX_MESSAGE_LENGTH, max_message_size_);
+ if (max_receive_message_size_ >= 0) {
+ args.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, max_receive_message_size_);
+ }
+ if (max_send_message_size_ >= 0) {
+ args.SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, max_send_message_size_);
}
args.SetInt(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
enabled_compression_algorithms_bitset_);
@@ -173,8 +178,8 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM,
maybe_default_compression_algorithm_.algorithm);
}
- std::unique_ptr<Server> server(
- new Server(thread_pool.release(), true, max_message_size_, &args));
+ std::unique_ptr<Server> server(new Server(thread_pool.release(), true,
+ max_receive_message_size_, &args));
ServerInitializer* initializer = server->initializer();
// If the server has atleast one sync methods, we know that this is a Sync
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index af04fd4ca6..a693ce9b8e 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -220,7 +220,7 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
public:
explicit CallData(Server* server, SyncRequest* mrd)
: cq_(mrd->cq_),
- call_(mrd->call_, server, &cq_, server->max_message_size_),
+ call_(mrd->call_, server, &cq_, server->max_receive_message_size_),
ctx_(mrd->deadline_, mrd->request_metadata_.metadata,
mrd->request_metadata_.count),
has_request_payload_(mrd->has_request_payload_),
@@ -243,7 +243,7 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
ctx_.BeginCompletionOp(&call_);
global_callbacks->PreSynchronousRequest(&ctx_);
method_->handler()->RunHandler(MethodHandler::HandlerParameter(
- &call_, &ctx_, request_payload_, call_.max_message_size()));
+ &call_, &ctx_, request_payload_, call_.max_receive_message_size()));
global_callbacks->PostSynchronousRequest(&ctx_);
request_payload_ = nullptr;
void* ignored_tag;
@@ -277,8 +277,8 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
static internal::GrpcLibraryInitializer g_gli_initializer;
Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned,
- int max_message_size, ChannelArguments* args)
- : max_message_size_(max_message_size),
+ int max_receive_message_size, ChannelArguments* args)
+ : max_receive_message_size_(max_receive_message_size),
started_(false),
shutdown_(false),
shutdown_notified_(false),
@@ -514,7 +514,7 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag,
grpc_metadata_array_destroy(&initial_metadata_array_);
context_->set_call(call_);
context_->cq_ = call_cq_;
- Call call(call_, server_, call_cq_, server_->max_message_size());
+ Call call(call_, server_, call_cq_, server_->max_receive_message_size());
if (*status && call_) {
context_->BeginCompletionOp(&call);
}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
index c35aaf680f..09790120d1 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
@@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
@@ -149,8 +150,7 @@ namespace Grpc.Core.Internal.Tests
var writeTask = responseStream.WriteAsync("request1");
fakeCall.SendCompletionHandler(false);
- // TODO(jtattermusch): should we throw a different exception type instead?
- Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await writeTask);
+ Assert.ThrowsAsync(typeof(IOException), async () => await writeTask);
fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
AssertFinished(asyncCallServer, fakeCall, finishedTask);
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
index 98e27a17a1..616bc06d76 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
@@ -180,21 +180,74 @@ namespace Grpc.Core.Internal.Tests
}
[Test]
- public void ClientStreaming_WriteCompletionFailure()
+ public void ClientStreaming_WriteFailureThrowsRpcException()
{
var resultTask = asyncCall.ClientStreamingCallAsync();
var requestStream = new ClientRequestStream<string, string>(asyncCall);
var writeTask = requestStream.WriteAsync("request1");
fakeCall.SendCompletionHandler(false);
- // TODO: maybe IOException or waiting for RPCException is more appropriate here.
- Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await writeTask);
+
+ // The write will wait for call to finish to receive the status code.
+ Assert.IsFalse(writeTask.IsCompleted);
fakeCall.UnaryResponseClientHandler(true,
CreateClientSideStatus(StatusCode.Internal),
null,
new Metadata());
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
+ Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Internal);
+ }
+
+ [Test]
+ public void ClientStreaming_WriteFailureThrowsRpcException2()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ var writeTask = requestStream.WriteAsync("request1");
+
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.Internal),
+ null,
+ new Metadata());
+
+ fakeCall.SendCompletionHandler(false);
+
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
+ Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
+
+ AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Internal);
+ }
+
+ [Test]
+ public void ClientStreaming_WriteFailureThrowsRpcException3()
+ {
+ var resultTask = asyncCall.ClientStreamingCallAsync();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ fakeCall.SendCompletionHandler(false);
+
+ // Until the delayed write completion has been triggered,
+ // we still act as if there was an active write.
+ Assert.Throws(typeof(InvalidOperationException), () => requestStream.WriteAsync("request2"));
+
+ fakeCall.UnaryResponseClientHandler(true,
+ CreateClientSideStatus(StatusCode.Internal),
+ null,
+ new Metadata());
+
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
+ Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
+
+ // Following attempts to write keep delivering the same status
+ var ex2 = Assert.ThrowsAsync<RpcException>(async () => await requestStream.WriteAsync("after call has finished"));
+ Assert.AreEqual(StatusCode.Internal, ex2.Status.StatusCode);
+
AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Internal);
}
@@ -416,6 +469,49 @@ namespace Grpc.Core.Internal.Tests
}
[Test]
+ public void DuplexStreaming_WriteFailureThrowsRpcException()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var writeTask = requestStream.WriteAsync("request1");
+ fakeCall.SendCompletionHandler(false);
+
+ // The write will wait for call to finish to receive the status code.
+ Assert.IsFalse(writeTask.IsCompleted);
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.PermissionDenied));
+
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
+ Assert.AreEqual(StatusCode.PermissionDenied, ex.Status.StatusCode);
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.PermissionDenied);
+ }
+
+ [Test]
+ public void DuplexStreaming_WriteFailureThrowsRpcException2()
+ {
+ asyncCall.StartDuplexStreamingCall();
+ var requestStream = new ClientRequestStream<string, string>(asyncCall);
+ var responseStream = new ClientResponseStream<string, string>(asyncCall);
+
+ var writeTask = requestStream.WriteAsync("request1");
+
+ var readTask = responseStream.MoveNext();
+ fakeCall.ReceivedMessageHandler(true, null);
+ fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.PermissionDenied));
+ fakeCall.SendCompletionHandler(false);
+
+ var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
+ Assert.AreEqual(StatusCode.PermissionDenied, ex.Status.StatusCode);
+
+ AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.PermissionDenied);
+ }
+
+ [Test]
public void DuplexStreaming_WriteAfterCancellationRequestThrowsTaskCanceledException()
{
asyncCall.StartDuplexStreamingCall();
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index f549c52876..9abaf1120f 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -341,6 +341,11 @@ namespace Grpc.Core.Internal
get { return true; }
}
+ protected override Exception GetRpcExceptionClientOnly()
+ {
+ return new RpcException(finishedStatus.Value.Status);
+ }
+
protected override Task CheckSendAllowedOrEarlyResult()
{
var earlyResult = CheckSendPreconditionsClientSide();
@@ -452,6 +457,7 @@ namespace Grpc.Core.Internal
using (Profilers.ForCurrentThread().NewScope("AsyncCall.HandleUnaryResponse"))
{
+ TaskCompletionSource<object> delayedStreamingWriteTcs = null;
TResponse msg = default(TResponse);
var deserializeException = TryDeserialize(receivedMessage, out msg);
@@ -465,13 +471,23 @@ namespace Grpc.Core.Internal
}
finishedStatus = receivedStatus;
+ if (isStreamingWriteCompletionDelayed)
+ {
+ delayedStreamingWriteTcs = streamingWriteTcs;
+ streamingWriteTcs = null;
+ }
+
ReleaseResourcesIfPossible();
}
responseHeadersTcs.SetResult(responseHeaders);
- var status = receivedStatus.Status;
+ if (delayedStreamingWriteTcs != null)
+ {
+ delayedStreamingWriteTcs.SetException(GetRpcExceptionClientOnly());
+ }
+ var status = receivedStatus.Status;
if (status.StatusCode != StatusCode.OK)
{
unaryResponseTcs.SetException(new RpcException(status));
@@ -490,16 +506,27 @@ namespace Grpc.Core.Internal
// NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT,
// success will be always set to true.
+ TaskCompletionSource<object> delayedStreamingWriteTcs = null;
+
lock (myLock)
{
finished = true;
finishedStatus = receivedStatus;
+ if (isStreamingWriteCompletionDelayed)
+ {
+ delayedStreamingWriteTcs = streamingWriteTcs;
+ streamingWriteTcs = null;
+ }
ReleaseResourcesIfPossible();
}
- var status = receivedStatus.Status;
+ if (delayedStreamingWriteTcs != null)
+ {
+ delayedStreamingWriteTcs.SetException(GetRpcExceptionClientOnly());
+ }
+ var status = receivedStatus.Status;
if (status.StatusCode != StatusCode.OK)
{
streamingCallFinishedTcs.SetException(new RpcException(status));
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index eb9c3ea62d..9f9d260e7e 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -69,6 +69,7 @@ namespace Grpc.Core.Internal
protected TaskCompletionSource<TRead> streamingReadTcs; // Completion of a pending streaming read if not null.
protected TaskCompletionSource<object> streamingWriteTcs; // Completion of a pending streaming write or send close from client if not null.
protected TaskCompletionSource<object> sendStatusFromServerTcs;
+ protected bool isStreamingWriteCompletionDelayed; // Only used for the client side.
protected bool readingDone; // True if last read (i.e. read with null payload) was already received.
protected bool halfcloseRequested; // True if send close have been initiated.
@@ -200,6 +201,12 @@ namespace Grpc.Core.Internal
get;
}
+ /// <summary>
+ /// Returns an exception to throw for a failed send operation.
+ /// It is only allowed to call this method for a call that has already finished.
+ /// </summary>
+ protected abstract Exception GetRpcExceptionClientOnly();
+
private void ReleaseResources()
{
if (call != null)
@@ -252,18 +259,43 @@ namespace Grpc.Core.Internal
/// </summary>
protected void HandleSendFinished(bool success)
{
+ bool delayCompletion = false;
TaskCompletionSource<object> origTcs = null;
lock (myLock)
{
- origTcs = streamingWriteTcs;
- streamingWriteTcs = null;
+ if (!success && !finished && IsClient) {
+ // We should be setting this only once per call, following writes will be short circuited
+ // because they cannot start until the entire call finishes.
+ GrpcPreconditions.CheckState(!isStreamingWriteCompletionDelayed);
+
+ // leave streamingWriteTcs set, it will be completed once call finished.
+ isStreamingWriteCompletionDelayed = true;
+ delayCompletion = true;
+ }
+ else
+ {
+ origTcs = streamingWriteTcs;
+ streamingWriteTcs = null;
+ }
ReleaseResourcesIfPossible();
}
if (!success)
{
- origTcs.SetException(new InvalidOperationException("Send failed"));
+ if (!delayCompletion)
+ {
+ if (IsClient)
+ {
+ GrpcPreconditions.CheckState(finished); // implied by !success && !delayCompletion && IsClient
+ origTcs.SetException(GetRpcExceptionClientOnly());
+ }
+ else
+ {
+ origTcs.SetException (new IOException("Error sending from server."));
+ }
+ }
+ // if delayCompletion == true, postpone SetException until call finishes.
}
else
{
@@ -283,7 +315,7 @@ namespace Grpc.Core.Internal
if (!success)
{
- sendStatusFromServerTcs.SetException(new InvalidOperationException("Error sending status from server."));
+ sendStatusFromServerTcs.SetException(new IOException("Error sending status from server."));
}
else
{
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index 56c23ba3ef..50fdfa9006 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -33,6 +33,7 @@
using System;
using System.Diagnostics;
+using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
@@ -193,6 +194,11 @@ namespace Grpc.Core.Internal
get { return false; }
}
+ protected override Exception GetRpcExceptionClientOnly()
+ {
+ throw new InvalidOperationException("Call be only called for client calls");
+ }
+
protected override void OnAfterReleaseResources()
{
server.RemoveCallReference(this);
diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec
index 31d1bed647..0c937ab9cb 100644
--- a/src/csharp/Grpc.Tools.nuspec
+++ b/src/csharp/Grpc.Tools.nuspec
@@ -16,17 +16,18 @@
<tags>gRPC RPC Protocol HTTP/2</tags>
</metadata>
<files>
- <file src="protoc_plugins\windows_x86\protoc.exe" target="tools\windows_x86\protoc.exe" />
- <file src="protoc_plugins\windows_x86\grpc_csharp_plugin.exe" target="tools\windows_x86\grpc_csharp_plugin.exe" />
- <file src="protoc_plugins\windows_x64\protoc.exe" target="tools\windows_x64\protoc.exe" />
- <file src="protoc_plugins\windows_x64\grpc_csharp_plugin.exe" target="tools\windows_x64\grpc_csharp_plugin.exe" />
- <file src="protoc_plugins\linux_x86\protoc" target="tools\linux_x86\protoc" />
- <file src="protoc_plugins\linux_x86\grpc_csharp_plugin" target="tools\linux_x86\grpc_csharp_plugin" />
- <file src="protoc_plugins\linux_x64\protoc" target="tools\linux_x64\protoc" />
- <file src="protoc_plugins\linux_x64\grpc_csharp_plugin" target="tools\linux_x64\grpc_csharp_plugin" />
- <file src="protoc_plugins\macosx_x86\protoc" target="tools\macosx_x86\protoc" />
- <file src="protoc_plugins\macosx_x86\grpc_csharp_plugin" target="tools\macosx_x86\grpc_csharp_plugin" />
- <file src="protoc_plugins\macosx_x64\protoc" target="tools\macosx_x64\protoc" />
- <file src="protoc_plugins\macosx_x64\grpc_csharp_plugin" target="tools\macosx_x64\grpc_csharp_plugin" />
+ <!-- forward slashes in src path enable building on Linux -->
+ <file src="protoc_plugins/windows_x86/protoc.exe" target="tools\windows_x86\protoc.exe" />
+ <file src="protoc_plugins/windows_x86/grpc_csharp_plugin.exe" target="tools\windows_x86\grpc_csharp_plugin.exe" />
+ <file src="protoc_plugins/windows_x64/protoc.exe" target="tools\windows_x64\protoc.exe" />
+ <file src="protoc_plugins/windows_x64/grpc_csharp_plugin.exe" target="tools\windows_x64\grpc_csharp_plugin.exe" />
+ <file src="protoc_plugins/linux_x86/protoc" target="tools\linux_x86\protoc" />
+ <file src="protoc_plugins/linux_x86/grpc_csharp_plugin" target="tools\linux_x86\grpc_csharp_plugin" />
+ <file src="protoc_plugins/linux_x64/protoc" target="tools\linux_x64\protoc" />
+ <file src="protoc_plugins/linux_x64/grpc_csharp_plugin" target="tools\linux_x64\grpc_csharp_plugin" />
+ <file src="protoc_plugins/macosx_x86/protoc" target="tools\macosx_x86\protoc" />
+ <file src="protoc_plugins/macosx_x86/grpc_csharp_plugin" target="tools\macosx_x86\grpc_csharp_plugin" />
+ <file src="protoc_plugins/macosx_x64/protoc" target="tools\macosx_x64\protoc" />
+ <file src="protoc_plugins/macosx_x64/grpc_csharp_plugin" target="tools\macosx_x64\grpc_csharp_plugin" />
</files>
</package>
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index b92189c840..c0036df13f 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -29,6 +29,10 @@
@rem Builds gRPC NuGet packages
+@rem This way of building nuget packages is now obsolete. C# nuget packages
+@rem with CoreCLR support are now being built using the dotnet cli
+@rem in build_packages_dotnetcli.sh
+
@rem Current package versions
set VERSION=1.1.0-dev
set PROTOBUF_VERSION=3.0.0
@@ -77,8 +81,8 @@ endlocal
xcopy /Y /I *.nupkg ..\..\artifacts\
@rem create a zipfile with the artifacts as well
-powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('..\..\artifacts', 'csharp_nugets.zip');"
-xcopy /Y /I csharp_nugets.zip ..\..\artifacts\
+powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('..\..\artifacts', 'csharp_nugets_obsolete.zip');"
+xcopy /Y /I csharp_nugets_obsolete.zip ..\..\artifacts\
goto :EOF
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index 2807278de6..3c127f320b 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -34,9 +34,6 @@ cd $(dirname $0)
mkdir -p ../../artifacts/
-# IMPORTANT: NuGet packages generated by dotnet CLI are considered experimental.
-# The official nugets are generated by src/csharp/build_packages.bat
-
mkdir -p nativelibs/windows_x86 nativelibs/windows_x64 \
nativelibs/linux_x86 nativelibs/linux_x64 \
nativelibs/macosx_x86 nativelibs/macosx_x64
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index 9cd9593d17..1159aac7a7 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -217,7 +217,7 @@ static NSMutableDictionary *kHostCache;
}
if (_responseSizeLimitOverride) {
- args[@GRPC_ARG_MAX_MESSAGE_LENGTH] = _responseSizeLimitOverride;
+ args[@GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH] = _responseSizeLimitOverride;
}
return args;
}
diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m
index f04a7e6441..44f22c9e85 100644
--- a/src/objective-c/tests/InteropTests.m
+++ b/src/objective-c/tests/InteropTests.m
@@ -180,7 +180,7 @@
// - If you're developing the server, consider using response streaming, or let clients filter
// responses by setting a google.protobuf.FieldMask in the request:
// https://github.com/google/protobuf/blob/master/src/google/protobuf/field_mask.proto
- XCTAssertEqualObjects(error.localizedDescription, @"Max message size exceeded");
+ XCTAssertEqualObjects(error.localizedDescription, @"Received message larger than max (4194305 vs. 4194304)");
[expectation fulfill];
}];
diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh
index a265149f48..81c2885320 100755
--- a/src/objective-c/tests/run_tests.sh
+++ b/src/objective-c/tests/run_tests.sh
@@ -44,8 +44,8 @@ BINDIR=../../../bins/$CONFIG
"interop_server before calling this script."
exit 1
}
-$BINDIR/interop_server --port=5050 &
-$BINDIR/interop_server --port=5051 --use_tls &
+$BINDIR/interop_server --port=5050 --max_send_message_size=8388608 &
+$BINDIR/interop_server --port=5051 --max_send_message_size=8388608 --use_tls &
# Kill them when this script exits.
trap 'kill -9 `jobs -p`' EXIT
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index d850eebc78..8a7f6572a6 100644
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -182,6 +182,7 @@ class BaseStub
} else {
$hostname = $this->hostname;
}
+
return 'https://'.$hostname.$service_name;
}
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 94ceeda02c..4bc4589956 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -70,7 +70,8 @@ function hardAssertIfStatusOk($status)
*/
function emptyUnary($stub)
{
- list($result, $status) = $stub->EmptyCall(new grpc\testing\EmptyMessage())->wait();
+ list($result, $status) =
+ $stub->EmptyCall(new grpc\testing\EmptyMessage())->wait();
hardAssertIfStatusOk($status);
hardAssert($result !== null, 'Call completed with a null response');
}
@@ -92,8 +93,8 @@ function largeUnary($stub)
* @param $fillUsername boolean whether to fill result with username
* @param $fillOauthScope boolean whether to fill result with oauth scope
*/
-function performLargeUnary($stub, $fillUsername = false, $fillOauthScope = false,
- $callback = false)
+function performLargeUnary($stub, $fillUsername = false,
+ $fillOauthScope = false, $callback = false)
{
$request_len = 271828;
$response_len = 314159;
@@ -118,11 +119,11 @@ function performLargeUnary($stub, $fillUsername = false, $fillOauthScope = false
hardAssert($result !== null, 'Call returned a null response');
$payload = $result->getPayload();
hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE,
- 'Payload had the wrong type');
+ 'Payload had the wrong type');
hardAssert(strlen($payload->getBody()) === $response_len,
- 'Payload had the wrong length');
+ 'Payload had the wrong length');
hardAssert($payload->getBody() === str_repeat("\0", $response_len),
- 'Payload had the wrong content');
+ 'Payload had the wrong content');
return $result;
}
@@ -141,11 +142,12 @@ function serviceAccountCreds($stub, $args)
$jsonKey = json_decode(
file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
true);
- $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true);
- hardAssert($result->getUsername() == $jsonKey['client_email'],
- 'invalid email returned');
+ $result = performLargeUnary($stub, $fillUsername = true,
+ $fillOauthScope = true);
+ hardAssert($result->getUsername() === $jsonKey['client_email'],
+ 'invalid email returned');
hardAssert(strpos($args['oauth_scope'], $result->getOauthScope()) !== false,
- 'invalid oauth scope returned');
+ 'invalid oauth scope returned');
}
/**
@@ -163,9 +165,10 @@ function computeEngineCreds($stub, $args)
if (!array_key_exists('default_service_account', $args)) {
throw new Exception('Missing default_service_account');
}
- $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true);
- hardAssert($args['default_service_account'] == $result->getUsername(),
- 'invalid email returned');
+ $result = performLargeUnary($stub, $fillUsername = true,
+ $fillOauthScope = true);
+ hardAssert($args['default_service_account'] === $result->getUsername(),
+ 'invalid email returned');
}
/**
@@ -179,9 +182,10 @@ function jwtTokenCreds($stub, $args)
$jsonKey = json_decode(
file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
true);
- $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true);
- hardAssert($result->getUsername() == $jsonKey['client_email'],
- 'invalid email returned');
+ $result = performLargeUnary($stub, $fillUsername = true,
+ $fillOauthScope = true);
+ hardAssert($result->getUsername() === $jsonKey['client_email'],
+ 'invalid email returned');
}
/**
@@ -195,9 +199,10 @@ function oauth2AuthToken($stub, $args)
$jsonKey = json_decode(
file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
true);
- $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true);
- hardAssert($result->getUsername() == $jsonKey['client_email'],
- 'invalid email returned');
+ $result = performLargeUnary($stub, $fillUsername = true,
+ $fillOauthScope = true);
+ hardAssert($result->getUsername() === $jsonKey['client_email'],
+ 'invalid email returned');
}
function updateAuthMetadataCallback($context)
@@ -209,8 +214,9 @@ function updateAuthMetadataCallback($context)
$metadata = [];
$result = $auth_credentials->updateMetadata([], $authUri);
foreach ($result as $key => $value) {
- $metadata[strtolower($key)] = $value;
+ $metadata[strtolower($key)] = $value;
}
+
return $metadata;
}
@@ -226,10 +232,11 @@ function perRpcCreds($stub, $args)
file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
true);
- $result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true,
+ $result = performLargeUnary($stub, $fillUsername = true,
+ $fillOauthScope = true,
'updateAuthMetadataCallback');
- hardAssert($result->getUsername() == $jsonKey['client_email'],
- 'invalid email returned');
+ hardAssert($result->getUsername() === $jsonKey['client_email'],
+ 'invalid email returned');
}
/**
@@ -258,7 +265,7 @@ function clientStreaming($stub)
list($result, $status) = $call->wait();
hardAssertIfStatusOk($status);
hardAssert($result->getAggregatedPayloadSize() === 74922,
- 'aggregated_payload_size was incorrect');
+ 'aggregated_payload_size was incorrect');
}
/**
@@ -283,10 +290,11 @@ function serverStreaming($stub)
foreach ($call->responses() as $value) {
hardAssert($i < 4, 'Too many responses');
$payload = $value->getPayload();
- hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE,
- 'Payload '.$i.' had the wrong type');
+ hardAssert(
+ $payload->getType() === grpc\testing\PayloadType::COMPRESSABLE,
+ 'Payload '.$i.' had the wrong type');
hardAssert(strlen($payload->getBody()) === $sizes[$i],
- 'Response '.$i.' had the wrong length');
+ 'Response '.$i.' had the wrong length');
$i += 1;
}
hardAssertIfStatusOk($call->getStatus());
@@ -318,10 +326,11 @@ function pingPong($stub)
hardAssert($response !== null, 'Server returned too few responses');
$payload = $response->getPayload();
- hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE,
- 'Payload '.$i.' had the wrong type');
+ hardAssert(
+ $payload->getType() === grpc\testing\PayloadType::COMPRESSABLE,
+ 'Payload '.$i.' had the wrong type');
hardAssert(strlen($payload->getBody()) === $response_lengths[$i],
- 'Payload '.$i.' had the wrong length');
+ 'Payload '.$i.' had the wrong length');
}
$call->writesDone();
hardAssert($call->read() === null, 'Server returned too many responses');
@@ -352,7 +361,7 @@ function cancelAfterBegin($stub)
$call->cancel();
list($result, $status) = $call->wait();
hardAssert($status->code === Grpc\STATUS_CANCELLED,
- 'Call status was not CANCELLED');
+ 'Call status was not CANCELLED');
}
/**
@@ -377,7 +386,7 @@ function cancelAfterFirstResponse($stub)
$call->cancel();
hardAssert($call->getStatus()->code === Grpc\STATUS_CANCELLED,
- 'Call status was not CANCELLED');
+ 'Call status was not CANCELLED');
}
function timeoutOnSleepingServer($stub)
@@ -396,7 +405,7 @@ function timeoutOnSleepingServer($stub)
$response = $call->read();
hardAssert($call->getStatus()->code === Grpc\STATUS_DEADLINE_EXCEEDED,
- 'Call status was not DEADLINE_EXCEEDED');
+ 'Call status was not DEADLINE_EXCEEDED');
}
function customMetadata($stub)
@@ -425,9 +434,9 @@ function customMetadata($stub)
$initial_metadata = $call->getMetadata();
hardAssert(array_key_exists($ECHO_INITIAL_KEY, $initial_metadata),
'Initial metadata does not contain expected key');
- hardAssert($initial_metadata[$ECHO_INITIAL_KEY][0] ==
- $ECHO_INITIAL_VALUE,
- 'Incorrect initial metadata value');
+ hardAssert(
+ $initial_metadata[$ECHO_INITIAL_KEY][0] === $ECHO_INITIAL_VALUE,
+ 'Incorrect initial metadata value');
list($result, $status) = $call->wait();
hardAssertIfStatusOk($status);
@@ -435,8 +444,9 @@ function customMetadata($stub)
$trailing_metadata = $call->getTrailingMetadata();
hardAssert(array_key_exists($ECHO_TRAILING_KEY, $trailing_metadata),
'Trailing metadata does not contain expected key');
- hardAssert($trailing_metadata[$ECHO_TRAILING_KEY][0] ==
- $ECHO_TRAILING_VALUE, 'Incorrect trailing metadata value');
+ hardAssert(
+ $trailing_metadata[$ECHO_TRAILING_KEY][0] === $ECHO_TRAILING_VALUE,
+ 'Incorrect trailing metadata value');
$streaming_call = $stub->FullDuplexCall($metadata);
@@ -451,7 +461,7 @@ function customMetadata($stub)
hardAssert(array_key_exists($ECHO_TRAILING_KEY,
$streaming_trailing_metadata),
'Trailing metadata does not contain expected key');
- hardAssert($streaming_trailing_metadata[$ECHO_TRAILING_KEY][0] ==
+ hardAssert($streaming_trailing_metadata[$ECHO_TRAILING_KEY][0] ===
$ECHO_TRAILING_VALUE, 'Incorrect trailing metadata value');
}
@@ -506,7 +516,7 @@ function _makeStub($args)
throw new Exception('Missing argument: --test_case is required');
}
- if ($args['server_port'] == 443) {
+ if ($args['server_port'] === 443) {
$server_address = $args['server_host'];
} else {
$server_address = $args['server_host'].':'.$args['server_port'];
@@ -548,7 +558,7 @@ function _makeStub($args)
if (in_array($test_case, ['service_account_creds',
'compute_engine_creds', 'jwt_token_creds', ])) {
- if ($test_case == 'jwt_token_creds') {
+ if ($test_case === 'jwt_token_creds') {
$auth_credentials = ApplicationDefaultCredentials::getCredentials();
} else {
$auth_credentials = ApplicationDefaultCredentials::getCredentials(
@@ -558,7 +568,7 @@ function _makeStub($args)
$opts['update_metadata'] = $auth_credentials->getUpdateMetadataFunc();
}
- if ($test_case == 'oauth2_auth_token') {
+ if ($test_case === 'oauth2_auth_token') {
$auth_credentials = ApplicationDefaultCredentials::getCredentials(
$args['oauth_scope']
);
@@ -578,8 +588,9 @@ function _makeStub($args)
$opts['update_metadata'] = $update_metadata;
}
- if ($test_case == 'unimplemented_method') {
- $stub = new grpc\testing\UnimplementedServiceClient($server_address, $opts);
+ if ($test_case === 'unimplemented_method') {
+ $stub = new grpc\testing\UnimplementedServiceClient($server_address,
+ $opts);
} else {
$stub = new grpc\testing\TestServiceClient($server_address, $opts);
}
@@ -656,7 +667,8 @@ function interop_main($args, $stub = false)
return $stub;
}
-if (isset($_SERVER['PHP_SELF']) && preg_match('/interop_client/', $_SERVER['PHP_SELF'])) {
+if (isset($_SERVER['PHP_SELF']) &&
+ preg_match('/interop_client/', $_SERVER['PHP_SELF'])) {
$args = getopt('', ['server_host:', 'server_port:', 'test_case:',
'use_tls::', 'use_test_ca::',
'server_host_override:', 'oauth_scope:',
diff --git a/src/php/tests/unit_tests/CallCredentials2Test.php b/src/php/tests/unit_tests/CallCredentials2Test.php
index b3b98a22ca..fa31439c54 100644
--- a/src/php/tests/unit_tests/CallCredentials2Test.php
+++ b/src/php/tests/unit_tests/CallCredentials2Test.php
@@ -170,7 +170,7 @@ class CallCredentials2Test extends PHPUnit_Framework_TestCase
$this->assertTrue(is_string($context->service_url));
$this->assertTrue(is_string($context->method_name));
- return "a string";
+ return 'a string';
}
public function testCallbackWithInvalidReturnValue()
@@ -196,5 +196,4 @@ class CallCredentials2Test extends PHPUnit_Framework_TestCase
$this->assertTrue($event->send_close);
$this->assertTrue($event->status->code == Grpc\STATUS_UNAUTHENTICATED);
}
-
}
diff --git a/src/proto/grpc/lb/v1/load_balancer.options b/src/proto/grpc/lb/v1/load_balancer.options
index d90366996e..a9398d5f47 100644
--- a/src/proto/grpc/lb/v1/load_balancer.options
+++ b/src/proto/grpc/lb/v1/load_balancer.options
@@ -1,6 +1,6 @@
grpc.lb.v1.InitialLoadBalanceRequest.name max_size:128
grpc.lb.v1.InitialLoadBalanceResponse.client_config max_size:64
grpc.lb.v1.InitialLoadBalanceResponse.load_balancer_delegate max_size:64
-grpc.lb.v1.Server.ip_address max_size:46
-grpc.lb.v1.Server.load_balance_token max_size:64
+grpc.lb.v1.Server.ip_address max_size:16
+grpc.lb.v1.Server.load_balance_token max_size:65
load_balancer.proto no_unions:true
diff --git a/src/proto/grpc/lb/v1/load_balancer.proto b/src/proto/grpc/lb/v1/load_balancer.proto
index 1bcad0b1d4..210fba1323 100644
--- a/src/proto/grpc/lb/v1/load_balancer.proto
+++ b/src/proto/grpc/lb/v1/load_balancer.proto
@@ -32,7 +32,6 @@ syntax = "proto3";
package grpc.lb.v1;
message Duration {
-
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive.
int64 seconds = 1;
@@ -93,21 +92,16 @@ message LoadBalanceResponse {
}
message InitialLoadBalanceResponse {
- oneof initial_response_type {
- // TODO(zhangkun83): ClientConfig not yet defined
- //ClientConfig client_config = 1;
-
- // This is an application layer redirect that indicates the client should
- // use the specified server for load balancing. When this field is set in
- // the response, the client should open a separate connection to the
- // load_balancer_delegate and call the BalanceLoad method.
- string load_balancer_delegate = 2;
- }
+ // This is an application layer redirect that indicates the client should use
+ // the specified server for load balancing. When this field is non-empty in
+ // the response, the client should open a separate connection to the
+ // load_balancer_delegate and call the BalanceLoad method.
+ string load_balancer_delegate = 1;
// This interval defines how often the client should send the client stats
// to the load balancer. Stats should only be reported when the duration is
// positive.
- Duration client_stats_report_interval = 3;
+ Duration client_stats_report_interval = 2;
}
message ServerList {
@@ -125,14 +119,17 @@ message ServerList {
}
message Server {
- // A resolved address and port for the server. The IP address string may
+ // A resolved address for the server, serialized in network-byte-order. It may
// either be an IPv4 or IPv6 address.
- string ip_address = 1;
+ bytes ip_address = 1;
+
+ // A resolved port number for the server.
int32 port = 2;
- // An opaque token that is passed from the client to the server in metadata.
- // The server may expect this token to indicate that the request from the
- // client was load balanced.
+ // An opaque but printable token given to the frontend for each pick. All
+ // frontend requests for that pick must include the token in its initial
+ // metadata. The token is used by the backend to verify the request and to
+ // allow the backend to report load to the gRPC LB system.
string load_balance_token = 3;
// Indicates whether this particular request should be dropped by the client
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index d36ac23305..ea3b6f3391 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -53,6 +53,7 @@ PYTHON_STEM = os.path.dirname(os.path.abspath(__file__))
GRPC_STEM = os.path.abspath(PYTHON_STEM + '../../../../')
PROTO_STEM = os.path.join(GRPC_STEM, 'src', 'proto')
PROTO_GEN_STEM = os.path.join(GRPC_STEM, 'src', 'python', 'gens')
+CYTHON_STEM = os.path.join(PYTHON_STEM, 'grpc', '_cython')
CONF_PY_ADDENDUM = """
extensions.append('sphinx.ext.napoleon')
@@ -244,7 +245,7 @@ def try_cythonize(extensions, linetracing=False, mandatory=True):
extensions,
include_path=[
include_dir for extension in extensions for include_dir in extension.include_dirs
- ],
+ ] + [CYTHON_STEM],
compiler_directives=cython_compiler_directives
)
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index faf3ab5f0d..b9b662c032 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -1189,7 +1189,7 @@ def insecure_channel(target, options=None):
A Channel to the target through which RPCs may be conducted.
"""
from grpc import _channel
- return _channel.Channel(target, options, None)
+ return _channel.Channel(target, () if options is None else options, None)
def secure_channel(target, credentials, options=None):
@@ -1205,10 +1205,11 @@ def secure_channel(target, credentials, options=None):
A Channel to the target through which RPCs may be conducted.
"""
from grpc import _channel
- return _channel.Channel(target, options, credentials._credentials)
+ return _channel.Channel(target, () if options is None else options,
+ credentials._credentials)
-def server(thread_pool, handlers=None):
+def server(thread_pool, handlers=None, options=None):
"""Creates a Server with which RPCs can be serviced.
Args:
@@ -1219,12 +1220,15 @@ def server(thread_pool, handlers=None):
only handlers the server will use to service RPCs; other handlers may
later be added by calling add_generic_rpc_handlers any time before the
returned Server is started.
+ options: A sequence of string-value pairs according to which to configure
+ the created server.
Returns:
A Server with which RPCs can be serviced.
"""
from grpc import _server
- return _server.Server(thread_pool, () if handlers is None else handlers)
+ return _server.Server(thread_pool, () if handlers is None else handlers,
+ () if options is None else options)
################################### __all__ #################################
diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py
index 3117dd1cb3..53a26727ab 100644
--- a/src/python/grpcio/grpc/_channel.py
+++ b/src/python/grpcio/grpc/_channel.py
@@ -842,18 +842,8 @@ def _unsubscribe(state, callback):
def _options(options):
- if options is None:
- pairs = ((cygrpc.ChannelArgKey.primary_user_agent_string, _USER_AGENT),)
- else:
- pairs = list(options) + [
- (cygrpc.ChannelArgKey.primary_user_agent_string, _USER_AGENT)]
- encoded_pairs = [
- (_common.encode(arg_name), arg_value) if isinstance(arg_value, int)
- else (_common.encode(arg_name), _common.encode(arg_value))
- for arg_name, arg_value in pairs]
- return cygrpc.ChannelArgs([
- cygrpc.ChannelArg(arg_name, arg_value)
- for arg_name, arg_value in encoded_pairs])
+ return list(options) + [
+ (cygrpc.ChannelArgKey.primary_user_agent_string, _USER_AGENT)]
class Channel(grpc.Channel):
@@ -867,7 +857,8 @@ class Channel(grpc.Channel):
credentials: A cygrpc.ChannelCredentials or None.
"""
self._channel = cygrpc.Channel(
- _common.encode(target), _options(options), credentials)
+ _common.encode(target), _common.channel_args(_options(options)),
+ credentials)
self._call_state = _ChannelCallState(self._channel)
self._connectivity_state = _ChannelConnectivityState(self._channel)
diff --git a/src/python/grpcio/grpc/_common.py b/src/python/grpcio/grpc/_common.py
index 4d7d521419..cc0984c8c6 100644
--- a/src/python/grpcio/grpc/_common.py
+++ b/src/python/grpcio/grpc/_common.py
@@ -94,6 +94,16 @@ def decode(b):
return b.decode('latin1')
+def channel_args(options):
+ channel_args = []
+ for key, value in options:
+ if isinstance(value, six.string_types):
+ channel_args.append(cygrpc.ChannelArg(encode(key), encode(value)))
+ else:
+ channel_args.append(cygrpc.ChannelArg(encode(key), value))
+ return cygrpc.ChannelArgs(channel_args)
+
+
def cygrpc_metadata(application_metadata):
return _EMPTY_METADATA if application_metadata is None else cygrpc.Metadata(
cygrpc.Metadatum(encode(key), encode(value))
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
index 3df937eb14..73d1ff7b97 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
@@ -32,15 +32,16 @@ cimport cpython
cdef class Channel:
- def __cinit__(self, bytes target, ChannelArgs arguments=None,
+ def __cinit__(self, bytes target, ChannelArgs arguments,
ChannelCredentials channel_credentials=None):
grpc_init()
cdef grpc_channel_args *c_arguments = NULL
cdef char *c_target = NULL
self.c_channel = NULL
self.references = []
- if arguments is not None:
+ if len(arguments) > 0:
c_arguments = &arguments.c_args
+ self.references.append(arguments)
c_target = target
if channel_credentials is None:
with nogil:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 42fced6545..dae28e15f2 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -135,7 +135,7 @@ cdef extern from "grpc/grpc.h":
const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
const char *GRPC_ARG_ENABLE_CENSUS
const char *GRPC_ARG_MAX_CONCURRENT_STREAMS
- const char *GRPC_ARG_MAX_MESSAGE_LENGTH
+ const char *GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH
const char *GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
const char *GRPC_ARG_DEFAULT_AUTHORITY
const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index 834a44123d..f444e33cf0 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -39,7 +39,7 @@ class ConnectivityState:
class ChannelArgKey:
enable_census = GRPC_ARG_ENABLE_CENSUS
max_concurrent_streams = GRPC_ARG_MAX_CONCURRENT_STREAMS
- max_message_length = GRPC_ARG_MAX_MESSAGE_LENGTH
+ max_message_length = GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH
http2_initial_sequence_number = GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
default_authority = GRPC_ARG_DEFAULT_AUTHORITY
primary_user_agent_string = GRPC_ARG_PRIMARY_USER_AGENT_STRING
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi
index 23cee7bd6e..20fc1c5fce 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi
@@ -35,7 +35,7 @@ import pkg_resources
cdef grpc_ssl_roots_override_result ssl_roots_override_callback(
char **pem_root_certs) with gil:
temporary_pem_root_certs = pkg_resources.resource_string(
- 'grpc._cython', '_credentials/roots.pem')
+ __name__.rstrip('.cygrpc'), '_credentials/roots.pem')
pem_root_certs[0] = <char *>gpr_malloc(len(temporary_pem_root_certs) + 1)
memcpy(
pem_root_certs[0], <char *>temporary_pem_root_certs,
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
index ca2b831114..18db38b686 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
@@ -34,12 +34,12 @@ import time
cdef class Server:
- def __cinit__(self, ChannelArgs arguments=None):
+ def __cinit__(self, ChannelArgs arguments):
grpc_init()
cdef grpc_channel_args *c_arguments = NULL
self.references = []
self.registered_completion_queues = []
- if arguments is not None:
+ if len(arguments) > 0:
c_arguments = &arguments.c_args
self.references.append(arguments)
with nogil:
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pxd b/src/python/grpcio/grpc/_cython/cygrpc.pxd
index 9779534e38..26454634a1 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pxd
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pxd
@@ -27,12 +27,12 @@
# (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/_cython/_cygrpc/grpc.pxi"
+include "_cygrpc/grpc.pxi"
-include "grpc/_cython/_cygrpc/call.pxd.pxi"
-include "grpc/_cython/_cygrpc/channel.pxd.pxi"
-include "grpc/_cython/_cygrpc/credentials.pxd.pxi"
-include "grpc/_cython/_cygrpc/completion_queue.pxd.pxi"
-include "grpc/_cython/_cygrpc/records.pxd.pxi"
-include "grpc/_cython/_cygrpc/security.pxd.pxi"
-include "grpc/_cython/_cygrpc/server.pxd.pxi"
+include "_cygrpc/call.pxd.pxi"
+include "_cygrpc/channel.pxd.pxi"
+include "_cygrpc/credentials.pxd.pxi"
+include "_cygrpc/completion_queue.pxd.pxi"
+include "_cygrpc/records.pxd.pxi"
+include "_cygrpc/security.pxd.pxi"
+include "_cygrpc/server.pxd.pxi"
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index 08089994a9..e1bd046a1a 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -35,14 +35,14 @@ import sys
# TODO(atash): figure out why the coverage tool gets confused about the Cython
# coverage plugin when the following files don't have a '.pxi' suffix.
-include "grpc/_cython/_cygrpc/grpc_string.pyx.pxi"
-include "grpc/_cython/_cygrpc/call.pyx.pxi"
-include "grpc/_cython/_cygrpc/channel.pyx.pxi"
-include "grpc/_cython/_cygrpc/credentials.pyx.pxi"
-include "grpc/_cython/_cygrpc/completion_queue.pyx.pxi"
-include "grpc/_cython/_cygrpc/records.pyx.pxi"
-include "grpc/_cython/_cygrpc/security.pyx.pxi"
-include "grpc/_cython/_cygrpc/server.pyx.pxi"
+include "_cygrpc/grpc_string.pyx.pxi"
+include "_cygrpc/call.pyx.pxi"
+include "_cygrpc/channel.pyx.pxi"
+include "_cygrpc/credentials.pyx.pxi"
+include "_cygrpc/completion_queue.pyx.pxi"
+include "_cygrpc/records.pyx.pxi"
+include "_cygrpc/security.pyx.pxi"
+include "_cygrpc/server.pyx.pxi"
#
# initialize gRPC
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index 94a13bfb2f..5f846ce773 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -728,12 +728,11 @@ def _start(state):
cleanup_server, target=_serve, args=(state,))
thread.start()
-
class Server(grpc.Server):
- def __init__(self, thread_pool, generic_handlers):
+ def __init__(self, thread_pool, generic_handlers, options):
completion_queue = cygrpc.CompletionQueue()
- server = cygrpc.Server()
+ server = cygrpc.Server(_common.channel_args(options))
server.register_completion_queue(completion_queue)
self._state = _ServerState(
completion_queue, server, generic_handlers, thread_pool)
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index be7f30c29b..288f02042e 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -50,6 +50,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/support/log_linux.c',
'src/core/lib/support/log_posix.c',
'src/core/lib/support/log_windows.c',
+ 'src/core/lib/support/mpscq.c',
'src/core/lib/support/murmur_hash.c',
'src/core/lib/support/percent_encoding.c',
'src/core/lib/support/slice.c',
@@ -85,6 +86,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/channel/handshaker.c',
'src/core/lib/channel/http_client_filter.c',
'src/core/lib/channel/http_server_filter.c',
+ 'src/core/lib/channel/message_size_filter.c',
'src/core/lib/compression/compression.c',
'src/core/lib/compression/message_compress.c',
'src/core/lib/debug/trace.c',
@@ -92,6 +94,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/http/httpcli.c',
'src/core/lib/http/parser.c',
'src/core/lib/iomgr/closure.c',
+ 'src/core/lib/iomgr/combiner.c',
'src/core/lib/iomgr/endpoint.c',
'src/core/lib/iomgr/endpoint_pair_posix.c',
'src/core/lib/iomgr/endpoint_pair_windows.c',
@@ -134,7 +137,6 @@ CORE_SOURCE_FILES = [
'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',
@@ -264,6 +266,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/census/operation.c',
'src/core/ext/census/placeholders.c',
'src/core/ext/census/resource.c',
+ 'src/core/ext/census/trace_context.c',
'src/core/ext/census/tracing.c',
'src/core/plugin_registry/grpc_plugin_registry.c',
'src/boringssl/err_data.c',
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index dcaef0db1f..2071a33e13 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -7,6 +7,7 @@
"_beta_features_test.BetaFeaturesTest",
"_beta_features_test.ContextManagementAndLifecycleTest",
"_cancel_many_calls_test.CancelManyCallsTest",
+ "_channel_args_test.ChannelArgsTest",
"_channel_connectivity_test.ChannelConnectivityTest",
"_channel_ready_future_test.ChannelReadyFutureTest",
"_channel_test.ChannelTest",
diff --git a/src/python/grpcio_tests/tests/unit/_channel_args_test.py b/src/python/grpcio_tests/tests/unit/_channel_args_test.py
new file mode 100644
index 0000000000..6a636d7993
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_channel_args_test.py
@@ -0,0 +1,53 @@
+# 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.
+
+"""Tests of Channel Args on client/server side."""
+
+import unittest
+
+import grpc
+
+TEST_CHANNEL_ARGS = (
+ ('arg1', b'bytes_val'),
+ ('arg2', 'str_val'),
+ ('arg3', 1),
+ (b'arg4', 'str_val'),
+)
+
+
+class ChannelArgsTest(unittest.TestCase):
+
+ def test_client(self):
+ grpc.insecure_channel('localhost:8080', options=TEST_CHANNEL_ARGS)
+
+ def test_server(self):
+ grpc.server(None, options=TEST_CHANNEL_ARGS)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
index 9cae96a00d..1324ad37b6 100644
--- a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
+++ b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
@@ -78,7 +78,7 @@ class ChannelConnectivityTest(unittest.TestCase):
def test_lonely_channel_connectivity(self):
callback = _Callback()
- channel = _channel.Channel('localhost:12345', None, None)
+ channel = _channel.Channel('localhost:12345', (), None)
channel.subscribe(callback.update, try_to_connect=False)
first_connectivities = callback.block_until_connectivities_satisfy(bool)
channel.subscribe(callback.update, try_to_connect=True)
@@ -105,13 +105,13 @@ class ChannelConnectivityTest(unittest.TestCase):
def test_immediately_connectable_channel_connectivity(self):
thread_pool = _thread_pool.RecordingThreadPool(max_workers=None)
- server = _server.Server(thread_pool, ())
+ server = _server.Server(thread_pool, (), ())
port = server.add_insecure_port('[::]:0')
server.start()
first_callback = _Callback()
second_callback = _Callback()
- channel = _channel.Channel('localhost:{}'.format(port), None, None)
+ channel = _channel.Channel('localhost:{}'.format(port), (), None)
channel.subscribe(first_callback.update, try_to_connect=False)
first_connectivities = first_callback.block_until_connectivities_satisfy(
bool)
@@ -146,12 +146,12 @@ class ChannelConnectivityTest(unittest.TestCase):
def test_reachable_then_unreachable_channel_connectivity(self):
thread_pool = _thread_pool.RecordingThreadPool(max_workers=None)
- server = _server.Server(thread_pool, ())
+ server = _server.Server(thread_pool, (), ())
port = server.add_insecure_port('[::]:0')
server.start()
callback = _Callback()
- channel = _channel.Channel('localhost:{}'.format(port), None, None)
+ channel = _channel.Channel('localhost:{}'.format(port), (), None)
channel.subscribe(callback.update, try_to_connect=True)
callback.block_until_connectivities_satisfy(_ready_in_connectivities)
# Now take down the server and confirm that channel readiness is repudiated.
diff --git a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
index 24f5b45b18..60d478bcd9 100644
--- a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
+++ b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
@@ -79,7 +79,7 @@ class ChannelReadyFutureTest(unittest.TestCase):
def test_immediately_connectable_channel_connectivity(self):
thread_pool = _thread_pool.RecordingThreadPool(max_workers=None)
- server = _server.Server(thread_pool, ())
+ server = _server.Server(thread_pool, (), ())
port = server.add_insecure_port('[::]:0')
server.start()
channel = grpc.insecure_channel('localhost:{}'.format(port))
diff --git a/src/python/grpcio_tests/tests/unit/_cython/_cancel_many_calls_test.py b/src/python/grpcio_tests/tests/unit/_cython/_cancel_many_calls_test.py
index cf212c5653..20115fb22c 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/_cancel_many_calls_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/_cancel_many_calls_test.py
@@ -157,11 +157,12 @@ class CancelManyCallsTest(unittest.TestCase):
server_thread_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
server_completion_queue = cygrpc.CompletionQueue()
- server = cygrpc.Server()
+ server = cygrpc.Server(cygrpc.ChannelArgs([]))
server.register_completion_queue(server_completion_queue)
port = server.add_http2_port(b'[::]:0')
server.start()
- channel = cygrpc.Channel('localhost:{}'.format(port).encode())
+ channel = cygrpc.Channel('localhost:{}'.format(port).encode(),
+ cygrpc.ChannelArgs([]))
state = _State()
diff --git a/src/python/grpcio_tests/tests/unit/_cython/_read_some_but_not_all_responses_test.py b/src/python/grpcio_tests/tests/unit/_cython/_read_some_but_not_all_responses_test.py
index 152d8edde3..2ae5285232 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/_read_some_but_not_all_responses_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/_read_some_but_not_all_responses_test.py
@@ -124,11 +124,12 @@ class ReadSomeButNotAllResponsesTest(unittest.TestCase):
def testReadSomeButNotAllResponses(self):
server_completion_queue = cygrpc.CompletionQueue()
- server = cygrpc.Server()
+ server = cygrpc.Server(cygrpc.ChannelArgs([]))
server.register_completion_queue(server_completion_queue)
port = server.add_http2_port(b'[::]:0')
server.start()
- channel = cygrpc.Channel('localhost:{}'.format(port).encode())
+ channel = cygrpc.Channel('localhost:{}'.format(port).encode(),
+ cygrpc.ChannelArgs([]))
server_shutdown_tag = 'server_shutdown_tag'
server_driver = _ServerDriver(server_completion_queue, server_shutdown_tag)
diff --git a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
index 142387d810..8dedebfabe 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
@@ -121,7 +121,7 @@ class TypeSmokeTest(unittest.TestCase):
del call_credentials
def testServerStartNoExplicitShutdown(self):
- server = cygrpc.Server()
+ server = cygrpc.Server(cygrpc.ChannelArgs([]))
completion_queue = cygrpc.CompletionQueue()
server.register_completion_queue(completion_queue)
port = server.add_http2_port(b'[::]:0')
@@ -131,7 +131,7 @@ class TypeSmokeTest(unittest.TestCase):
def testServerStartShutdown(self):
completion_queue = cygrpc.CompletionQueue()
- server = cygrpc.Server()
+ server = cygrpc.Server(cygrpc.ChannelArgs([]))
server.add_http2_port(b'[::]:0')
server.register_completion_queue(completion_queue)
server.start()
@@ -148,7 +148,7 @@ class ServerClientMixin(object):
def setUpMixin(self, server_credentials, client_credentials, host_override):
self.server_completion_queue = cygrpc.CompletionQueue()
- self.server = cygrpc.Server()
+ self.server = cygrpc.Server(cygrpc.ChannelArgs([]))
self.server.register_completion_queue(self.server_completion_queue)
if server_credentials:
self.port = self.server.add_http2_port(b'[::]:0', server_credentials)
@@ -164,7 +164,8 @@ class ServerClientMixin(object):
'localhost:{}'.format(self.port).encode(), client_channel_arguments,
client_credentials)
else:
- self.client_channel = cygrpc.Channel('localhost:{}'.format(self.port).encode())
+ self.client_channel = cygrpc.Channel(
+ 'localhost:{}'.format(self.port).encode(), cygrpc.ChannelArgs([]))
if host_override:
self.host_argument = None # default host
self.expected_host = host_override
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index e6d30a174b..3b2b88eb77 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -386,7 +386,7 @@ void Init_grpc_channel() {
rb_define_const(grpc_rb_cChannel, "MAX_CONCURRENT_STREAMS",
ID2SYM(rb_intern(GRPC_ARG_MAX_CONCURRENT_STREAMS)));
rb_define_const(grpc_rb_cChannel, "MAX_MESSAGE_LENGTH",
- ID2SYM(rb_intern(GRPC_ARG_MAX_MESSAGE_LENGTH)));
+ ID2SYM(rb_intern(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH)));
id_insecure_channel = rb_intern("this_channel_is_insecure");
Init_grpc_propagate_masks();
Init_grpc_connectivity_states();