grpc 1.0.0.pre1 → 1.0.0.pre2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +1 -37
  3. data/include/grpc/impl/codegen/compression_types.h +16 -1
  4. data/include/grpc/impl/codegen/grpc_types.h +23 -15
  5. data/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c +4 -2
  6. data/src/core/ext/transport/chttp2/transport/chttp2_plugin.c +3 -0
  7. data/src/core/ext/transport/chttp2/transport/chttp2_transport.c +305 -64
  8. data/src/core/ext/transport/chttp2/transport/internal.h +46 -19
  9. data/src/core/ext/transport/chttp2/transport/parsing.c +6 -5
  10. data/src/core/ext/transport/chttp2/transport/stream_lists.c +11 -9
  11. data/src/core/ext/transport/chttp2/transport/writing.c +13 -3
  12. data/src/core/lib/iomgr/endpoint.c +4 -0
  13. data/src/core/lib/iomgr/endpoint.h +4 -0
  14. data/src/core/lib/iomgr/ev_epoll_linux.c +161 -116
  15. data/src/core/lib/iomgr/ev_poll_and_epoll_posix.c +3 -0
  16. data/src/core/lib/iomgr/ev_poll_posix.c +3 -0
  17. data/src/core/lib/iomgr/ev_posix.c +4 -0
  18. data/src/core/lib/iomgr/ev_posix.h +4 -0
  19. data/src/core/lib/iomgr/exec_ctx.c +7 -3
  20. data/src/core/lib/iomgr/exec_ctx.h +5 -1
  21. data/src/core/lib/iomgr/iomgr.c +3 -0
  22. data/src/core/lib/iomgr/network_status_tracker.c +9 -6
  23. data/src/core/lib/iomgr/network_status_tracker.h +4 -0
  24. data/src/core/lib/iomgr/tcp_posix.c +14 -4
  25. data/src/core/lib/iomgr/tcp_server_posix.c +2 -1
  26. data/src/core/lib/iomgr/tcp_windows.c +10 -3
  27. data/src/core/lib/iomgr/workqueue.h +25 -14
  28. data/src/core/lib/iomgr/workqueue_posix.c +1 -7
  29. data/src/core/lib/iomgr/workqueue_posix.h +5 -0
  30. data/src/core/lib/iomgr/workqueue_windows.c +22 -0
  31. data/src/core/lib/security/transport/secure_endpoint.c +13 -5
  32. data/src/core/lib/support/log.c +10 -9
  33. data/src/core/lib/surface/server.c +45 -31
  34. data/src/core/lib/surface/version.c +1 -1
  35. data/src/core/lib/transport/connectivity_state.c +3 -0
  36. data/src/ruby/bin/math_client.rb +1 -1
  37. data/src/ruby/bin/{math.rb → math_pb.rb} +0 -0
  38. data/src/ruby/bin/math_server.rb +1 -1
  39. data/src/ruby/bin/{math_services.rb → math_services_pb.rb} +4 -4
  40. data/src/ruby/lib/grpc/version.rb +1 -1
  41. data/src/ruby/pb/grpc/health/checker.rb +1 -1
  42. data/src/ruby/pb/grpc/health/v1/{health.rb → health_pb.rb} +0 -0
  43. data/src/ruby/pb/grpc/health/v1/{health_services.rb → health_services_pb.rb} +1 -1
  44. data/src/ruby/pb/grpc/testing/duplicate/{echo_duplicate_services.rb → echo_duplicate_services_pb.rb} +2 -2
  45. data/src/ruby/pb/grpc/testing/{metrics.rb → metrics_pb.rb} +1 -1
  46. data/src/ruby/pb/grpc/testing/{metrics_services.rb → metrics_services_pb.rb} +2 -2
  47. data/src/ruby/pb/src/proto/grpc/testing/{empty.rb → empty_pb.rb} +0 -0
  48. data/src/ruby/pb/src/proto/grpc/testing/{messages.rb → messages_pb.rb} +8 -10
  49. data/src/ruby/pb/src/proto/grpc/testing/{test.rb → test_pb.rb} +2 -2
  50. data/src/ruby/pb/src/proto/grpc/testing/{test_services.rb → test_services_pb.rb} +1 -1
  51. data/src/ruby/pb/test/client.rb +3 -3
  52. data/src/ruby/pb/test/server.rb +3 -3
  53. data/src/ruby/spec/pb/duplicate/codegen_spec.rb +2 -2
  54. data/src/ruby/spec/pb/health/checker_spec.rb +4 -4
  55. metadata +15 -19
  56. data/src/ruby/pb/test/proto/empty.rb +0 -15
  57. data/src/ruby/pb/test/proto/messages.rb +0 -80
  58. data/src/ruby/pb/test/proto/test.rb +0 -14
  59. data/src/ruby/pb/test/proto/test_services.rb +0 -64
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dafe9d26f247ae4dba67525b7432a4479d07c350
4
- data.tar.gz: 6e45adc85ba75b19cf779e90e382de957e92fb68
3
+ metadata.gz: a66bb42d25ec71cb62d54fa3fb51c4079daac412
4
+ data.tar.gz: 2c50fc771054f69a4d0ff9ca0724bbb65eeca137
5
5
  SHA512:
6
- metadata.gz: d5f94005a7d94d36dd7ad43d413df81f180fabc024e8243490dbce8b575af1cff06e41635b40f96fe8596cca15f25f274a774b548ad54229fd18090c533fbce7
7
- data.tar.gz: b5f3e0697da658123d989a1aa0ec1c117d4cf9f38851f912ea41ebc28dd1256c09ce1f975b4b33b66fd758ad705487435be125db5a905e43c54994d7f8cf2a63
6
+ metadata.gz: 14cebd91ffce3a5b0ce44cb8ae37be42cfb39a60aa566d15c0efce6caa65805096540fd2ac6917c6877e5c915b36fd058155794dfc3b0ee2d980a187e4756a6a
7
+ data.tar.gz: d047c9804da730b19f1bd8faf43a8231e12ab4cf8d0eb889f643a25de6890582ec929ba50465331d93ac62dd2bd9f69eebd588cfe09ad8c6eceb4b5dff6d7077
data/Makefile CHANGED
@@ -415,7 +415,7 @@ E = @echo
415
415
  Q = @
416
416
  endif
417
417
 
418
- VERSION = 1.0.0-pre1
418
+ VERSION = 1.0.0-pre2
419
419
 
420
420
  CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
421
421
  CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -991,7 +991,6 @@ transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test
991
991
  udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test
992
992
  uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test
993
993
  uri_parser_test: $(BINDIR)/$(CONFIG)/uri_parser_test
994
- workqueue_test: $(BINDIR)/$(CONFIG)/workqueue_test
995
994
  alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test
996
995
  async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
997
996
  auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test
@@ -1295,7 +1294,6 @@ buildtests_c: privatelibs_c \
1295
1294
  $(BINDIR)/$(CONFIG)/transport_security_test \
1296
1295
  $(BINDIR)/$(CONFIG)/udp_server_test \
1297
1296
  $(BINDIR)/$(CONFIG)/uri_parser_test \
1298
- $(BINDIR)/$(CONFIG)/workqueue_test \
1299
1297
  $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 \
1300
1298
  $(BINDIR)/$(CONFIG)/badreq_bad_client_test \
1301
1299
  $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \
@@ -1674,8 +1672,6 @@ test_c: buildtests_c
1674
1672
  $(Q) $(BINDIR)/$(CONFIG)/udp_server_test || ( echo test udp_server_test failed ; exit 1 )
1675
1673
  $(E) "[RUN] Testing uri_parser_test"
1676
1674
  $(Q) $(BINDIR)/$(CONFIG)/uri_parser_test || ( echo test uri_parser_test failed ; exit 1 )
1677
- $(E) "[RUN] Testing workqueue_test"
1678
- $(Q) $(BINDIR)/$(CONFIG)/workqueue_test || ( echo test workqueue_test failed ; exit 1 )
1679
1675
  $(E) "[RUN] Testing public_headers_must_be_c89"
1680
1676
  $(Q) $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 || ( echo test public_headers_must_be_c89 failed ; exit 1 )
1681
1677
  $(E) "[RUN] Testing badreq_bad_client_test"
@@ -10175,38 +10171,6 @@ endif
10175
10171
  endif
10176
10172
 
10177
10173
 
10178
- WORKQUEUE_TEST_SRC = \
10179
- test/core/iomgr/workqueue_test.c \
10180
-
10181
- WORKQUEUE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(WORKQUEUE_TEST_SRC))))
10182
- ifeq ($(NO_SECURE),true)
10183
-
10184
- # You can't build secure targets if you don't have OpenSSL.
10185
-
10186
- $(BINDIR)/$(CONFIG)/workqueue_test: openssl_dep_error
10187
-
10188
- else
10189
-
10190
-
10191
-
10192
- $(BINDIR)/$(CONFIG)/workqueue_test: $(WORKQUEUE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
10193
- $(E) "[LD] Linking $@"
10194
- $(Q) mkdir -p `dirname $@`
10195
- $(Q) $(LD) $(LDFLAGS) $(WORKQUEUE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/workqueue_test
10196
-
10197
- endif
10198
-
10199
- $(OBJDIR)/$(CONFIG)/test/core/iomgr/workqueue_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
10200
-
10201
- deps_workqueue_test: $(WORKQUEUE_TEST_OBJS:.o=.dep)
10202
-
10203
- ifneq ($(NO_SECURE),true)
10204
- ifneq ($(NO_DEPS),true)
10205
- -include $(WORKQUEUE_TEST_OBJS:.o=.dep)
10206
- endif
10207
- endif
10208
-
10209
-
10210
10174
  ALARM_CPP_TEST_SRC = \
10211
10175
  test/cpp/common/alarm_cpp_test.cc \
10212
10176
 
@@ -46,12 +46,27 @@ extern "C" {
46
46
  #define GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY \
47
47
  "grpc-internal-encoding-request"
48
48
 
49
- /** To be used in channel arguments */
49
+ /** To be used in channel arguments.
50
+ *
51
+ * \addtogroup grpc_arg_keys
52
+ * \{ */
53
+ /** Default compression algorithm for the channel.
54
+ * Its value is an int from the \a grpc_compression_algorithm enum. */
50
55
  #define GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM \
51
56
  "grpc.default_compression_algorithm"
57
+ /** Default compression level for the channel.
58
+ * Its value is an int from the \a grpc_compression_level enum. */
52
59
  #define GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL "grpc.default_compression_level"
60
+ /** Compression algorithms supported by the channel.
61
+ * Its value is a bitset (an int). Bits correspond to algorithms in \a
62
+ * grpc_compression_algorithm. For example, its LSB corresponds to
63
+ * GRPC_COMPRESS_NONE, the next bit to GRPC_COMPRESS_DEFLATE, etc.
64
+ * Unset bits disable support for the algorithm. By default all algorithms are
65
+ * supported. It's not possible to disable GRPC_COMPRESS_NONE (the attempt will
66
+ * be ignored). */
53
67
  #define GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET \
54
68
  "grpc.compression_enabled_algorithms_bitset"
69
+ /** \} */
55
70
 
56
71
  /* The various compression algorithms supported by gRPC */
57
72
  typedef enum {
@@ -106,58 +106,66 @@ typedef struct {
106
106
  by grpc_arg; keys are strings to allow easy backwards-compatible extension
107
107
  by arbitrary parties.
108
108
  All evaluation is performed at channel creation time (i.e. the values in
109
- this structure need only live through the creation invocation). */
109
+ this structure need only live through the creation invocation).
110
+
111
+ See the description of the \ref grpc_arg_keys "available args" for more
112
+ details. */
110
113
  typedef struct {
111
114
  size_t num_args;
112
115
  grpc_arg *args;
113
116
  } grpc_channel_args;
114
117
 
115
- /* Channel argument keys: */
116
- /** Enable census for tracing and stats collection */
118
+ /** \defgroup grpc_arg_keys
119
+ * Channel argument keys.
120
+ * \{
121
+ */
122
+ /** If non-zero, enable census for tracing and stats collection. */
117
123
  #define GRPC_ARG_ENABLE_CENSUS "grpc.census"
118
- /** Enable load reporting */
124
+ /** If non-zero, enable load reporting. */
119
125
  #define GRPC_ARG_ENABLE_LOAD_REPORTING "grpc.loadreporting"
120
126
  /** Maximum number of concurrent incoming streams to allow on a http2
121
- connection */
127
+ connection. Int valued. */
122
128
  #define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
123
- /** Maximum message length that the channel can receive */
129
+ /** Maximum message length that the channel can receive. Int valued, bytes. */
124
130
  #define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
125
- /** Initial sequence number for http2 transports */
131
+ /** Initial sequence number for http2 transports. Int valued. */
126
132
  #define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
127
133
  "grpc.http2.initial_sequence_number"
128
134
  /** Amount to read ahead on individual streams. Defaults to 64kb, larger
129
135
  values can help throughput on high-latency connections.
130
136
  NOTE: at some point we'd like to auto-tune this, and this parameter
131
- will become a no-op. */
137
+ will become a no-op. Int valued, bytes. */
132
138
  #define GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES "grpc.http2.lookahead_bytes"
133
- /** How much memory to use for hpack decoding */
139
+ /** How much memory to use for hpack decoding. Int valued, bytes. */
134
140
  #define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \
135
141
  "grpc.http2.hpack_table_size.decoder"
136
- /** How much memory to use for hpack encoding */
142
+ /** How much memory to use for hpack encoding. Int valued, bytes. */
137
143
  #define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \
138
144
  "grpc.http2.hpack_table_size.encoder"
139
- /** Default authority to pass if none specified on call construction */
145
+ /** Default authority to pass if none specified on call construction. A string.
146
+ * */
140
147
  #define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
141
148
  /** Primary user agent: goes at the start of the user-agent metadata
142
- sent on each request */
149
+ sent on each request. A string. */
143
150
  #define GRPC_ARG_PRIMARY_USER_AGENT_STRING "grpc.primary_user_agent"
144
151
  /** Secondary user agent: goes at the end of the user-agent metadata
145
- sent on each request */
152
+ sent on each request. A string. */
146
153
  #define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent"
147
154
  /** The maximum time between subsequent connection attempts, in ms */
148
155
  #define GRPC_ARG_MAX_RECONNECT_BACKOFF_MS "grpc.max_reconnect_backoff_ms"
149
156
  /* The caller of the secure_channel_create functions may override the target
150
157
  name used for SSL host name checking using this channel argument which is of
151
- type GRPC_ARG_STRING. This *should* be used for testing only.
158
+ type \a GRPC_ARG_STRING. This *should* be used for testing only.
152
159
  If this argument is not specified, the name used for SSL host name checking
153
160
  will be the target parameter (assuming that the secure channel is an SSL
154
161
  channel). If this parameter is specified and the underlying is not an SSL
155
162
  channel, it will just be ignored. */
156
163
  #define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override"
157
- /* Maximum metadata size */
164
+ /* Maximum metadata size, in bytes. */
158
165
  #define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size"
159
166
  /** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */
160
167
  #define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport"
168
+ /** \} */
161
169
 
162
170
  /** Result of a grpc call. If the caller satisfies the prerequisites of a
163
171
  particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
@@ -91,11 +91,13 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
91
91
  connector *c = arg;
92
92
  grpc_closure *notify;
93
93
  gpr_mu_lock(&c->mu);
94
+ grpc_error *error = GRPC_ERROR_NONE;
94
95
  if (c->connecting_endpoint == NULL) {
95
96
  memset(c->result, 0, sizeof(*c->result));
96
97
  gpr_mu_unlock(&c->mu);
97
98
  } else if (status != GRPC_SECURITY_OK) {
98
- gpr_log(GPR_ERROR, "Secure handshake failed with error %d.", status);
99
+ error = grpc_error_set_int(GRPC_ERROR_CREATE("Secure handshake failed"),
100
+ GRPC_ERROR_INT_SECURITY_STATUS, status);
99
101
  memset(c->result, 0, sizeof(*c->result));
100
102
  c->connecting_endpoint = NULL;
101
103
  gpr_mu_unlock(&c->mu);
@@ -113,7 +115,7 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
113
115
  }
114
116
  notify = c->notify;
115
117
  c->notify = NULL;
116
- grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_NONE, NULL);
118
+ grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
117
119
  }
118
120
 
119
121
  static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
@@ -36,11 +36,14 @@
36
36
  #include "src/core/lib/debug/trace.h"
37
37
  #include "src/core/lib/transport/metadata.h"
38
38
 
39
+ extern int grpc_http_write_state_trace;
40
+
39
41
  void grpc_chttp2_plugin_init(void) {
40
42
  grpc_chttp2_base64_encode_and_huffman_compress =
41
43
  grpc_chttp2_base64_encode_and_huffman_compress_impl;
42
44
  grpc_register_tracer("http", &grpc_http_trace);
43
45
  grpc_register_tracer("flowctl", &grpc_flowctl_trace);
46
+ grpc_register_tracer("http_write_state", &grpc_http_write_state_trace);
44
47
  }
45
48
 
46
49
  void grpc_chttp2_plugin_shutdown(void) {}
@@ -48,6 +48,7 @@
48
48
  #include "src/core/ext/transport/chttp2/transport/status_conversion.h"
49
49
  #include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
50
50
  #include "src/core/lib/http/parser.h"
51
+ #include "src/core/lib/iomgr/workqueue.h"
51
52
  #include "src/core/lib/profiling/timers.h"
52
53
  #include "src/core/lib/support/string.h"
53
54
  #include "src/core/lib/transport/static_metadata.h"
@@ -60,9 +61,9 @@
60
61
  #define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024)
61
62
 
62
63
  #define MAX_CLIENT_STREAM_ID 0x7fffffffu
63
-
64
64
  int grpc_http_trace = 0;
65
65
  int grpc_flowctl_trace = 0;
66
+ int grpc_http_write_state_trace = 0;
66
67
 
67
68
  #define TRANSPORT_FROM_WRITING(tw) \
68
69
  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
@@ -88,10 +89,16 @@ static const grpc_transport_vtable vtable;
88
89
  static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
89
90
  static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
90
91
  static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
92
+ static void initiate_writing(grpc_exec_ctx *exec_ctx, void *t,
93
+ grpc_error *error);
94
+
95
+ static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
96
+ static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
97
+ grpc_chttp2_transport *t, grpc_error *error);
91
98
 
92
99
  /** Set a transport level setting, and push it to our peer */
93
- static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
94
- uint32_t value);
100
+ static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
101
+ grpc_chttp2_setting_id id, uint32_t value);
95
102
 
96
103
  /** Start disconnection chain */
97
104
  static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@@ -137,7 +144,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
137
144
  grpc_chttp2_transport_global *transport_global);
138
145
 
139
146
  static void incoming_byte_stream_update_flow_control(
140
- grpc_chttp2_transport_global *transport_global,
147
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
141
148
  grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
142
149
  size_t have_already);
143
150
  static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
@@ -201,6 +208,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
201
208
  gpr_free(t);
202
209
  }
203
210
 
211
+ /*#define REFCOUNTING_DEBUG 1*/
204
212
  #ifdef REFCOUNTING_DEBUG
205
213
  #define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
206
214
  #define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__)
@@ -231,7 +239,7 @@ static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
231
239
 
232
240
  static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
233
241
  const grpc_channel_args *channel_args,
234
- grpc_endpoint *ep, uint8_t is_client) {
242
+ grpc_endpoint *ep, bool is_client) {
235
243
  size_t i;
236
244
  int j;
237
245
 
@@ -273,6 +281,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
273
281
  grpc_closure_init(&t->writing_action, writing_action, t);
274
282
  grpc_closure_init(&t->reading_action, reading_action, t);
275
283
  grpc_closure_init(&t->parsing_action, parsing_action, t);
284
+ grpc_closure_init(&t->initiate_writing, initiate_writing, t);
276
285
 
277
286
  gpr_slice_buffer_init(&t->parsing.qbuf);
278
287
  grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
@@ -286,6 +295,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
286
295
  gpr_slice_buffer_add(
287
296
  &t->global.qbuf,
288
297
  gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
298
+ grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "initial_write");
289
299
  }
290
300
  /* 8 is a random stab in the dark as to a good initial size: it's small enough
291
301
  that it shouldn't waste memory for infrequently used connections, yet
@@ -311,11 +321,12 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
311
321
 
312
322
  /* configure http2 the way we like it */
313
323
  if (is_client) {
314
- push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
315
- push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
324
+ push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
325
+ push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
316
326
  }
317
- push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW);
318
- push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
327
+ push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
328
+ DEFAULT_WINDOW);
329
+ push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
319
330
  DEFAULT_MAX_HEADER_LIST_SIZE);
320
331
 
321
332
  if (channel_args) {
@@ -329,7 +340,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
329
340
  gpr_log(GPR_ERROR, "%s: must be an integer",
330
341
  GRPC_ARG_MAX_CONCURRENT_STREAMS);
331
342
  } else {
332
- push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
343
+ push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
333
344
  (uint32_t)channel_args->args[i].value.integer);
334
345
  }
335
346
  } else if (0 == strcmp(channel_args->args[i].key,
@@ -368,7 +379,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
368
379
  gpr_log(GPR_ERROR, "%s: must be non-negative",
369
380
  GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
370
381
  } else {
371
- push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
382
+ push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
372
383
  (uint32_t)channel_args->args[i].value.integer);
373
384
  }
374
385
  } else if (0 == strcmp(channel_args->args[i].key,
@@ -393,7 +404,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
393
404
  gpr_log(GPR_ERROR, "%s: must be non-negative",
394
405
  GRPC_ARG_MAX_METADATA_SIZE);
395
406
  } else {
396
- push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
407
+ push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
397
408
  (uint32_t)channel_args->args[i].value.integer);
398
409
  }
399
410
  }
@@ -444,6 +455,9 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
444
455
  grpc_chttp2_transport *t,
445
456
  grpc_error *error) {
446
457
  if (!t->closed) {
458
+ if (grpc_http_write_state_trace) {
459
+ gpr_log(GPR_DEBUG, "W:%p close transport", t);
460
+ }
447
461
  t->closed = 1;
448
462
  connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN,
449
463
  GRPC_ERROR_REF(error), "close_transport");
@@ -590,7 +604,8 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
590
604
  grpc_chttp2_incoming_metadata_buffer_destroy(
591
605
  &s->global.received_trailing_metadata);
592
606
  gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer);
593
- GRPC_ERROR_UNREF(s->global.removal_error);
607
+ GRPC_ERROR_UNREF(s->global.read_closed_error);
608
+ GRPC_ERROR_UNREF(s->global.write_closed_error);
594
609
 
595
610
  UNREF_TRANSPORT(exec_ctx, t, "stream");
596
611
 
@@ -634,6 +649,36 @@ grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
634
649
  * LOCK MANAGEMENT
635
650
  */
636
651
 
652
+ static const char *write_state_name(grpc_chttp2_write_state state) {
653
+ switch (state) {
654
+ case GRPC_CHTTP2_WRITING_INACTIVE:
655
+ return "INACTIVE";
656
+ case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
657
+ return "REQUESTED[p=0]";
658
+ case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
659
+ return "REQUESTED[p=1]";
660
+ case GRPC_CHTTP2_WRITE_SCHEDULED:
661
+ return "SCHEDULED";
662
+ case GRPC_CHTTP2_WRITING:
663
+ return "WRITING";
664
+ case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
665
+ return "WRITING[p=1]";
666
+ case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
667
+ return "WRITING[p=0]";
668
+ }
669
+ GPR_UNREACHABLE_CODE(return "UNKNOWN");
670
+ }
671
+
672
+ static void set_write_state(grpc_chttp2_transport *t,
673
+ grpc_chttp2_write_state state, const char *reason) {
674
+ if (grpc_http_write_state_trace) {
675
+ gpr_log(GPR_DEBUG, "W:%p %s -> %s because %s", t,
676
+ write_state_name(t->executor.write_state), write_state_name(state),
677
+ reason);
678
+ }
679
+ t->executor.write_state = state;
680
+ }
681
+
637
682
  static void finish_global_actions(grpc_exec_ctx *exec_ctx,
638
683
  grpc_chttp2_transport *t) {
639
684
  grpc_chttp2_executor_action_header *hdr;
@@ -642,13 +687,6 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
642
687
  GPR_TIMER_BEGIN("finish_global_actions", 0);
643
688
 
644
689
  for (;;) {
645
- if (!t->executor.writing_active && !t->closed &&
646
- grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
647
- t->executor.writing_active = 1;
648
- REF_TRANSPORT(t, "writing");
649
- prevent_endpoint_shutdown(t);
650
- grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
651
- }
652
690
  check_read_ops(exec_ctx, &t->global);
653
691
 
654
692
  gpr_mu_lock(&t->executor.mu);
@@ -669,8 +707,28 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
669
707
  continue;
670
708
  } else {
671
709
  t->executor.global_active = false;
710
+ switch (t->executor.write_state) {
711
+ case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
712
+ set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "unlocking");
713
+ REF_TRANSPORT(t, "initiate_writing");
714
+ gpr_mu_unlock(&t->executor.mu);
715
+ grpc_exec_ctx_sched(
716
+ exec_ctx, &t->initiate_writing, GRPC_ERROR_NONE,
717
+ t->ep != NULL ? grpc_endpoint_get_workqueue(t->ep) : NULL);
718
+ break;
719
+ case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
720
+ start_writing(exec_ctx, t);
721
+ gpr_mu_unlock(&t->executor.mu);
722
+ break;
723
+ case GRPC_CHTTP2_WRITING_INACTIVE:
724
+ case GRPC_CHTTP2_WRITING:
725
+ case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
726
+ case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
727
+ case GRPC_CHTTP2_WRITE_SCHEDULED:
728
+ gpr_mu_unlock(&t->executor.mu);
729
+ break;
730
+ }
672
731
  }
673
- gpr_mu_unlock(&t->executor.mu);
674
732
  break;
675
733
  }
676
734
 
@@ -741,16 +799,118 @@ void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
741
799
  * OUTPUT PROCESSING
742
800
  */
743
801
 
744
- void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
745
- grpc_chttp2_stream_global *stream_global) {
802
+ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
803
+ grpc_chttp2_transport_global *transport_global,
804
+ bool covered_by_poller, const char *reason) {
805
+ /* Perform state checks, and transition to a scheduled state if appropriate.
806
+ Each time we finish the global lock execution, we check if we need to
807
+ write. If we do:
808
+ - (if there is a poller surrounding the write) schedule
809
+ initiate_writing, which locks and calls initiate_writing_locked to...
810
+ - call start_writing, which verifies (under the global lock) that there
811
+ are things that need to be written by calling
812
+ grpc_chttp2_unlocking_check_writes, and if so schedules writing_action
813
+ against the current exec_ctx, to be executed OUTSIDE of the global lock
814
+ - eventually writing_action results in grpc_chttp2_terminate_writing being
815
+ called, which re-takes the global lock, updates state, checks if we need
816
+ to do *another* write immediately, and if so loops back to
817
+ start_writing.
818
+
819
+ Current problems:
820
+ - too much lock entry/exiting
821
+ - the writing thread can become stuck indefinitely (punt through the
822
+ workqueue periodically to fix) */
823
+
824
+ grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global);
825
+ switch (t->executor.write_state) {
826
+ case GRPC_CHTTP2_WRITING_INACTIVE:
827
+ set_write_state(t, covered_by_poller
828
+ ? GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER
829
+ : GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
830
+ reason);
831
+ break;
832
+ case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
833
+ /* nothing to do: write already requested */
834
+ break;
835
+ case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
836
+ if (covered_by_poller) {
837
+ /* upgrade to note poller is available to cover the write */
838
+ set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER, reason);
839
+ }
840
+ break;
841
+ case GRPC_CHTTP2_WRITE_SCHEDULED:
842
+ /* nothing to do: write already scheduled */
843
+ break;
844
+ case GRPC_CHTTP2_WRITING:
845
+ set_write_state(t,
846
+ covered_by_poller ? GRPC_CHTTP2_WRITING_STALE_WITH_POLLER
847
+ : GRPC_CHTTP2_WRITING_STALE_NO_POLLER,
848
+ reason);
849
+ break;
850
+ case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
851
+ /* nothing to do: write already requested */
852
+ break;
853
+ case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
854
+ if (covered_by_poller) {
855
+ /* upgrade to note poller is available to cover the write */
856
+ set_write_state(t, GRPC_CHTTP2_WRITING_STALE_WITH_POLLER, reason);
857
+ }
858
+ break;
859
+ }
860
+ }
861
+
862
+ static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
863
+ GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED ||
864
+ t->executor.write_state == GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER);
865
+ if (!t->closed &&
866
+ grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
867
+ set_write_state(t, GRPC_CHTTP2_WRITING, "start_writing");
868
+ REF_TRANSPORT(t, "writing");
869
+ prevent_endpoint_shutdown(t);
870
+ grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
871
+ } else {
872
+ if (t->closed) {
873
+ set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE,
874
+ "start_writing:transport_closed");
875
+ } else {
876
+ set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE,
877
+ "start_writing:nothing_to_write");
878
+ }
879
+ end_waiting_for_write(exec_ctx, t, GRPC_ERROR_CREATE("Nothing to write"));
880
+ if (t->ep && !t->endpoint_reading) {
881
+ destroy_endpoint(exec_ctx, t);
882
+ }
883
+ }
884
+ }
885
+
886
+ static void initiate_writing_locked(grpc_exec_ctx *exec_ctx,
887
+ grpc_chttp2_transport *t,
888
+ grpc_chttp2_stream *s_unused,
889
+ void *arg_ignored) {
890
+ start_writing(exec_ctx, t);
891
+ UNREF_TRANSPORT(exec_ctx, t, "initiate_writing");
892
+ }
893
+
894
+ static void initiate_writing(grpc_exec_ctx *exec_ctx, void *arg,
895
+ grpc_error *error) {
896
+ grpc_chttp2_run_with_global_lock(exec_ctx, arg, NULL, initiate_writing_locked,
897
+ NULL, 0);
898
+ }
899
+
900
+ void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
901
+ grpc_chttp2_transport_global *transport_global,
902
+ grpc_chttp2_stream_global *stream_global,
903
+ bool covered_by_poller, const char *reason) {
746
904
  if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed &&
747
905
  grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) {
748
906
  GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
907
+ grpc_chttp2_initiate_write(exec_ctx, transport_global, covered_by_poller,
908
+ reason);
749
909
  }
750
910
  }
751
911
 
752
- static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
753
- uint32_t value) {
912
+ static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
913
+ grpc_chttp2_setting_id id, uint32_t value) {
754
914
  const grpc_chttp2_setting_parameters *sp =
755
915
  &grpc_chttp2_settings_parameters[id];
756
916
  uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value);
@@ -761,9 +921,22 @@ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
761
921
  if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) {
762
922
  t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value;
763
923
  t->global.dirtied_local_settings = 1;
924
+ grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "push_setting");
764
925
  }
765
926
  }
766
927
 
928
+ static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
929
+ grpc_chttp2_transport *t, grpc_error *error) {
930
+ grpc_chttp2_stream_global *stream_global;
931
+ while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
932
+ &stream_global)) {
933
+ fail_pending_writes(exec_ctx, &t->global, stream_global,
934
+ GRPC_ERROR_REF(error));
935
+ GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
936
+ }
937
+ GRPC_ERROR_UNREF(error);
938
+ }
939
+
767
940
  static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
768
941
  grpc_chttp2_transport *t,
769
942
  grpc_chttp2_stream *s_ignored,
@@ -778,24 +951,32 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
778
951
 
779
952
  grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
780
953
 
781
- grpc_chttp2_stream_global *stream_global;
782
- while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
783
- &stream_global)) {
784
- fail_pending_writes(exec_ctx, &t->global, stream_global,
785
- GRPC_ERROR_REF(error));
786
- GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
954
+ end_waiting_for_write(exec_ctx, t, error);
955
+
956
+ switch (t->executor.write_state) {
957
+ case GRPC_CHTTP2_WRITING_INACTIVE:
958
+ case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
959
+ case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
960
+ case GRPC_CHTTP2_WRITE_SCHEDULED:
961
+ GPR_UNREACHABLE_CODE(break);
962
+ case GRPC_CHTTP2_WRITING:
963
+ set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "terminate_writing");
964
+ break;
965
+ case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
966
+ set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
967
+ "terminate_writing");
968
+ break;
969
+ case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
970
+ set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
971
+ "terminate_writing");
972
+ break;
787
973
  }
788
974
 
789
- /* leave the writing flag up on shutdown to prevent further writes in
790
- unlock()
791
- from starting */
792
- t->executor.writing_active = 0;
793
975
  if (t->ep && !t->endpoint_reading) {
794
976
  destroy_endpoint(exec_ctx, t);
795
977
  }
796
978
 
797
979
  UNREF_TRANSPORT(exec_ctx, t, "writing");
798
- GRPC_ERROR_UNREF(error);
799
980
  }
800
981
 
801
982
  void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
@@ -878,7 +1059,8 @@ static void maybe_start_some_streams(
878
1059
  stream_global->id, STREAM_FROM_GLOBAL(stream_global));
879
1060
  stream_global->in_stream_map = true;
880
1061
  transport_global->concurrent_stream_count++;
881
- grpc_chttp2_become_writable(transport_global, stream_global);
1062
+ grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, true,
1063
+ "new_stream");
882
1064
  }
883
1065
  /* cancel out streams that will never be started */
884
1066
  while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
@@ -1018,9 +1200,11 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
1018
1200
  maybe_start_some_streams(exec_ctx, transport_global);
1019
1201
  } else {
1020
1202
  GPR_ASSERT(stream_global->id != 0);
1021
- grpc_chttp2_become_writable(transport_global, stream_global);
1203
+ grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
1204
+ true, "op.send_initial_metadata");
1022
1205
  }
1023
1206
  } else {
1207
+ stream_global->send_trailing_metadata = NULL;
1024
1208
  grpc_chttp2_complete_closure_step(
1025
1209
  exec_ctx, transport_global, stream_global,
1026
1210
  &stream_global->send_initial_metadata_finished,
@@ -1042,7 +1226,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
1042
1226
  } else {
1043
1227
  stream_global->send_message = op->send_message;
1044
1228
  if (stream_global->id != 0) {
1045
- grpc_chttp2_become_writable(transport_global, stream_global);
1229
+ grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
1230
+ true, "op.send_message");
1046
1231
  }
1047
1232
  }
1048
1233
  }
@@ -1075,6 +1260,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
1075
1260
  grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
1076
1261
  }
1077
1262
  if (stream_global->write_closed) {
1263
+ stream_global->send_trailing_metadata = NULL;
1078
1264
  grpc_chttp2_complete_closure_step(
1079
1265
  exec_ctx, transport_global, stream_global,
1080
1266
  &stream_global->send_trailing_metadata_finished,
@@ -1085,7 +1271,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
1085
1271
  } else if (stream_global->id != 0) {
1086
1272
  /* TODO(ctiller): check if there's flow control for any outstanding
1087
1273
  bytes before going writable */
1088
- grpc_chttp2_become_writable(transport_global, stream_global);
1274
+ grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
1275
+ true, "op.send_trailing_metadata");
1089
1276
  }
1090
1277
  }
1091
1278
  }
@@ -1106,8 +1293,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
1106
1293
  (stream_global->incoming_frames.head == NULL ||
1107
1294
  stream_global->incoming_frames.head->is_tail)) {
1108
1295
  incoming_byte_stream_update_flow_control(
1109
- transport_global, stream_global, transport_global->stream_lookahead,
1110
- 0);
1296
+ exec_ctx, transport_global, stream_global,
1297
+ transport_global->stream_lookahead, 0);
1111
1298
  }
1112
1299
  grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
1113
1300
  }
@@ -1135,7 +1322,8 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
1135
1322
  sizeof(*op));
1136
1323
  }
1137
1324
 
1138
- static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
1325
+ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
1326
+ grpc_closure *on_recv) {
1139
1327
  grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p));
1140
1328
  p->next = &t->global.pings;
1141
1329
  p->prev = p->next->prev;
@@ -1150,6 +1338,7 @@ static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
1150
1338
  p->id[7] = (uint8_t)(t->global.ping_counter & 0xff);
1151
1339
  p->on_recv = on_recv;
1152
1340
  gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
1341
+ grpc_chttp2_initiate_write(exec_ctx, &t->global, true, "send_ping");
1153
1342
  }
1154
1343
 
1155
1344
  static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@@ -1209,6 +1398,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
1209
1398
  close_transport = grpc_chttp2_has_streams(t)
1210
1399
  ? GRPC_ERROR_NONE
1211
1400
  : GRPC_ERROR_CREATE("GOAWAY sent");
1401
+ grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "goaway_sent");
1212
1402
  }
1213
1403
 
1214
1404
  if (op->set_accept_stream) {
@@ -1226,7 +1416,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
1226
1416
  }
1227
1417
 
1228
1418
  if (op->send_ping) {
1229
- send_ping_locked(t, op->send_ping);
1419
+ send_ping_locked(exec_ctx, t, op->send_ping);
1230
1420
  }
1231
1421
 
1232
1422
  if (close_transport != GRPC_ERROR_NONE) {
@@ -1414,6 +1604,8 @@ static void cancel_from_api(grpc_exec_ctx *exec_ctx,
1414
1604
  &transport_global->qbuf,
1415
1605
  grpc_chttp2_rst_stream_create(stream_global->id, (uint32_t)http_error,
1416
1606
  &stream_global->stats.outgoing));
1607
+ grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
1608
+ "rst_stream");
1417
1609
  }
1418
1610
 
1419
1611
  const char *msg =
@@ -1473,10 +1665,39 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
1473
1665
  }
1474
1666
  }
1475
1667
 
1668
+ static void add_error(grpc_error *error, grpc_error **refs, size_t *nrefs) {
1669
+ if (error == GRPC_ERROR_NONE) return;
1670
+ for (size_t i = 0; i < *nrefs; i++) {
1671
+ if (error == refs[i]) {
1672
+ return;
1673
+ }
1674
+ }
1675
+ refs[*nrefs] = error;
1676
+ ++*nrefs;
1677
+ }
1678
+
1679
+ static grpc_error *removal_error(grpc_error *extra_error,
1680
+ grpc_chttp2_stream_global *stream_global) {
1681
+ grpc_error *refs[3];
1682
+ size_t nrefs = 0;
1683
+ add_error(stream_global->read_closed_error, refs, &nrefs);
1684
+ add_error(stream_global->write_closed_error, refs, &nrefs);
1685
+ add_error(extra_error, refs, &nrefs);
1686
+ grpc_error *error = GRPC_ERROR_NONE;
1687
+ if (nrefs > 0) {
1688
+ error = GRPC_ERROR_CREATE_REFERENCING("Failed due to stream removal", refs,
1689
+ nrefs);
1690
+ }
1691
+ GRPC_ERROR_UNREF(extra_error);
1692
+ return error;
1693
+ }
1694
+
1476
1695
  static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
1477
1696
  grpc_chttp2_transport_global *transport_global,
1478
1697
  grpc_chttp2_stream_global *stream_global,
1479
1698
  grpc_error *error) {
1699
+ error = removal_error(error, stream_global);
1700
+ stream_global->send_message = NULL;
1480
1701
  grpc_chttp2_complete_closure_step(
1481
1702
  exec_ctx, transport_global, stream_global,
1482
1703
  &stream_global->send_initial_metadata_finished, GRPC_ERROR_REF(error));
@@ -1499,14 +1720,17 @@ void grpc_chttp2_mark_stream_closed(
1499
1720
  }
1500
1721
  grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
1501
1722
  if (close_reads && !stream_global->read_closed) {
1723
+ stream_global->read_closed_error = GRPC_ERROR_REF(error);
1502
1724
  stream_global->read_closed = true;
1503
1725
  stream_global->published_initial_metadata = true;
1504
1726
  stream_global->published_trailing_metadata = true;
1505
1727
  decrement_active_streams_locked(exec_ctx, transport_global, stream_global);
1506
1728
  }
1507
1729
  if (close_writes && !stream_global->write_closed) {
1730
+ stream_global->write_closed_error = GRPC_ERROR_REF(error);
1508
1731
  stream_global->write_closed = true;
1509
- if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.writing_active) {
1732
+ if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.write_state !=
1733
+ GRPC_CHTTP2_WRITING_INACTIVE) {
1510
1734
  GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
1511
1735
  grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
1512
1736
  stream_global);
@@ -1516,7 +1740,6 @@ void grpc_chttp2_mark_stream_closed(
1516
1740
  }
1517
1741
  }
1518
1742
  if (stream_global->read_closed && stream_global->write_closed) {
1519
- stream_global->removal_error = GRPC_ERROR_REF(error);
1520
1743
  if (stream_global->id != 0 &&
1521
1744
  TRANSPORT_FROM_GLOBAL(transport_global)->executor.parsing_active) {
1522
1745
  grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
@@ -1524,7 +1747,8 @@ void grpc_chttp2_mark_stream_closed(
1524
1747
  } else {
1525
1748
  if (stream_global->id != 0) {
1526
1749
  remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
1527
- stream_global->id, GRPC_ERROR_REF(error));
1750
+ stream_global->id,
1751
+ removal_error(GRPC_ERROR_REF(error), stream_global));
1528
1752
  }
1529
1753
  GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
1530
1754
  }
@@ -1649,6 +1873,8 @@ static void close_from_api(grpc_exec_ctx *exec_ctx,
1649
1873
 
1650
1874
  grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
1651
1875
  1, error);
1876
+ grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
1877
+ "close_from_api");
1652
1878
  }
1653
1879
 
1654
1880
  typedef struct {
@@ -1678,8 +1904,14 @@ static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
1678
1904
  }
1679
1905
 
1680
1906
  /** update window from a settings change */
1907
+ typedef struct {
1908
+ grpc_chttp2_transport *t;
1909
+ grpc_exec_ctx *exec_ctx;
1910
+ } update_global_window_args;
1911
+
1681
1912
  static void update_global_window(void *args, uint32_t id, void *stream) {
1682
- grpc_chttp2_transport *t = args;
1913
+ update_global_window_args *a = args;
1914
+ grpc_chttp2_transport *t = a->t;
1683
1915
  grpc_chttp2_stream *s = stream;
1684
1916
  grpc_chttp2_transport_global *transport_global = &t->global;
1685
1917
  grpc_chttp2_stream_global *stream_global = &s->global;
@@ -1693,7 +1925,8 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
1693
1925
  is_zero = stream_global->outgoing_window <= 0;
1694
1926
 
1695
1927
  if (was_zero && !is_zero) {
1696
- grpc_chttp2_become_writable(transport_global, stream_global);
1928
+ grpc_chttp2_become_writable(a->exec_ctx, transport_global, stream_global,
1929
+ true, "update_global_window");
1697
1930
  }
1698
1931
  }
1699
1932
 
@@ -1801,14 +2034,19 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
1801
2034
  grpc_chttp2_transport_global *transport_global = &t->global;
1802
2035
  grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
1803
2036
  /* copy parsing qbuf to global qbuf */
1804
- gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
2037
+ if (t->parsing.qbuf.count > 0) {
2038
+ gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
2039
+ grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
2040
+ "parsing_qbuf");
2041
+ }
1805
2042
  /* merge stream lists */
1806
2043
  grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map);
1807
2044
  transport_global->concurrent_stream_count =
1808
2045
  (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
1809
2046
  if (transport_parsing->initial_window_update != 0) {
2047
+ update_global_window_args args = {t, exec_ctx};
1810
2048
  grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
1811
- update_global_window, t);
2049
+ update_global_window, &args);
1812
2050
  transport_parsing->initial_window_update = 0;
1813
2051
  }
1814
2052
  /* handle higher level things */
@@ -1831,7 +2069,7 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
1831
2069
  GPR_ASSERT(stream_global->write_closed);
1832
2070
  GPR_ASSERT(stream_global->read_closed);
1833
2071
  remove_stream(exec_ctx, t, stream_global->id,
1834
- GRPC_ERROR_REF(stream_global->removal_error));
2072
+ removal_error(GRPC_ERROR_NONE, stream_global));
1835
2073
  GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
1836
2074
  }
1837
2075
 
@@ -1854,11 +2092,12 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
1854
2092
  }
1855
2093
  drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
1856
2094
  t->endpoint_reading = 0;
1857
- if (!t->executor.writing_active && t->ep) {
1858
- grpc_endpoint_destroy(exec_ctx, t->ep);
1859
- t->ep = NULL;
1860
- /* safe as we still have a ref for read */
1861
- UNREF_TRANSPORT(exec_ctx, t, "disconnect");
2095
+ if (grpc_http_write_state_trace) {
2096
+ gpr_log(GPR_DEBUG, "R:%p -> 0 ws=%s", t,
2097
+ write_state_name(t->executor.write_state));
2098
+ }
2099
+ if (t->executor.write_state == GRPC_CHTTP2_WRITING_INACTIVE && t->ep) {
2100
+ destroy_endpoint(exec_ctx, t);
1862
2101
  }
1863
2102
  } else if (!t->closed) {
1864
2103
  keep_reading = true;
@@ -1942,7 +2181,7 @@ static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
1942
2181
  }
1943
2182
 
1944
2183
  static void incoming_byte_stream_update_flow_control(
1945
- grpc_chttp2_transport_global *transport_global,
2184
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
1946
2185
  grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
1947
2186
  size_t have_already) {
1948
2187
  uint32_t max_recv_bytes;
@@ -1977,7 +2216,8 @@ static void incoming_byte_stream_update_flow_control(
1977
2216
  add_max_recv_bytes);
1978
2217
  grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global,
1979
2218
  stream_global);
1980
- grpc_chttp2_become_writable(transport_global, stream_global);
2219
+ grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
2220
+ false, "read_incoming_stream");
1981
2221
  }
1982
2222
  }
1983
2223
 
@@ -1999,8 +2239,9 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
1999
2239
  grpc_chttp2_stream_global *stream_global = &bs->stream->global;
2000
2240
 
2001
2241
  if (bs->is_tail) {
2002
- incoming_byte_stream_update_flow_control(
2003
- transport_global, stream_global, arg->max_size_hint, bs->slices.length);
2242
+ incoming_byte_stream_update_flow_control(exec_ctx, transport_global,
2243
+ stream_global, arg->max_size_hint,
2244
+ bs->slices.length);
2004
2245
  }
2005
2246
  if (bs->slices.count > 0) {
2006
2247
  *arg->slice = gpr_slice_buffer_take_first(&bs->slices);
@@ -2184,7 +2425,7 @@ static char *format_flowctl_context_var(const char *context, const char *var,
2184
2425
  if (context == NULL) {
2185
2426
  *scope = NULL;
2186
2427
  gpr_asprintf(&buf, "%s(%" PRId64 ")", var, val);
2187
- result = gpr_leftpad(buf, ' ', 40);
2428
+ result = gpr_leftpad(buf, ' ', 60);
2188
2429
  gpr_free(buf);
2189
2430
  return result;
2190
2431
  }
@@ -2197,7 +2438,7 @@ static char *format_flowctl_context_var(const char *context, const char *var,
2197
2438
  gpr_free(tmp);
2198
2439
  }
2199
2440
  gpr_asprintf(&buf, "%s.%s(%" PRId64 ")", underscore_pos + 1, var, val);
2200
- result = gpr_leftpad(buf, ' ', 40);
2441
+ result = gpr_leftpad(buf, ' ', 60);
2201
2442
  gpr_free(buf);
2202
2443
  return result;
2203
2444
  }
@@ -2230,7 +2471,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
2230
2471
 
2231
2472
  tmp_phase = gpr_leftpad(phase, ' ', 8);
2232
2473
  tmp_scope1 = gpr_leftpad(scope1, ' ', 11);
2233
- gpr_asprintf(&prefix, "FLOW %s: %s %s ", phase, clisvr, scope1);
2474
+ gpr_asprintf(&prefix, "FLOW %s: %s %s ", tmp_phase, clisvr, scope1);
2234
2475
  gpr_free(tmp_phase);
2235
2476
  gpr_free(tmp_scope1);
2236
2477