grpc 1.1.2 → 1.2.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +1257 -404
  3. data/etc/roots.pem +189 -102
  4. data/include/grpc/census.h +7 -7
  5. data/include/grpc/compression.h +4 -4
  6. data/include/grpc/grpc.h +13 -7
  7. data/include/grpc/impl/codegen/atm_gcc_atomic.h +26 -9
  8. data/include/grpc/impl/codegen/grpc_types.h +39 -30
  9. data/include/grpc/impl/codegen/slice.h +24 -6
  10. data/include/grpc/impl/codegen/sync.h +8 -0
  11. data/include/grpc/load_reporting.h +63 -0
  12. data/include/grpc/slice.h +37 -1
  13. data/include/grpc/slice_buffer.h +7 -0
  14. data/include/grpc/support/alloc.h +3 -0
  15. data/include/grpc/support/useful.h +3 -0
  16. data/src/core/ext/census/gen/census.pb.h +1 -1
  17. data/src/core/ext/census/gen/trace_context.pb.c +9 -36
  18. data/src/core/ext/census/gen/trace_context.pb.h +20 -26
  19. data/src/core/ext/census/grpc_filter.c +3 -5
  20. data/src/core/ext/census/trace_context.c +1 -1
  21. data/src/core/ext/census/trace_context.h +3 -0
  22. data/src/core/ext/census/trace_label.h +61 -0
  23. data/src/core/ext/census/trace_propagation.h +63 -0
  24. data/src/core/ext/census/trace_status.h +45 -0
  25. data/src/core/ext/census/trace_string.h +50 -0
  26. data/src/core/ext/census/tracing.c +31 -11
  27. data/src/core/ext/census/tracing.h +124 -0
  28. data/src/core/ext/client_channel/client_channel.c +456 -368
  29. data/src/core/ext/client_channel/client_channel.h +4 -0
  30. data/src/core/ext/client_channel/client_channel_plugin.c +6 -1
  31. data/src/core/ext/client_channel/connector.c +3 -3
  32. data/src/core/ext/client_channel/connector.h +4 -3
  33. data/src/core/ext/client_channel/http_connect_handshaker.c +62 -72
  34. data/src/core/ext/client_channel/http_connect_handshaker.h +7 -10
  35. data/src/core/ext/client_channel/http_proxy.c +125 -0
  36. data/src/core/ext/client_channel/http_proxy.h +39 -0
  37. data/src/core/ext/client_channel/lb_policy.c +56 -35
  38. data/src/core/ext/client_channel/lb_policy.h +46 -39
  39. data/src/core/ext/client_channel/lb_policy_factory.h +1 -0
  40. data/src/core/ext/client_channel/parse_address.c +32 -6
  41. data/src/core/ext/client_channel/proxy_mapper.c +63 -0
  42. data/src/core/ext/client_channel/proxy_mapper.h +89 -0
  43. data/src/core/ext/client_channel/proxy_mapper_registry.c +133 -0
  44. data/src/core/ext/client_channel/proxy_mapper_registry.h +59 -0
  45. data/src/core/ext/client_channel/resolver.c +16 -9
  46. data/src/core/ext/client_channel/resolver.h +23 -12
  47. data/src/core/ext/client_channel/resolver_factory.h +1 -0
  48. data/src/core/ext/client_channel/resolver_registry.c +15 -11
  49. data/src/core/ext/client_channel/resolver_registry.h +5 -3
  50. data/src/core/ext/client_channel/subchannel.c +44 -27
  51. data/src/core/ext/client_channel/subchannel.h +6 -2
  52. data/src/core/ext/client_channel/uri_parser.c +26 -14
  53. data/src/core/ext/client_channel/uri_parser.h +3 -1
  54. data/src/core/ext/lb_policy/grpclb/grpclb.c +220 -209
  55. data/src/core/ext/lb_policy/grpclb/grpclb_channel.h +56 -0
  56. data/src/core/ext/lb_policy/grpclb/grpclb_channel_secure.c +107 -0
  57. data/src/core/ext/lb_policy/grpclb/load_balancer_api.c +3 -6
  58. data/src/core/ext/lb_policy/pick_first/pick_first.c +71 -116
  59. data/src/core/ext/lb_policy/round_robin/round_robin.c +52 -67
  60. data/src/core/ext/load_reporting/load_reporting.c +20 -0
  61. data/src/core/ext/load_reporting/load_reporting.h +1 -16
  62. data/src/core/ext/load_reporting/load_reporting_filter.c +28 -54
  63. data/src/core/ext/resolver/dns/native/dns_resolver.c +31 -45
  64. data/src/core/ext/resolver/sockaddr/sockaddr_resolver.c +20 -29
  65. data/src/core/ext/transport/chttp2/client/chttp2_connector.c +11 -8
  66. data/src/core/ext/transport/chttp2/client/insecure/channel_create.c +11 -2
  67. data/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c +143 -46
  68. data/src/core/ext/transport/chttp2/server/chttp2_server.c +12 -50
  69. data/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c +1 -1
  70. data/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c +1 -1
  71. data/src/core/ext/transport/chttp2/transport/bin_decoder.c +7 -7
  72. data/src/core/ext/transport/chttp2/transport/bin_encoder.c +1 -2
  73. data/src/core/ext/transport/chttp2/transport/bin_encoder.h +1 -2
  74. data/src/core/ext/transport/chttp2/transport/chttp2_plugin.c +0 -3
  75. data/src/core/ext/transport/chttp2/transport/chttp2_transport.c +606 -374
  76. data/src/core/ext/transport/chttp2/transport/frame_ping.c +17 -5
  77. data/src/core/ext/transport/chttp2/transport/frame_ping.h +2 -2
  78. data/src/core/ext/transport/chttp2/transport/frame_rst_stream.c +9 -13
  79. data/src/core/ext/transport/chttp2/transport/frame_settings.c +12 -11
  80. data/src/core/ext/transport/chttp2/transport/frame_settings.h +1 -1
  81. data/src/core/ext/transport/chttp2/transport/frame_window_update.c +5 -6
  82. data/src/core/ext/transport/chttp2/transport/hpack_encoder.c +100 -53
  83. data/src/core/ext/transport/chttp2/transport/hpack_encoder.h +2 -2
  84. data/src/core/ext/transport/chttp2/transport/hpack_parser.c +126 -70
  85. data/src/core/ext/transport/chttp2/transport/hpack_parser.h +13 -7
  86. data/src/core/ext/transport/chttp2/transport/hpack_table.c +22 -19
  87. data/src/core/ext/transport/chttp2/transport/hpack_table.h +6 -6
  88. data/src/core/ext/transport/chttp2/transport/incoming_metadata.c +23 -11
  89. data/src/core/ext/transport/chttp2/transport/incoming_metadata.h +6 -2
  90. data/src/core/ext/transport/chttp2/transport/internal.h +169 -42
  91. data/src/core/ext/transport/chttp2/transport/parsing.c +98 -41
  92. data/src/core/ext/transport/chttp2/transport/stream_lists.c +29 -14
  93. data/src/core/ext/transport/chttp2/transport/writing.c +137 -15
  94. data/src/core/lib/channel/channel_stack.c +14 -44
  95. data/src/core/lib/channel/channel_stack.h +10 -17
  96. data/src/core/lib/channel/channel_stack_builder.c +2 -3
  97. data/src/core/lib/channel/compress_filter.c +54 -46
  98. data/src/core/lib/channel/connected_channel.c +4 -4
  99. data/src/core/lib/channel/connected_channel.h +5 -0
  100. data/src/core/lib/channel/context.h +3 -0
  101. data/src/core/lib/channel/deadline_filter.c +61 -61
  102. data/src/core/lib/channel/deadline_filter.h +8 -5
  103. data/src/core/lib/channel/handshaker.c +47 -7
  104. data/src/core/lib/channel/handshaker.h +21 -3
  105. data/src/core/lib/channel/http_client_filter.c +149 -99
  106. data/src/core/lib/channel/http_server_filter.c +163 -147
  107. data/src/core/lib/channel/message_size_filter.c +15 -10
  108. data/src/core/lib/compression/algorithm_metadata.h +4 -4
  109. data/src/core/lib/compression/compression.c +17 -23
  110. data/src/core/lib/http/httpcli.c +3 -2
  111. data/src/core/lib/http/httpcli.h +2 -1
  112. data/src/core/lib/http/httpcli_security_connector.c +2 -3
  113. data/src/core/lib/http/parser.c +2 -2
  114. data/src/core/lib/iomgr/closure.c +6 -3
  115. data/src/core/lib/iomgr/closure.h +4 -2
  116. data/src/core/lib/iomgr/combiner.c +35 -5
  117. data/src/core/lib/iomgr/combiner.h +21 -2
  118. data/src/core/lib/iomgr/endpoint.c +3 -2
  119. data/src/core/lib/iomgr/endpoint.h +3 -2
  120. data/src/core/lib/iomgr/error.c +60 -94
  121. data/src/core/lib/iomgr/error.h +7 -10
  122. data/src/core/lib/iomgr/error_internal.h +54 -0
  123. data/src/core/lib/iomgr/ev_epoll_linux.c +253 -109
  124. data/src/core/lib/iomgr/ev_poll_posix.c +61 -29
  125. data/src/core/lib/iomgr/ev_posix.c +7 -8
  126. data/src/core/lib/iomgr/ev_posix.h +4 -4
  127. data/src/core/lib/iomgr/exec_ctx.c +11 -6
  128. data/src/core/lib/iomgr/exec_ctx.h +11 -14
  129. data/src/core/lib/iomgr/executor.c +2 -2
  130. data/src/core/lib/iomgr/load_file.c +1 -1
  131. data/src/core/lib/iomgr/network_status_tracker.c +5 -81
  132. data/src/core/lib/iomgr/pollset.h +1 -3
  133. data/src/core/lib/iomgr/pollset_set.h +2 -1
  134. data/src/core/lib/iomgr/pollset_set_uv.c +2 -1
  135. data/src/core/lib/iomgr/pollset_set_windows.c +2 -1
  136. data/src/core/lib/iomgr/pollset_uv.c +25 -11
  137. data/src/core/lib/iomgr/pollset_windows.c +0 -11
  138. data/src/core/lib/iomgr/resolve_address_uv.c +50 -2
  139. data/src/core/lib/iomgr/resource_quota.c +41 -11
  140. data/src/core/lib/iomgr/resource_quota.h +6 -0
  141. data/src/core/lib/iomgr/sockaddr_utils.c +33 -17
  142. data/src/core/lib/iomgr/sockaddr_utils.h +4 -0
  143. data/src/core/lib/iomgr/tcp_client_posix.c +2 -3
  144. data/src/core/lib/iomgr/tcp_client_uv.c +1 -3
  145. data/src/core/lib/iomgr/tcp_client_windows.c +21 -6
  146. data/src/core/lib/iomgr/tcp_posix.c +4 -5
  147. data/src/core/lib/iomgr/tcp_server_posix.c +269 -94
  148. data/src/core/lib/iomgr/tcp_server_windows.c +1 -1
  149. data/src/core/lib/iomgr/tcp_uv.c +11 -5
  150. data/src/core/lib/iomgr/tcp_windows.c +20 -7
  151. data/src/core/lib/iomgr/timer_generic.c +15 -22
  152. data/src/core/lib/iomgr/timer_generic.h +1 -1
  153. data/src/core/lib/iomgr/timer_uv.c +10 -6
  154. data/src/core/lib/iomgr/timer_uv.h +1 -1
  155. data/src/core/lib/iomgr/udp_server.c +45 -6
  156. data/src/core/lib/iomgr/udp_server.h +7 -1
  157. data/src/core/lib/iomgr/unix_sockets_posix.c +11 -1
  158. data/src/core/lib/json/json.c +1 -2
  159. data/src/core/lib/profiling/basic_timers.c +17 -3
  160. data/src/core/lib/security/context/security_context.c +3 -10
  161. data/src/core/lib/security/credentials/composite/composite_credentials.c +4 -8
  162. data/src/core/lib/security/credentials/credentials.c +48 -2
  163. data/src/core/lib/security/credentials/credentials.h +13 -0
  164. data/src/core/lib/security/credentials/credentials_metadata.c +1 -2
  165. data/src/core/lib/security/credentials/fake/fake_credentials.c +6 -8
  166. data/src/core/lib/security/credentials/fake/fake_credentials.h +15 -0
  167. data/src/core/lib/security/credentials/google_default/google_default_credentials.c +3 -3
  168. data/src/core/lib/security/credentials/iam/iam_credentials.c +1 -2
  169. data/src/core/lib/security/credentials/jwt/jwt_credentials.c +1 -2
  170. data/src/core/lib/security/credentials/jwt/jwt_verifier.c +5 -8
  171. data/src/core/lib/security/credentials/jwt/jwt_verifier.h +2 -1
  172. data/src/core/lib/security/credentials/oauth2/oauth2_credentials.c +3 -5
  173. data/src/core/lib/security/credentials/plugin/plugin_credentials.c +15 -13
  174. data/src/core/lib/security/credentials/ssl/ssl_credentials.c +2 -4
  175. data/src/core/lib/security/transport/client_auth_filter.c +72 -47
  176. data/src/core/lib/security/transport/lb_targets_info.c +70 -0
  177. data/src/core/lib/security/transport/lb_targets_info.h +47 -0
  178. data/src/core/lib/security/transport/secure_endpoint.c +3 -3
  179. data/src/core/lib/security/transport/security_connector.c +125 -28
  180. data/src/core/lib/security/transport/security_connector.h +4 -3
  181. data/src/core/lib/security/transport/security_handshaker.c +13 -9
  182. data/src/core/lib/security/transport/server_auth_filter.c +31 -40
  183. data/src/core/lib/security/util/b64.c +1 -1
  184. data/src/core/lib/slice/slice.c +110 -20
  185. data/src/core/lib/slice/slice_buffer.c +92 -39
  186. data/src/core/lib/{transport/mdstr_hash_table.c → slice/slice_hash_table.c} +40 -33
  187. data/src/core/lib/{transport/mdstr_hash_table.h → slice/slice_hash_table.h} +21 -21
  188. data/src/core/lib/slice/slice_intern.c +346 -0
  189. data/src/core/lib/slice/slice_internal.h +15 -0
  190. data/src/core/lib/slice/slice_string_helpers.c +5 -0
  191. data/src/core/lib/slice/slice_string_helpers.h +5 -0
  192. data/src/core/lib/support/alloc.c +26 -1
  193. data/src/core/lib/support/cmdline.c +2 -4
  194. data/src/core/lib/support/cpu_posix.c +2 -7
  195. data/src/core/lib/support/histogram.c +1 -2
  196. data/src/core/lib/support/log_posix.c +8 -4
  197. data/src/core/lib/support/spinlock.h +52 -0
  198. data/src/core/lib/support/subprocess_posix.c +1 -2
  199. data/src/core/lib/support/sync.c +7 -1
  200. data/src/core/lib/support/sync_posix.c +9 -0
  201. data/src/core/lib/support/time_windows.c +7 -1
  202. data/src/core/lib/surface/call.c +647 -629
  203. data/src/core/lib/surface/call.h +4 -1
  204. data/src/core/lib/surface/call_details.c +8 -2
  205. data/src/core/lib/surface/call_log_batch.c +17 -6
  206. data/src/core/lib/surface/channel.c +49 -59
  207. data/src/core/lib/surface/channel.h +5 -6
  208. data/src/core/lib/surface/completion_queue.c +16 -45
  209. data/src/core/lib/surface/completion_queue.h +0 -3
  210. data/src/core/lib/surface/init.c +6 -2
  211. data/src/core/lib/surface/init_secure.c +1 -1
  212. data/src/core/lib/surface/lame_client.c +14 -4
  213. data/src/core/lib/surface/server.c +79 -82
  214. data/src/core/lib/surface/validate_metadata.c +46 -15
  215. data/src/core/lib/surface/validate_metadata.h +43 -0
  216. data/src/core/lib/surface/version.c +2 -2
  217. data/src/core/lib/transport/bdp_estimator.c +104 -0
  218. data/src/core/lib/transport/bdp_estimator.h +76 -0
  219. data/src/core/lib/transport/connectivity_state.c +33 -13
  220. data/src/core/lib/transport/connectivity_state.h +15 -5
  221. data/src/core/lib/transport/error_utils.c +124 -0
  222. data/src/core/lib/transport/error_utils.h +56 -0
  223. data/src/core/{ext/transport/chttp2 → lib}/transport/http2_errors.h +18 -18
  224. data/src/core/lib/transport/metadata.c +259 -503
  225. data/src/core/lib/transport/metadata.h +69 -68
  226. data/src/core/lib/transport/metadata_batch.c +183 -63
  227. data/src/core/lib/transport/metadata_batch.h +50 -26
  228. data/src/core/lib/transport/pid_controller.c +28 -8
  229. data/src/core/lib/transport/pid_controller.h +15 -2
  230. data/src/core/lib/transport/service_config.c +21 -18
  231. data/src/core/lib/transport/service_config.h +5 -5
  232. data/src/core/lib/transport/static_metadata.c +753 -112
  233. data/src/core/lib/transport/static_metadata.h +403 -264
  234. data/src/core/{ext/transport/chttp2 → lib}/transport/status_conversion.c +18 -20
  235. data/src/core/{ext/transport/chttp2 → lib}/transport/status_conversion.h +9 -10
  236. data/src/core/lib/transport/timeout_encoding.c +11 -9
  237. data/src/core/lib/transport/timeout_encoding.h +3 -1
  238. data/src/core/lib/transport/transport.c +47 -87
  239. data/src/core/lib/transport/transport.h +20 -25
  240. data/src/core/lib/transport/transport_op_string.c +7 -19
  241. data/src/core/lib/tsi/fake_transport_security.c +2 -4
  242. data/src/core/lib/tsi/ssl_transport_security.c +7 -16
  243. data/src/core/lib/tsi/transport_security.c +2 -4
  244. data/src/ruby/ext/grpc/extconf.rb +4 -1
  245. data/src/ruby/ext/grpc/rb_byte_buffer.c +7 -0
  246. data/src/ruby/ext/grpc/rb_byte_buffer.h +3 -0
  247. data/src/ruby/ext/grpc/rb_call.c +47 -46
  248. data/src/ruby/ext/grpc/rb_channel.c +21 -6
  249. data/src/ruby/ext/grpc/rb_compression_options.c +9 -6
  250. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +36 -2
  251. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +59 -8
  252. data/src/ruby/ext/grpc/rb_server.c +6 -4
  253. data/src/ruby/lib/grpc/generic/client_stub.rb +1 -1
  254. data/src/ruby/lib/grpc/version.rb +1 -1
  255. metadata +33 -9
@@ -46,4 +46,19 @@ void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx *exec_ctx,
46
46
  void grpc_slice_buffer_destroy_internal(grpc_exec_ctx *exec_ctx,
47
47
  grpc_slice_buffer *sb);
48
48
 
49
+ /* Check if a slice is interned */
50
+ bool grpc_slice_is_interned(grpc_slice slice);
51
+
52
+ void grpc_slice_intern_init(void);
53
+ void grpc_slice_intern_shutdown(void);
54
+ void grpc_test_only_set_slice_hash_seed(uint32_t key);
55
+ // if slice matches a static slice, returns the static slice
56
+ // otherwise returns the passed in slice (without reffing it)
57
+ // used for surface boundaries where we might receive an un-interned static
58
+ // string
59
+ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
60
+ bool *returned_slice_is_different);
61
+ uint32_t grpc_static_slice_hash(grpc_slice s);
62
+ int grpc_static_slice_eq(grpc_slice a, grpc_slice b);
63
+
49
64
  #endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */
@@ -88,3 +88,8 @@ void grpc_slice_split(grpc_slice str, const char *sep, grpc_slice_buffer *dst) {
88
88
  grpc_slice_buffer_add_indexed(dst, grpc_slice_ref_internal(str));
89
89
  }
90
90
  }
91
+
92
+ bool grpc_parse_slice_to_uint32(grpc_slice str, uint32_t *result) {
93
+ return gpr_parse_bytes_to_uint32((const char *)GRPC_SLICE_START_PTR(str),
94
+ GRPC_SLICE_LENGTH(str), result) != 0;
95
+ }
@@ -34,12 +34,15 @@
34
34
  #ifndef GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H
35
35
  #define GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H
36
36
 
37
+ #include <stdbool.h>
37
38
  #include <stddef.h>
38
39
 
39
40
  #include <grpc/slice.h>
40
41
  #include <grpc/slice_buffer.h>
41
42
  #include <grpc/support/port_platform.h>
42
43
 
44
+ #include "src/core/lib/support/string.h"
45
+
43
46
  #ifdef __cplusplus
44
47
  extern "C" {
45
48
  #endif
@@ -51,6 +54,8 @@ char *grpc_dump_slice(grpc_slice slice, uint32_t flags);
51
54
  * should be a properly initialized instance. */
52
55
  void grpc_slice_split(grpc_slice str, const char *sep, grpc_slice_buffer *dst);
53
56
 
57
+ bool grpc_parse_slice_to_uint32(grpc_slice str, uint32_t *result);
58
+
54
59
  #ifdef __cplusplus
55
60
  }
56
61
  #endif
@@ -36,9 +36,19 @@
36
36
  #include <grpc/support/log.h>
37
37
  #include <grpc/support/port_platform.h>
38
38
  #include <stdlib.h>
39
+ #include <string.h>
39
40
  #include "src/core/lib/profiling/timers.h"
40
41
 
41
- static gpr_allocation_functions g_alloc_functions = {malloc, realloc, free};
42
+ static void *zalloc_with_calloc(size_t sz) { return calloc(sz, 1); }
43
+
44
+ static void *zalloc_with_gpr_malloc(size_t sz) {
45
+ void *p = gpr_malloc(sz);
46
+ memset(p, 0, sz);
47
+ return p;
48
+ }
49
+
50
+ static gpr_allocation_functions g_alloc_functions = {malloc, zalloc_with_calloc,
51
+ realloc, free};
42
52
 
43
53
  gpr_allocation_functions gpr_get_allocation_functions() {
44
54
  return g_alloc_functions;
@@ -48,6 +58,9 @@ void gpr_set_allocation_functions(gpr_allocation_functions functions) {
48
58
  GPR_ASSERT(functions.malloc_fn != NULL);
49
59
  GPR_ASSERT(functions.realloc_fn != NULL);
50
60
  GPR_ASSERT(functions.free_fn != NULL);
61
+ if (functions.zalloc_fn == NULL) {
62
+ functions.zalloc_fn = zalloc_with_gpr_malloc;
63
+ }
51
64
  g_alloc_functions = functions;
52
65
  }
53
66
 
@@ -63,6 +76,18 @@ void *gpr_malloc(size_t size) {
63
76
  return p;
64
77
  }
65
78
 
79
+ void *gpr_zalloc(size_t size) {
80
+ void *p;
81
+ if (size == 0) return NULL;
82
+ GPR_TIMER_BEGIN("gpr_zalloc", 0);
83
+ p = g_alloc_functions.zalloc_fn(size);
84
+ if (!p) {
85
+ abort();
86
+ }
87
+ GPR_TIMER_END("gpr_zalloc", 0);
88
+ return p;
89
+ }
90
+
66
91
  void gpr_free(void *p) {
67
92
  GPR_TIMER_BEGIN("gpr_free", 0);
68
93
  g_alloc_functions.free_fn(p);
@@ -71,8 +71,7 @@ struct gpr_cmdline {
71
71
  static int normal_state(gpr_cmdline *cl, char *arg);
72
72
 
73
73
  gpr_cmdline *gpr_cmdline_create(const char *description) {
74
- gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline));
75
- memset(cl, 0, sizeof(gpr_cmdline));
74
+ gpr_cmdline *cl = gpr_zalloc(sizeof(gpr_cmdline));
76
75
 
77
76
  cl->description = description;
78
77
  cl->state = normal_state;
@@ -101,8 +100,7 @@ static void add_arg(gpr_cmdline *cl, const char *name, const char *help,
101
100
  GPR_ASSERT(0 != strcmp(a->name, name));
102
101
  }
103
102
 
104
- a = gpr_malloc(sizeof(arg));
105
- memset(a, 0, sizeof(arg));
103
+ a = gpr_zalloc(sizeof(arg));
106
104
  a->name = name;
107
105
  a->help = help;
108
106
  a->type = type;
@@ -41,6 +41,7 @@
41
41
 
42
42
  #include <grpc/support/log.h>
43
43
  #include <grpc/support/sync.h>
44
+ #include <grpc/support/useful.h>
44
45
 
45
46
  static __thread char magic_thread_local;
46
47
 
@@ -60,18 +61,12 @@ unsigned gpr_cpu_num_cores(void) {
60
61
  return (unsigned)ncpus;
61
62
  }
62
63
 
63
- /* This is a cheap, but good enough, pointer hash for sharding things: */
64
- static size_t shard_ptr(const void *info) {
65
- size_t x = (size_t)info;
66
- return ((x >> 4) ^ (x >> 9) ^ (x >> 14)) % gpr_cpu_num_cores();
67
- }
68
-
69
64
  unsigned gpr_cpu_current_cpu(void) {
70
65
  /* NOTE: there's no way I know to return the actual cpu index portably...
71
66
  most code that's using this is using it to shard across work queues though,
72
67
  so here we use thread identity instead to achieve a similar though not
73
68
  identical effect */
74
- return (unsigned)shard_ptr(&magic_thread_local);
69
+ return (unsigned)GPR_HASH_POINTER(&magic_thread_local, gpr_cpu_num_cores());
75
70
  }
76
71
 
77
72
  #endif /* GPR_CPU_POSIX */
@@ -102,8 +102,7 @@ gpr_histogram *gpr_histogram_create(double resolution,
102
102
  h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1;
103
103
  GPR_ASSERT(h->num_buckets > 1);
104
104
  GPR_ASSERT(h->num_buckets < 100000000);
105
- h->buckets = gpr_malloc(sizeof(uint32_t) * h->num_buckets);
106
- memset(h->buckets, 0, sizeof(uint32_t) * h->num_buckets);
105
+ h->buckets = gpr_zalloc(sizeof(uint32_t) * h->num_buckets);
107
106
  return h;
108
107
  }
109
108
 
@@ -37,6 +37,7 @@
37
37
 
38
38
  #include <grpc/support/alloc.h>
39
39
  #include <grpc/support/log.h>
40
+ #include <grpc/support/string_util.h>
40
41
  #include <grpc/support/time.h>
41
42
  #include <pthread.h>
42
43
  #include <stdarg.h>
@@ -93,10 +94,13 @@ void gpr_default_log(gpr_log_func_args *args) {
93
94
  strcpy(time_buffer, "error:strftime");
94
95
  }
95
96
 
96
- fprintf(stderr, "%s%s.%09d %7tu %s:%d] %s\n",
97
- gpr_log_severity_string(args->severity), time_buffer,
98
- (int)(now.tv_nsec), gettid(), display_file, args->line,
99
- args->message);
97
+ char *prefix;
98
+ gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]",
99
+ gpr_log_severity_string(args->severity), time_buffer,
100
+ (int)(now.tv_nsec), gettid(), display_file, args->line);
101
+
102
+ fprintf(stderr, "%-70s %s\n", prefix, args->message);
103
+ gpr_free(prefix);
100
104
  }
101
105
 
102
106
  #endif /* defined(GPR_POSIX_LOG) */
@@ -0,0 +1,52 @@
1
+ /*
2
+ *
3
+ * Copyright 2015, Google Inc.
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are
8
+ * met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright
11
+ * notice, this list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above
13
+ * copyright notice, this list of conditions and the following disclaimer
14
+ * in the documentation and/or other materials provided with the
15
+ * distribution.
16
+ * * Neither the name of Google Inc. nor the names of its
17
+ * contributors may be used to endorse or promote products derived from
18
+ * this software without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ *
32
+ */
33
+
34
+ #ifndef GRPC_CORE_LIB_SUPPORT_SPINLOCK_H
35
+ #define GRPC_CORE_LIB_SUPPORT_SPINLOCK_H
36
+
37
+ #include <grpc/support/atm.h>
38
+
39
+ /* Simple spinlock. No backoff strategy, gpr_spinlock_lock is almost always
40
+ a concurrency code smell. */
41
+ typedef struct { gpr_atm atm; } gpr_spinlock;
42
+
43
+ #define GPR_SPINLOCK_INITIALIZER ((gpr_spinlock){0})
44
+ #define GPR_SPINLOCK_STATIC_INITIALIZER \
45
+ { 0 }
46
+ #define gpr_spinlock_trylock(lock) (gpr_atm_acq_cas(&(lock)->atm, 0, 1))
47
+ #define gpr_spinlock_unlock(lock) (gpr_atm_rel_store(&(lock)->atm, 0))
48
+ #define gpr_spinlock_lock(lock) \
49
+ do { \
50
+ } while (!gpr_spinlock_trylock((lock)))
51
+
52
+ #endif /* GRPC_CORE_LIB_SUPPORT_SPINLOCK_H */
@@ -76,8 +76,7 @@ gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) {
76
76
  _exit(1);
77
77
  return NULL;
78
78
  } else {
79
- r = gpr_malloc(sizeof(gpr_subprocess));
80
- memset(r, 0, sizeof(*r));
79
+ r = gpr_zalloc(sizeof(gpr_subprocess));
81
80
  r->pid = pid;
82
81
  return r;
83
82
  }
@@ -37,6 +37,8 @@
37
37
  #include <grpc/support/log.h>
38
38
  #include <grpc/support/sync.h>
39
39
 
40
+ #include <assert.h>
41
+
40
42
  /* Number of mutexes to allocate for events, to avoid lock contention.
41
43
  Should be a prime. */
42
44
  enum { event_sync_partitions = 31 };
@@ -99,8 +101,12 @@ void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); }
99
101
  void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); }
100
102
 
101
103
  void gpr_ref_non_zero(gpr_refcount *r) {
104
+ #ifndef NDEBUG
102
105
  gpr_atm prior = gpr_atm_no_barrier_fetch_add(&r->count, 1);
103
- GPR_ASSERT(prior > 0);
106
+ assert(prior > 0);
107
+ #else
108
+ gpr_ref(r);
109
+ #endif
104
110
  }
105
111
 
106
112
  void gpr_refn(gpr_refcount *r, int n) {
@@ -42,11 +42,20 @@
42
42
  #include <time.h>
43
43
  #include "src/core/lib/profiling/timers.h"
44
44
 
45
+ #ifdef GPR_LOW_LEVEL_COUNTERS
46
+ gpr_atm gpr_mu_locks = 0;
47
+ gpr_atm gpr_counter_atm_cas = 0;
48
+ gpr_atm gpr_counter_atm_add = 0;
49
+ #endif
50
+
45
51
  void gpr_mu_init(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); }
46
52
 
47
53
  void gpr_mu_destroy(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); }
48
54
 
49
55
  void gpr_mu_lock(gpr_mu* mu) {
56
+ #ifdef GPR_LOW_LEVEL_COUNTERS
57
+ GPR_ATM_INC_COUNTER(gpr_mu_locks);
58
+ #endif
50
59
  GPR_TIMER_BEGIN("gpr_mu_lock", 0);
51
60
  GPR_ASSERT(pthread_mutex_lock(mu) == 0);
52
61
  GPR_TIMER_END("gpr_mu_lock", 0);
@@ -56,7 +56,7 @@ void gpr_time_init(void) {
56
56
  g_time_scale = 1.0 / (double)frequency.QuadPart;
57
57
  }
58
58
 
59
- gpr_timespec gpr_now(gpr_clock_type clock) {
59
+ static gpr_timespec now_impl(gpr_clock_type clock) {
60
60
  gpr_timespec now_tv;
61
61
  LONGLONG diff;
62
62
  struct _timeb now_tb;
@@ -84,6 +84,12 @@ gpr_timespec gpr_now(gpr_clock_type clock) {
84
84
  return now_tv;
85
85
  }
86
86
 
87
+ gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type) = now_impl;
88
+
89
+ gpr_timespec gpr_now(gpr_clock_type clock_type) {
90
+ return gpr_now_impl(clock_type);
91
+ }
92
+
87
93
  void gpr_sleep_until(gpr_timespec until) {
88
94
  gpr_timespec now;
89
95
  gpr_timespec delta;
@@ -56,13 +56,15 @@
56
56
  #include "src/core/lib/surface/call.h"
57
57
  #include "src/core/lib/surface/channel.h"
58
58
  #include "src/core/lib/surface/completion_queue.h"
59
+ #include "src/core/lib/surface/validate_metadata.h"
60
+ #include "src/core/lib/transport/error_utils.h"
59
61
  #include "src/core/lib/transport/metadata.h"
60
62
  #include "src/core/lib/transport/static_metadata.h"
61
63
  #include "src/core/lib/transport/transport.h"
62
64
 
63
65
  /** The maximum number of concurrent batches possible.
64
66
  Based upon the maximum number of individually queueable ops in the batch
65
- api:
67
+ api:
66
68
  - initial metadata send
67
69
  - message send
68
70
  - status/close send (depending on client/server)
@@ -84,26 +86,43 @@ typedef enum {
84
86
  /* Status came from 'the wire' - or somewhere below the surface
85
87
  layer */
86
88
  STATUS_FROM_WIRE,
87
- /* Status was created by some internal channel stack operation */
89
+ /* Status was created by some internal channel stack operation: must come via
90
+ add_batch_error */
88
91
  STATUS_FROM_CORE,
92
+ /* Status was created by some surface error */
93
+ STATUS_FROM_SURFACE,
89
94
  /* Status came from the server sending status */
90
95
  STATUS_FROM_SERVER_STATUS,
91
96
  STATUS_SOURCE_COUNT
92
97
  } status_source;
93
98
 
94
99
  typedef struct {
95
- uint8_t is_set;
96
- grpc_status_code code;
97
- grpc_mdstr *details;
100
+ bool is_set;
101
+ grpc_error *error;
98
102
  } received_status;
99
103
 
104
+ static gpr_atm pack_received_status(received_status r) {
105
+ return r.is_set ? (1 | (gpr_atm)r.error) : 0;
106
+ }
107
+
108
+ static received_status unpack_received_status(gpr_atm atm) {
109
+ return (atm & 1) == 0
110
+ ? (received_status){.is_set = false, .error = GRPC_ERROR_NONE}
111
+ : (received_status){.is_set = true,
112
+ .error = (grpc_error *)(atm & ~(gpr_atm)1)};
113
+ }
114
+
115
+ #define MAX_ERRORS_PER_BATCH 4
116
+
100
117
  typedef struct batch_control {
101
118
  grpc_call *call;
102
119
  grpc_cq_completion cq_completion;
103
120
  grpc_closure finish_batch;
104
121
  void *notify_tag;
105
122
  gpr_refcount steps_to_complete;
106
- grpc_error *error;
123
+
124
+ grpc_error *errors[MAX_ERRORS_PER_BATCH];
125
+ gpr_atm num_errors;
107
126
 
108
127
  uint8_t send_initial_metadata;
109
128
  uint8_t send_message;
@@ -134,8 +153,6 @@ struct grpc_call {
134
153
  bool destroy_called;
135
154
  /** flag indicating that cancellation is inherited */
136
155
  bool cancellation_is_inherited;
137
- /** bitmask of live batches */
138
- uint8_t used_batches;
139
156
  /** which ops are in-flight */
140
157
  bool sent_initial_metadata;
141
158
  bool sending_message;
@@ -144,6 +161,7 @@ struct grpc_call {
144
161
  bool receiving_message;
145
162
  bool requested_final_op;
146
163
  bool received_final_op;
164
+ bool sent_any_op;
147
165
 
148
166
  /* have we received initial metadata */
149
167
  bool has_initial_md_been_received;
@@ -157,8 +175,8 @@ struct grpc_call {
157
175
  Element 0 is initial metadata, element 1 is trailing metadata. */
158
176
  grpc_metadata_array *buffered_metadata[2];
159
177
 
160
- /* Received call statuses from various sources */
161
- received_status status[STATUS_SOURCE_COUNT];
178
+ /* Packed received call statuses from various sources */
179
+ gpr_atm status[STATUS_SOURCE_COUNT];
162
180
 
163
181
  /* Call data useful used for reporting. Only valid after the call has
164
182
  * completed */
@@ -185,6 +203,7 @@ struct grpc_call {
185
203
  grpc_call *sibling_prev;
186
204
 
187
205
  grpc_slice_buffer_stream sending_stream;
206
+
188
207
  grpc_byte_stream *receiving_stream;
189
208
  grpc_byte_buffer **receiving_buffer;
190
209
  grpc_slice receiving_slice;
@@ -196,8 +215,7 @@ struct grpc_call {
196
215
  union {
197
216
  struct {
198
217
  grpc_status_code *status;
199
- char **status_details;
200
- size_t *status_details_capacity;
218
+ grpc_slice *status_details;
201
219
  } client;
202
220
  struct {
203
221
  int *cancelled;
@@ -207,6 +225,8 @@ struct grpc_call {
207
225
  void *saved_receiving_stream_ready_bctlp;
208
226
  };
209
227
 
228
+ int grpc_call_error_trace = 0;
229
+
210
230
  #define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
211
231
  #define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
212
232
  #define CALL_ELEM_FROM_CALL(call, idx) \
@@ -216,28 +236,45 @@ struct grpc_call {
216
236
 
217
237
  static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
218
238
  grpc_transport_stream_op *op);
219
- static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
220
- grpc_status_code status,
221
- const char *description);
222
- static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
223
- grpc_status_code status,
224
- const char *description);
239
+ static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
240
+ status_source source, grpc_status_code status,
241
+ const char *description);
242
+ static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
243
+ status_source source, grpc_error *error);
225
244
  static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
226
245
  grpc_error *error);
227
246
  static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
228
247
  grpc_error *error);
248
+ static void get_final_status(grpc_call *call,
249
+ void (*set_value)(grpc_status_code code,
250
+ void *user_data),
251
+ void *set_value_user_data, grpc_slice *details);
252
+ static void set_status_value_directly(grpc_status_code status, void *dest);
253
+ static void set_status_from_error(grpc_exec_ctx *exec_ctx, grpc_call *call,
254
+ status_source source, grpc_error *error);
255
+ static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl);
256
+ static void post_batch_completion(grpc_exec_ctx *exec_ctx, batch_control *bctl);
257
+ static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl,
258
+ grpc_error *error, bool has_cancelled);
259
+
260
+ static void add_init_error(grpc_error **composite, grpc_error *new) {
261
+ if (new == GRPC_ERROR_NONE) return;
262
+ if (*composite == GRPC_ERROR_NONE)
263
+ *composite = GRPC_ERROR_CREATE("Call creation failed");
264
+ *composite = grpc_error_add_child(*composite, new);
265
+ }
229
266
 
230
267
  grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
231
268
  const grpc_call_create_args *args,
232
269
  grpc_call **out_call) {
233
270
  size_t i, j;
271
+ grpc_error *error = GRPC_ERROR_NONE;
234
272
  grpc_channel_stack *channel_stack =
235
273
  grpc_channel_get_channel_stack(args->channel);
236
274
  grpc_call *call;
237
275
  GPR_TIMER_BEGIN("grpc_call_create", 0);
238
- call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
276
+ call = gpr_zalloc(sizeof(grpc_call) + channel_stack->call_stack_size);
239
277
  *out_call = call;
240
- memset(call, 0, sizeof(grpc_call));
241
278
  gpr_mu_init(&call->mu);
242
279
  call->channel = args->channel;
243
280
  call->cq = args->cq;
@@ -246,14 +283,16 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
246
283
  /* Always support no compression */
247
284
  GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
248
285
  call->is_client = args->server_transport_data == NULL;
249
- grpc_mdstr *path = NULL;
286
+ grpc_slice path = grpc_empty_slice();
250
287
  if (call->is_client) {
251
288
  GPR_ASSERT(args->add_initial_metadata_count <
252
289
  MAX_SEND_EXTRA_METADATA_COUNT);
253
290
  for (i = 0; i < args->add_initial_metadata_count; i++) {
254
291
  call->send_extra_metadata[i].md = args->add_initial_metadata[i];
255
- if (args->add_initial_metadata[i]->key == GRPC_MDSTR_PATH) {
256
- path = GRPC_MDSTR_REF(args->add_initial_metadata[i]->value);
292
+ if (grpc_slice_eq(GRPC_MDKEY(args->add_initial_metadata[i]),
293
+ GRPC_MDSTR_PATH)) {
294
+ path = grpc_slice_ref_internal(
295
+ GRPC_MDVALUE(args->add_initial_metadata[i]));
257
296
  }
258
297
  }
259
298
  call->send_extra_metadata_count = (int)args->add_initial_metadata_count;
@@ -287,12 +326,18 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
287
326
  /* TODO(ctiller): This should change to use the appropriate census start_op
288
327
  * call. */
289
328
  if (args->propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) {
290
- GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
329
+ if (0 == (args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT)) {
330
+ add_init_error(&error,
331
+ GRPC_ERROR_CREATE("Census tracing propagation requested "
332
+ "without Census context propagation"));
333
+ }
291
334
  grpc_call_context_set(
292
335
  call, GRPC_CONTEXT_TRACING,
293
336
  args->parent_call->context[GRPC_CONTEXT_TRACING].value, NULL);
294
- } else {
295
- GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
337
+ } else if (args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT) {
338
+ add_init_error(&error,
339
+ GRPC_ERROR_CREATE("Census context propagation requested "
340
+ "without Census tracing propagation"));
296
341
  }
297
342
  if (args->propagation_mask & GRPC_PROPAGATE_CANCELLATION) {
298
343
  call->cancellation_is_inherited = 1;
@@ -315,15 +360,14 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
315
360
 
316
361
  GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
317
362
  /* initial refcount dropped by grpc_call_destroy */
318
- grpc_error *error = grpc_call_stack_init(
319
- exec_ctx, channel_stack, 1, destroy_call, call, call->context,
320
- args->server_transport_data, path, call->start_time, send_deadline,
321
- CALL_STACK_FROM_CALL(call));
363
+ add_init_error(&error, grpc_call_stack_init(exec_ctx, channel_stack, 1,
364
+ destroy_call, call, call->context,
365
+ args->server_transport_data, path,
366
+ call->start_time, send_deadline,
367
+ CALL_STACK_FROM_CALL(call)));
322
368
  if (error != GRPC_ERROR_NONE) {
323
- grpc_status_code status;
324
- const char *error_str;
325
- grpc_error_get_status(error, &status, &error_str);
326
- close_with_status(exec_ctx, call, status, error_str);
369
+ cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE,
370
+ GRPC_ERROR_REF(error));
327
371
  }
328
372
  if (args->cq != NULL) {
329
373
  GPR_ASSERT(
@@ -342,7 +386,7 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
342
386
  exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
343
387
  }
344
388
 
345
- if (path != NULL) GRPC_MDSTR_UNREF(exec_ctx, path);
389
+ grpc_slice_unref_internal(exec_ctx, path);
346
390
 
347
391
  GPR_TIMER_END("grpc_call_create", 0);
348
392
  return error;
@@ -377,24 +421,6 @@ void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) {
377
421
  GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
378
422
  }
379
423
 
380
- static void get_final_status(grpc_call *call,
381
- void (*set_value)(grpc_status_code code,
382
- void *user_data),
383
- void *set_value_user_data) {
384
- int i;
385
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
386
- if (call->status[i].is_set) {
387
- set_value(call->status[i].code, set_value_user_data);
388
- return;
389
- }
390
- }
391
- if (call->is_client) {
392
- set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
393
- } else {
394
- set_value(GRPC_STATUS_OK, set_value_user_data);
395
- }
396
- }
397
-
398
424
  static void set_status_value_directly(grpc_status_code status, void *dest);
399
425
  static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
400
426
  grpc_error *error) {
@@ -410,11 +436,6 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
410
436
  grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
411
437
  }
412
438
  gpr_mu_destroy(&c->mu);
413
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
414
- if (c->status[i].details) {
415
- GRPC_MDSTR_UNREF(exec_ctx, c->status[i].details);
416
- }
417
- }
418
439
  for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
419
440
  GRPC_MDELEM_UNREF(exec_ctx, c->send_extra_metadata[ii].md);
420
441
  }
@@ -428,42 +449,263 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
428
449
  }
429
450
  grpc_channel *channel = c->channel;
430
451
 
431
- get_final_status(call, set_status_value_directly,
432
- &c->final_info.final_status);
452
+ get_final_status(call, set_status_value_directly, &c->final_info.final_status,
453
+ NULL);
433
454
  c->final_info.stats.latency =
434
455
  gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
435
456
 
457
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
458
+ GRPC_ERROR_UNREF(
459
+ unpack_received_status(gpr_atm_no_barrier_load(&c->status[i])).error);
460
+ }
461
+
436
462
  grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->final_info, c);
437
463
  GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
438
464
  GPR_TIMER_END("destroy_call", 0);
439
465
  }
440
466
 
441
- static void set_status_code(grpc_call *call, status_source source,
442
- uint32_t status) {
443
- if (call->status[source].is_set) return;
467
+ void grpc_call_destroy(grpc_call *c) {
468
+ int cancel;
469
+ grpc_call *parent = c->parent;
470
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
471
+
472
+ GPR_TIMER_BEGIN("grpc_call_destroy", 0);
473
+ GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
474
+
475
+ if (parent) {
476
+ gpr_mu_lock(&parent->mu);
477
+ if (c == parent->first_child) {
478
+ parent->first_child = c->sibling_next;
479
+ if (c == parent->first_child) {
480
+ parent->first_child = NULL;
481
+ }
482
+ c->sibling_prev->sibling_next = c->sibling_next;
483
+ c->sibling_next->sibling_prev = c->sibling_prev;
484
+ }
485
+ gpr_mu_unlock(&parent->mu);
486
+ GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
487
+ }
488
+
489
+ gpr_mu_lock(&c->mu);
490
+ GPR_ASSERT(!c->destroy_called);
491
+ c->destroy_called = 1;
492
+ cancel = c->sent_any_op && !c->received_final_op;
493
+ gpr_mu_unlock(&c->mu);
494
+ if (cancel) {
495
+ cancel_with_error(&exec_ctx, c, STATUS_FROM_API_OVERRIDE,
496
+ GRPC_ERROR_CANCELLED);
497
+ }
498
+ GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy");
499
+ grpc_exec_ctx_finish(&exec_ctx);
500
+ GPR_TIMER_END("grpc_call_destroy", 0);
501
+ }
502
+
503
+ grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
504
+ GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
505
+ GPR_ASSERT(!reserved);
506
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
507
+ cancel_with_error(&exec_ctx, call, STATUS_FROM_API_OVERRIDE,
508
+ GRPC_ERROR_CANCELLED);
509
+ grpc_exec_ctx_finish(&exec_ctx);
510
+ return GRPC_CALL_OK;
511
+ }
512
+
513
+ static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
514
+ grpc_transport_stream_op *op) {
515
+ grpc_call_element *elem;
516
+
517
+ GPR_TIMER_BEGIN("execute_op", 0);
518
+ elem = CALL_ELEM_FROM_CALL(call, 0);
519
+ op->context = call->context;
520
+ elem->filter->start_transport_stream_op(exec_ctx, elem, op);
521
+ GPR_TIMER_END("execute_op", 0);
522
+ }
523
+
524
+ char *grpc_call_get_peer(grpc_call *call) {
525
+ grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
526
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
527
+ char *result;
528
+ GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
529
+ result = elem->filter->get_peer(&exec_ctx, elem);
530
+ if (result == NULL) {
531
+ result = grpc_channel_get_target(call->channel);
532
+ }
533
+ if (result == NULL) {
534
+ result = gpr_strdup("unknown");
535
+ }
536
+ grpc_exec_ctx_finish(&exec_ctx);
537
+ return result;
538
+ }
539
+
540
+ grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
541
+ return CALL_FROM_TOP_ELEM(elem);
542
+ }
543
+
544
+ /*******************************************************************************
545
+ * CANCELLATION
546
+ */
547
+
548
+ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
549
+ grpc_status_code status,
550
+ const char *description,
551
+ void *reserved) {
552
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
553
+ GRPC_API_TRACE(
554
+ "grpc_call_cancel_with_status("
555
+ "c=%p, status=%d, description=%s, reserved=%p)",
556
+ 4, (c, (int)status, description, reserved));
557
+ GPR_ASSERT(reserved == NULL);
558
+ gpr_mu_lock(&c->mu);
559
+ cancel_with_status(&exec_ctx, c, STATUS_FROM_API_OVERRIDE, status,
560
+ description);
561
+ gpr_mu_unlock(&c->mu);
562
+ grpc_exec_ctx_finish(&exec_ctx);
563
+ return GRPC_CALL_OK;
564
+ }
565
+
566
+ typedef struct termination_closure {
567
+ grpc_closure closure;
568
+ grpc_call *call;
569
+ grpc_transport_stream_op op;
570
+ } termination_closure;
571
+
572
+ static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
573
+ grpc_error *error) {
574
+ termination_closure *tc = tcp;
575
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "termination");
576
+ gpr_free(tc);
577
+ }
578
+
579
+ static void send_termination(grpc_exec_ctx *exec_ctx, void *tcp,
580
+ grpc_error *error) {
581
+ termination_closure *tc = tcp;
582
+ memset(&tc->op, 0, sizeof(tc->op));
583
+ tc->op.cancel_error = GRPC_ERROR_REF(error);
584
+ /* reuse closure to catch completion */
585
+ tc->op.on_complete = grpc_closure_init(&tc->closure, done_termination, tc,
586
+ grpc_schedule_on_exec_ctx);
587
+ execute_op(exec_ctx, tc->call, &tc->op);
588
+ }
589
+
590
+ static void terminate_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
591
+ grpc_error *error) {
592
+ termination_closure *tc = gpr_malloc(sizeof(*tc));
593
+ memset(tc, 0, sizeof(*tc));
594
+ tc->call = c;
595
+ GRPC_CALL_INTERNAL_REF(tc->call, "termination");
596
+ grpc_closure_sched(exec_ctx, grpc_closure_init(&tc->closure, send_termination,
597
+ tc, grpc_schedule_on_exec_ctx),
598
+ error);
599
+ }
600
+
601
+ static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
602
+ status_source source, grpc_error *error) {
603
+ set_status_from_error(exec_ctx, c, source, GRPC_ERROR_REF(error));
604
+ terminate_with_error(exec_ctx, c, error);
605
+ }
606
+
607
+ static grpc_error *error_from_status(grpc_status_code status,
608
+ const char *description) {
609
+ return grpc_error_set_int(
610
+ grpc_error_set_str(GRPC_ERROR_CREATE(description),
611
+ GRPC_ERROR_STR_GRPC_MESSAGE, description),
612
+ GRPC_ERROR_INT_GRPC_STATUS, status);
613
+ }
614
+
615
+ static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
616
+ status_source source, grpc_status_code status,
617
+ const char *description) {
618
+ cancel_with_error(exec_ctx, c, source,
619
+ error_from_status(status, description));
620
+ }
444
621
 
445
- call->status[source].is_set = 1;
446
- call->status[source].code = (grpc_status_code)status;
622
+ /*******************************************************************************
623
+ * FINAL STATUS CODE MANIPULATION
624
+ */
625
+
626
+ static bool get_final_status_from(
627
+ grpc_call *call, grpc_error *error, bool allow_ok_status,
628
+ void (*set_value)(grpc_status_code code, void *user_data),
629
+ void *set_value_user_data, grpc_slice *details) {
630
+ grpc_status_code code;
631
+ const char *msg = NULL;
632
+ grpc_error_get_status(error, call->send_deadline, &code, &msg, NULL);
633
+ if (code == GRPC_STATUS_OK && !allow_ok_status) {
634
+ return false;
635
+ }
636
+
637
+ set_value(code, set_value_user_data);
638
+ if (details != NULL) {
639
+ *details =
640
+ msg == NULL ? grpc_empty_slice() : grpc_slice_from_copied_string(msg);
641
+ }
642
+ return true;
447
643
  }
448
644
 
449
- static void set_status_details(grpc_exec_ctx *exec_ctx, grpc_call *call,
450
- status_source source, grpc_mdstr *status) {
451
- if (call->status[source].details != NULL) {
452
- GRPC_MDSTR_UNREF(exec_ctx, status);
645
+ static void get_final_status(grpc_call *call,
646
+ void (*set_value)(grpc_status_code code,
647
+ void *user_data),
648
+ void *set_value_user_data, grpc_slice *details) {
649
+ int i;
650
+ received_status status[STATUS_SOURCE_COUNT];
651
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
652
+ status[i] = unpack_received_status(gpr_atm_acq_load(&call->status[i]));
653
+ }
654
+ if (grpc_call_error_trace) {
655
+ gpr_log(GPR_DEBUG, "get_final_status %s", call->is_client ? "CLI" : "SVR");
656
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
657
+ if (status[i].is_set) {
658
+ gpr_log(GPR_DEBUG, " %d: %s", i, grpc_error_string(status[i].error));
659
+ }
660
+ }
661
+ }
662
+ /* first search through ignoring "OK" statuses: if something went wrong,
663
+ * ensure we report it */
664
+ for (int allow_ok_status = 0; allow_ok_status < 2; allow_ok_status++) {
665
+ /* search for the best status we can present: ideally the error we use has a
666
+ clearly defined grpc-status, and we'll prefer that. */
667
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
668
+ if (status[i].is_set &&
669
+ grpc_error_has_clear_grpc_status(status[i].error)) {
670
+ if (get_final_status_from(call, status[i].error, allow_ok_status != 0,
671
+ set_value, set_value_user_data, details)) {
672
+ return;
673
+ }
674
+ }
675
+ }
676
+ /* If no clearly defined status exists, search for 'anything' */
677
+ for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
678
+ if (status[i].is_set) {
679
+ if (get_final_status_from(call, status[i].error, allow_ok_status != 0,
680
+ set_value, set_value_user_data, details)) {
681
+ return;
682
+ }
683
+ }
684
+ }
685
+ }
686
+ /* If nothing exists, set some default */
687
+ if (call->is_client) {
688
+ set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
453
689
  } else {
454
- call->status[source].details = status;
690
+ set_value(GRPC_STATUS_OK, set_value_user_data);
455
691
  }
456
692
  }
457
693
 
458
694
  static void set_status_from_error(grpc_exec_ctx *exec_ctx, grpc_call *call,
459
695
  status_source source, grpc_error *error) {
460
- grpc_status_code status;
461
- const char *msg;
462
- grpc_error_get_status(error, &status, &msg);
463
- set_status_code(call, source, (uint32_t)status);
464
- set_status_details(exec_ctx, call, source, grpc_mdstr_from_string(msg));
696
+ if (!gpr_atm_rel_cas(&call->status[source],
697
+ pack_received_status((received_status){
698
+ .is_set = false, .error = GRPC_ERROR_NONE}),
699
+ pack_received_status((received_status){
700
+ .is_set = true, .error = error}))) {
701
+ GRPC_ERROR_UNREF(error);
702
+ }
465
703
  }
466
704
 
705
+ /*******************************************************************************
706
+ * COMPRESSION
707
+ */
708
+
467
709
  static void set_incoming_compression_algorithm(
468
710
  grpc_call *call, grpc_compression_algorithm algo) {
469
711
  GPR_ASSERT(algo < GRPC_COMPRESS_ALGORITHMS_COUNT);
@@ -496,7 +738,7 @@ uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) {
496
738
  static void destroy_encodings_accepted_by_peer(void *p) { return; }
497
739
 
498
740
  static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
499
- grpc_call *call, grpc_mdelem *mdel) {
741
+ grpc_call *call, grpc_mdelem mdel) {
500
742
  size_t i;
501
743
  grpc_compression_algorithm algorithm;
502
744
  grpc_slice_buffer accept_encoding_parts;
@@ -511,7 +753,7 @@ static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
511
753
  return;
512
754
  }
513
755
 
514
- accept_encoding_slice = mdel->value->slice;
756
+ accept_encoding_slice = GRPC_MDVALUE(mdel);
515
757
  grpc_slice_buffer_init(&accept_encoding_parts);
516
758
  grpc_slice_split(accept_encoding_slice, ",", &accept_encoding_parts);
517
759
 
@@ -520,15 +762,13 @@ static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
520
762
  /* Always support no compression */
521
763
  GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
522
764
  for (i = 0; i < accept_encoding_parts.count; i++) {
523
- const grpc_slice *accept_encoding_entry_slice =
524
- &accept_encoding_parts.slices[i];
525
- if (grpc_compression_algorithm_parse(
526
- (const char *)GRPC_SLICE_START_PTR(*accept_encoding_entry_slice),
527
- GRPC_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) {
765
+ grpc_slice accept_encoding_entry_slice = accept_encoding_parts.slices[i];
766
+ if (grpc_compression_algorithm_parse(accept_encoding_entry_slice,
767
+ &algorithm)) {
528
768
  GPR_BITSET(&call->encodings_accepted_by_peer, algorithm);
529
769
  } else {
530
770
  char *accept_encoding_entry_str =
531
- grpc_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII);
771
+ grpc_slice_to_c_string(accept_encoding_entry_slice);
532
772
  gpr_log(GPR_ERROR,
533
773
  "Invalid entry in accept encoding metadata: '%s'. Ignoring.",
534
774
  accept_encoding_entry_str);
@@ -539,354 +779,84 @@ static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
539
779
  grpc_slice_buffer_destroy_internal(exec_ctx, &accept_encoding_parts);
540
780
 
541
781
  grpc_mdelem_set_user_data(
542
- mdel, destroy_encodings_accepted_by_peer,
543
- (void *)(((uintptr_t)call->encodings_accepted_by_peer) + 1));
544
- }
545
-
546
- uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
547
- uint32_t encodings_accepted_by_peer;
548
- gpr_mu_lock(&call->mu);
549
- encodings_accepted_by_peer = call->encodings_accepted_by_peer;
550
- gpr_mu_unlock(&call->mu);
551
- return encodings_accepted_by_peer;
552
- }
553
-
554
- static void get_final_details(grpc_call *call, char **out_details,
555
- size_t *out_details_capacity) {
556
- int i;
557
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
558
- if (call->status[i].is_set) {
559
- if (call->status[i].details) {
560
- grpc_slice details = call->status[i].details->slice;
561
- size_t len = GRPC_SLICE_LENGTH(details);
562
- if (len + 1 > *out_details_capacity) {
563
- *out_details_capacity =
564
- GPR_MAX(len + 1, *out_details_capacity * 3 / 2);
565
- *out_details = gpr_realloc(*out_details, *out_details_capacity);
566
- }
567
- memcpy(*out_details, GRPC_SLICE_START_PTR(details), len);
568
- (*out_details)[len] = 0;
569
- } else {
570
- goto no_details;
571
- }
572
- return;
573
- }
574
- }
575
-
576
- no_details:
577
- if (0 == *out_details_capacity) {
578
- *out_details_capacity = 8;
579
- *out_details = gpr_malloc(*out_details_capacity);
580
- }
581
- **out_details = 0;
582
- }
583
-
584
- static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) {
585
- return (grpc_linked_mdelem *)&md->internal_data;
586
- }
587
-
588
- static grpc_metadata *get_md_elem(grpc_metadata *metadata,
589
- grpc_metadata *additional_metadata, int i,
590
- int count) {
591
- grpc_metadata *res =
592
- i < count ? &metadata[i] : &additional_metadata[i - count];
593
- GPR_ASSERT(res);
594
- return res;
595
- }
596
-
597
- static int prepare_application_metadata(
598
- grpc_exec_ctx *exec_ctx, grpc_call *call, int count,
599
- grpc_metadata *metadata, int is_trailing, int prepend_extra_metadata,
600
- grpc_metadata *additional_metadata, int additional_metadata_count) {
601
- int total_count = count + additional_metadata_count;
602
- int i;
603
- grpc_metadata_batch *batch =
604
- &call->metadata_batch[0 /* is_receiving */][is_trailing];
605
- for (i = 0; i < total_count; i++) {
606
- const grpc_metadata *md =
607
- get_md_elem(metadata, additional_metadata, i, count);
608
- grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
609
- GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
610
- l->md = grpc_mdelem_from_string_and_buffer(
611
- exec_ctx, md->key, (const uint8_t *)md->value, md->value_length);
612
- if (!grpc_header_key_is_legal(grpc_mdstr_as_c_string(l->md->key),
613
- GRPC_MDSTR_LENGTH(l->md->key))) {
614
- gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s",
615
- grpc_mdstr_as_c_string(l->md->key));
616
- break;
617
- } else if (!grpc_is_binary_header(grpc_mdstr_as_c_string(l->md->key),
618
- GRPC_MDSTR_LENGTH(l->md->key)) &&
619
- !grpc_header_nonbin_value_is_legal(
620
- grpc_mdstr_as_c_string(l->md->value),
621
- GRPC_MDSTR_LENGTH(l->md->value))) {
622
- gpr_log(GPR_ERROR, "attempt to send invalid metadata value");
623
- break;
624
- }
625
- }
626
- if (i != total_count) {
627
- for (int j = 0; j <= i; j++) {
628
- const grpc_metadata *md =
629
- get_md_elem(metadata, additional_metadata, j, count);
630
- grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
631
- GRPC_MDELEM_UNREF(exec_ctx, l->md);
632
- }
633
- return 0;
634
- }
635
- if (prepend_extra_metadata) {
636
- if (call->send_extra_metadata_count == 0) {
637
- prepend_extra_metadata = 0;
638
- } else {
639
- for (i = 1; i < call->send_extra_metadata_count; i++) {
640
- call->send_extra_metadata[i].prev = &call->send_extra_metadata[i - 1];
641
- }
642
- for (i = 0; i < call->send_extra_metadata_count - 1; i++) {
643
- call->send_extra_metadata[i].next = &call->send_extra_metadata[i + 1];
644
- }
645
- }
646
- }
647
- for (i = 1; i < total_count; i++) {
648
- grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
649
- grpc_metadata *prev_md =
650
- get_md_elem(metadata, additional_metadata, i - 1, count);
651
- linked_from_md(md)->prev = linked_from_md(prev_md);
652
- }
653
- for (i = 0; i < total_count - 1; i++) {
654
- grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
655
- grpc_metadata *next_md =
656
- get_md_elem(metadata, additional_metadata, i + 1, count);
657
- linked_from_md(md)->next = linked_from_md(next_md);
658
- }
659
-
660
- switch (prepend_extra_metadata * 2 + (total_count != 0)) {
661
- case 0:
662
- /* no prepend, no metadata => nothing to do */
663
- batch->list.head = batch->list.tail = NULL;
664
- break;
665
- case 1: {
666
- /* metadata, but no prepend */
667
- grpc_metadata *first_md =
668
- get_md_elem(metadata, additional_metadata, 0, count);
669
- grpc_metadata *last_md =
670
- get_md_elem(metadata, additional_metadata, total_count - 1, count);
671
- batch->list.head = linked_from_md(first_md);
672
- batch->list.tail = linked_from_md(last_md);
673
- batch->list.head->prev = NULL;
674
- batch->list.tail->next = NULL;
675
- break;
676
- }
677
- case 2:
678
- /* prepend, but no md */
679
- batch->list.head = &call->send_extra_metadata[0];
680
- batch->list.tail =
681
- &call->send_extra_metadata[call->send_extra_metadata_count - 1];
682
- batch->list.head->prev = NULL;
683
- batch->list.tail->next = NULL;
684
- call->send_extra_metadata_count = 0;
685
- break;
686
- case 3: {
687
- /* prepend AND md */
688
- grpc_metadata *first_md =
689
- get_md_elem(metadata, additional_metadata, 0, count);
690
- grpc_metadata *last_md =
691
- get_md_elem(metadata, additional_metadata, total_count - 1, count);
692
- batch->list.head = &call->send_extra_metadata[0];
693
- call->send_extra_metadata[call->send_extra_metadata_count - 1].next =
694
- linked_from_md(first_md);
695
- linked_from_md(first_md)->prev =
696
- &call->send_extra_metadata[call->send_extra_metadata_count - 1];
697
- batch->list.tail = linked_from_md(last_md);
698
- batch->list.head->prev = NULL;
699
- batch->list.tail->next = NULL;
700
- call->send_extra_metadata_count = 0;
701
- break;
702
- }
703
- default:
704
- GPR_UNREACHABLE_CODE(return 0);
705
- }
706
-
707
- return 1;
708
- }
709
-
710
- void grpc_call_destroy(grpc_call *c) {
711
- int cancel;
712
- grpc_call *parent = c->parent;
713
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
714
-
715
- GPR_TIMER_BEGIN("grpc_call_destroy", 0);
716
- GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
717
-
718
- if (parent) {
719
- gpr_mu_lock(&parent->mu);
720
- if (c == parent->first_child) {
721
- parent->first_child = c->sibling_next;
722
- if (c == parent->first_child) {
723
- parent->first_child = NULL;
724
- }
725
- c->sibling_prev->sibling_next = c->sibling_next;
726
- c->sibling_next->sibling_prev = c->sibling_prev;
727
- }
728
- gpr_mu_unlock(&parent->mu);
729
- GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
730
- }
731
-
732
- gpr_mu_lock(&c->mu);
733
- GPR_ASSERT(!c->destroy_called);
734
- c->destroy_called = 1;
735
- cancel = !c->received_final_op;
736
- gpr_mu_unlock(&c->mu);
737
- if (cancel) grpc_call_cancel(c, NULL);
738
- GRPC_CALL_INTERNAL_UNREF(&exec_ctx, c, "destroy");
739
- grpc_exec_ctx_finish(&exec_ctx);
740
- GPR_TIMER_END("grpc_call_destroy", 0);
741
- }
742
-
743
- grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
744
- GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
745
- GPR_ASSERT(!reserved);
746
- return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled",
747
- NULL);
748
- }
749
-
750
- grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
751
- grpc_status_code status,
752
- const char *description,
753
- void *reserved) {
754
- grpc_call_error r;
755
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
756
- GRPC_API_TRACE(
757
- "grpc_call_cancel_with_status("
758
- "c=%p, status=%d, description=%s, reserved=%p)",
759
- 4, (c, (int)status, description, reserved));
760
- GPR_ASSERT(reserved == NULL);
761
- gpr_mu_lock(&c->mu);
762
- r = cancel_with_status(&exec_ctx, c, status, description);
763
- gpr_mu_unlock(&c->mu);
764
- grpc_exec_ctx_finish(&exec_ctx);
765
- return r;
766
- }
767
-
768
- typedef struct termination_closure {
769
- grpc_closure closure;
770
- grpc_call *call;
771
- grpc_error *error;
772
- enum { TC_CANCEL, TC_CLOSE } type;
773
- grpc_transport_stream_op op;
774
- } termination_closure;
775
-
776
- static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
777
- grpc_error *error) {
778
- termination_closure *tc = tcp;
779
- switch (tc->type) {
780
- case TC_CANCEL:
781
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "cancel");
782
- break;
783
- case TC_CLOSE:
784
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "close");
785
- break;
786
- }
787
- GRPC_ERROR_UNREF(tc->error);
788
- gpr_free(tc);
789
- }
790
-
791
- static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
792
- termination_closure *tc = tcp;
793
- memset(&tc->op, 0, sizeof(tc->op));
794
- tc->op.cancel_error = tc->error;
795
- /* reuse closure to catch completion */
796
- grpc_closure_init(&tc->closure, done_termination, tc,
797
- grpc_schedule_on_exec_ctx);
798
- tc->op.on_complete = &tc->closure;
799
- execute_op(exec_ctx, tc->call, &tc->op);
800
- }
801
-
802
- static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
803
- termination_closure *tc = tcp;
804
- memset(&tc->op, 0, sizeof(tc->op));
805
- tc->op.close_error = tc->error;
806
- /* reuse closure to catch completion */
807
- grpc_closure_init(&tc->closure, done_termination, tc,
808
- grpc_schedule_on_exec_ctx);
809
- tc->op.on_complete = &tc->closure;
810
- execute_op(exec_ctx, tc->call, &tc->op);
811
- }
812
-
813
- static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
814
- termination_closure *tc) {
815
- set_status_from_error(exec_ctx, tc->call, STATUS_FROM_API_OVERRIDE,
816
- tc->error);
817
-
818
- if (tc->type == TC_CANCEL) {
819
- grpc_closure_init(&tc->closure, send_cancel, tc, grpc_schedule_on_exec_ctx);
820
- GRPC_CALL_INTERNAL_REF(tc->call, "cancel");
821
- } else if (tc->type == TC_CLOSE) {
822
- grpc_closure_init(&tc->closure, send_close, tc, grpc_schedule_on_exec_ctx);
823
- GRPC_CALL_INTERNAL_REF(tc->call, "close");
824
- }
825
- grpc_closure_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE);
826
- return GRPC_CALL_OK;
827
- }
828
-
829
- static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
830
- grpc_status_code status,
831
- const char *description) {
832
- GPR_ASSERT(status != GRPC_STATUS_OK);
833
- termination_closure *tc = gpr_malloc(sizeof(*tc));
834
- memset(tc, 0, sizeof(termination_closure));
835
- tc->type = TC_CANCEL;
836
- tc->call = c;
837
- tc->error = grpc_error_set_int(
838
- grpc_error_set_str(GRPC_ERROR_CREATE(description),
839
- GRPC_ERROR_STR_GRPC_MESSAGE, description),
840
- GRPC_ERROR_INT_GRPC_STATUS, status);
841
-
842
- return terminate_with_status(exec_ctx, tc);
782
+ mdel, destroy_encodings_accepted_by_peer,
783
+ (void *)(((uintptr_t)call->encodings_accepted_by_peer) + 1));
843
784
  }
844
785
 
845
- static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
846
- grpc_status_code status,
847
- const char *description) {
848
- GPR_ASSERT(status != GRPC_STATUS_OK);
849
- termination_closure *tc = gpr_malloc(sizeof(*tc));
850
- memset(tc, 0, sizeof(termination_closure));
851
- tc->type = TC_CLOSE;
852
- tc->call = c;
853
- tc->error = grpc_error_set_int(
854
- grpc_error_set_str(GRPC_ERROR_CREATE(description),
855
- GRPC_ERROR_STR_GRPC_MESSAGE, description),
856
- GRPC_ERROR_INT_GRPC_STATUS, status);
857
-
858
- return terminate_with_status(exec_ctx, tc);
786
+ uint32_t grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
787
+ uint32_t encodings_accepted_by_peer;
788
+ gpr_mu_lock(&call->mu);
789
+ encodings_accepted_by_peer = call->encodings_accepted_by_peer;
790
+ gpr_mu_unlock(&call->mu);
791
+ return encodings_accepted_by_peer;
859
792
  }
860
793
 
861
- static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
862
- grpc_transport_stream_op *op) {
863
- grpc_call_element *elem;
794
+ static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) {
795
+ return (grpc_linked_mdelem *)&md->internal_data;
796
+ }
864
797
 
865
- GPR_TIMER_BEGIN("execute_op", 0);
866
- elem = CALL_ELEM_FROM_CALL(call, 0);
867
- op->context = call->context;
868
- elem->filter->start_transport_stream_op(exec_ctx, elem, op);
869
- GPR_TIMER_END("execute_op", 0);
798
+ static grpc_metadata *get_md_elem(grpc_metadata *metadata,
799
+ grpc_metadata *additional_metadata, int i,
800
+ int count) {
801
+ grpc_metadata *res =
802
+ i < count ? &metadata[i] : &additional_metadata[i - count];
803
+ GPR_ASSERT(res);
804
+ return res;
870
805
  }
871
806
 
872
- char *grpc_call_get_peer(grpc_call *call) {
873
- grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
874
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
875
- char *result;
876
- GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
877
- result = elem->filter->get_peer(&exec_ctx, elem);
878
- if (result == NULL) {
879
- result = grpc_channel_get_target(call->channel);
807
+ static int prepare_application_metadata(
808
+ grpc_exec_ctx *exec_ctx, grpc_call *call, int count,
809
+ grpc_metadata *metadata, int is_trailing, int prepend_extra_metadata,
810
+ grpc_metadata *additional_metadata, int additional_metadata_count) {
811
+ int total_count = count + additional_metadata_count;
812
+ int i;
813
+ grpc_metadata_batch *batch =
814
+ &call->metadata_batch[0 /* is_receiving */][is_trailing];
815
+ for (i = 0; i < total_count; i++) {
816
+ const grpc_metadata *md =
817
+ get_md_elem(metadata, additional_metadata, i, count);
818
+ grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
819
+ GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
820
+ if (!GRPC_LOG_IF_ERROR("validate_metadata",
821
+ grpc_validate_header_key_is_legal(md->key))) {
822
+ break;
823
+ } else if (!grpc_is_binary_header(md->key) &&
824
+ !GRPC_LOG_IF_ERROR(
825
+ "validate_metadata",
826
+ grpc_validate_header_nonbin_value_is_legal(md->value))) {
827
+ break;
828
+ }
829
+ l->md = grpc_mdelem_from_grpc_metadata(exec_ctx, (grpc_metadata *)md);
880
830
  }
881
- if (result == NULL) {
882
- result = gpr_strdup("unknown");
831
+ if (i != total_count) {
832
+ for (int j = 0; j < i; j++) {
833
+ const grpc_metadata *md =
834
+ get_md_elem(metadata, additional_metadata, j, count);
835
+ grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
836
+ GRPC_MDELEM_UNREF(exec_ctx, l->md);
837
+ }
838
+ return 0;
883
839
  }
884
- grpc_exec_ctx_finish(&exec_ctx);
885
- return result;
886
- }
840
+ if (prepend_extra_metadata) {
841
+ if (call->send_extra_metadata_count == 0) {
842
+ prepend_extra_metadata = 0;
843
+ } else {
844
+ for (i = 0; i < call->send_extra_metadata_count; i++) {
845
+ GRPC_LOG_IF_ERROR("prepare_application_metadata",
846
+ grpc_metadata_batch_link_tail(
847
+ exec_ctx, batch, &call->send_extra_metadata[i]));
848
+ }
849
+ }
850
+ }
851
+ for (i = 0; i < total_count; i++) {
852
+ grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
853
+ GRPC_LOG_IF_ERROR(
854
+ "prepare_application_metadata",
855
+ grpc_metadata_batch_link_tail(exec_ctx, batch, linked_from_md(md)));
856
+ }
857
+ call->send_extra_metadata_count = 0;
887
858
 
888
- grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
889
- return CALL_FROM_TOP_ELEM(elem);
859
+ return 1;
890
860
  }
891
861
 
892
862
  /* we offset status by a small amount when storing it into transport metadata
@@ -895,19 +865,17 @@ grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
895
865
  #define STATUS_OFFSET 1
896
866
  static void destroy_status(void *ignored) {}
897
867
 
898
- static uint32_t decode_status(grpc_mdelem *md) {
868
+ static uint32_t decode_status(grpc_mdelem md) {
899
869
  uint32_t status;
900
870
  void *user_data;
901
- if (md == GRPC_MDELEM_GRPC_STATUS_0) return 0;
902
- if (md == GRPC_MDELEM_GRPC_STATUS_1) return 1;
903
- if (md == GRPC_MDELEM_GRPC_STATUS_2) return 2;
871
+ if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) return 0;
872
+ if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) return 1;
873
+ if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) return 2;
904
874
  user_data = grpc_mdelem_get_user_data(md, destroy_status);
905
875
  if (user_data != NULL) {
906
876
  status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET;
907
877
  } else {
908
- if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
909
- GRPC_SLICE_LENGTH(md->value->slice),
910
- &status)) {
878
+ if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) {
911
879
  status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
912
880
  }
913
881
  grpc_mdelem_set_user_data(md, destroy_status,
@@ -916,93 +884,104 @@ static uint32_t decode_status(grpc_mdelem *md) {
916
884
  return status;
917
885
  }
918
886
 
919
- static grpc_compression_algorithm decode_compression(grpc_mdelem *md) {
887
+ static grpc_compression_algorithm decode_compression(grpc_mdelem md) {
920
888
  grpc_compression_algorithm algorithm =
921
- grpc_compression_algorithm_from_mdstr(md->value);
889
+ grpc_compression_algorithm_from_slice(GRPC_MDVALUE(md));
922
890
  if (algorithm == GRPC_COMPRESS_ALGORITHMS_COUNT) {
923
- const char *md_c_str = grpc_mdstr_as_c_string(md->value);
891
+ char *md_c_str = grpc_slice_to_c_string(GRPC_MDVALUE(md));
924
892
  gpr_log(GPR_ERROR,
925
893
  "Invalid incoming compression algorithm: '%s'. Interpreting "
926
894
  "incoming data as uncompressed.",
927
895
  md_c_str);
896
+ gpr_free(md_c_str);
928
897
  return GRPC_COMPRESS_NONE;
929
898
  }
930
899
  return algorithm;
931
900
  }
932
901
 
933
- static grpc_mdelem *recv_common_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
934
- grpc_mdelem *elem) {
935
- if (elem->key == GRPC_MDSTR_GRPC_STATUS) {
936
- GPR_TIMER_BEGIN("status", 0);
937
- set_status_code(call, STATUS_FROM_WIRE, decode_status(elem));
938
- GPR_TIMER_END("status", 0);
939
- return NULL;
940
- } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) {
941
- GPR_TIMER_BEGIN("status-details", 0);
942
- set_status_details(exec_ctx, call, STATUS_FROM_WIRE,
943
- GRPC_MDSTR_REF(elem->value));
944
- GPR_TIMER_END("status-details", 0);
945
- return NULL;
902
+ static void recv_common_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
903
+ grpc_metadata_batch *b) {
904
+ if (b->idx.named.grpc_status != NULL) {
905
+ uint32_t status_code = decode_status(b->idx.named.grpc_status->md);
906
+ grpc_error *error =
907
+ status_code == GRPC_STATUS_OK
908
+ ? GRPC_ERROR_NONE
909
+ : grpc_error_set_int(GRPC_ERROR_CREATE("Error received from peer"),
910
+ GRPC_ERROR_INT_GRPC_STATUS,
911
+ (intptr_t)status_code);
912
+
913
+ if (b->idx.named.grpc_message != NULL) {
914
+ char *msg =
915
+ grpc_slice_to_c_string(GRPC_MDVALUE(b->idx.named.grpc_message->md));
916
+ error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, msg);
917
+ gpr_free(msg);
918
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_message);
919
+ } else if (error != GRPC_ERROR_NONE) {
920
+ error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, "");
921
+ }
922
+
923
+ set_status_from_error(exec_ctx, call, STATUS_FROM_WIRE, error);
924
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_status);
946
925
  }
947
- return elem;
948
926
  }
949
927
 
950
- static grpc_mdelem *publish_app_metadata(grpc_call *call, grpc_mdelem *elem,
951
- int is_trailing) {
928
+ static void publish_app_metadata(grpc_call *call, grpc_metadata_batch *b,
929
+ int is_trailing) {
930
+ if (b->list.count == 0) return;
931
+ GPR_TIMER_BEGIN("publish_app_metadata", 0);
952
932
  grpc_metadata_array *dest;
953
933
  grpc_metadata *mdusr;
954
- GPR_TIMER_BEGIN("publish_app_metadata", 0);
955
934
  dest = call->buffered_metadata[is_trailing];
956
- if (dest->count == dest->capacity) {
957
- dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
935
+ if (dest->count + b->list.count > dest->capacity) {
936
+ dest->capacity =
937
+ GPR_MAX(dest->capacity + b->list.count, dest->capacity * 3 / 2);
958
938
  dest->metadata =
959
939
  gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity);
960
940
  }
961
- mdusr = &dest->metadata[dest->count++];
962
- mdusr->key = grpc_mdstr_as_c_string(elem->key);
963
- mdusr->value = grpc_mdstr_as_c_string(elem->value);
964
- mdusr->value_length = GRPC_SLICE_LENGTH(elem->value->slice);
941
+ for (grpc_linked_mdelem *l = b->list.head; l != NULL; l = l->next) {
942
+ mdusr = &dest->metadata[dest->count++];
943
+ /* we pass back borrowed slices that are valid whilst the call is valid */
944
+ mdusr->key = GRPC_MDKEY(l->md);
945
+ mdusr->value = GRPC_MDVALUE(l->md);
946
+ }
965
947
  GPR_TIMER_END("publish_app_metadata", 0);
966
- return elem;
967
948
  }
968
949
 
969
- static grpc_mdelem *recv_initial_filter(grpc_exec_ctx *exec_ctx, void *args,
970
- grpc_mdelem *elem) {
971
- grpc_call *call = args;
972
- elem = recv_common_filter(exec_ctx, call, elem);
973
- if (elem == NULL) {
974
- return NULL;
975
- } else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
950
+ static void recv_initial_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
951
+ grpc_metadata_batch *b) {
952
+ recv_common_filter(exec_ctx, call, b);
953
+
954
+ if (b->idx.named.grpc_encoding != NULL) {
976
955
  GPR_TIMER_BEGIN("incoming_compression_algorithm", 0);
977
- set_incoming_compression_algorithm(call, decode_compression(elem));
956
+ set_incoming_compression_algorithm(
957
+ call, decode_compression(b->idx.named.grpc_encoding->md));
978
958
  GPR_TIMER_END("incoming_compression_algorithm", 0);
979
- return NULL;
980
- } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
959
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_encoding);
960
+ }
961
+
962
+ if (b->idx.named.grpc_accept_encoding != NULL) {
981
963
  GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
982
- set_encodings_accepted_by_peer(exec_ctx, call, elem);
964
+ set_encodings_accepted_by_peer(exec_ctx, call,
965
+ b->idx.named.grpc_accept_encoding->md);
966
+ grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_accept_encoding);
983
967
  GPR_TIMER_END("encodings_accepted_by_peer", 0);
984
- return NULL;
985
- } else {
986
- return publish_app_metadata(call, elem, 0);
987
968
  }
969
+
970
+ publish_app_metadata(call, b, false);
988
971
  }
989
972
 
990
- static grpc_mdelem *recv_trailing_filter(grpc_exec_ctx *exec_ctx, void *args,
991
- grpc_mdelem *elem) {
973
+ static void recv_trailing_filter(grpc_exec_ctx *exec_ctx, void *args,
974
+ grpc_metadata_batch *b) {
992
975
  grpc_call *call = args;
993
- elem = recv_common_filter(exec_ctx, call, elem);
994
- if (elem == NULL) {
995
- return NULL;
996
- } else {
997
- return publish_app_metadata(call, elem, 1);
998
- }
976
+ recv_common_filter(exec_ctx, call, b);
977
+ publish_app_metadata(call, b, true);
999
978
  }
1000
979
 
1001
980
  grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) {
1002
981
  return CALL_STACK_FROM_CALL(call);
1003
982
  }
1004
983
 
1005
- /*
984
+ /*******************************************************************************
1006
985
  * BATCH API IMPLEMENTATION
1007
986
  */
1008
987
 
@@ -1031,44 +1010,132 @@ static bool are_initial_metadata_flags_valid(uint32_t flags, bool is_client) {
1031
1010
  return !(flags & invalid_positions);
1032
1011
  }
1033
1012
 
1034
- static batch_control *allocate_batch_control(grpc_call *call) {
1035
- size_t i;
1036
- for (i = 0; i < MAX_CONCURRENT_BATCHES; i++) {
1037
- if ((call->used_batches & (1 << i)) == 0) {
1038
- call->used_batches = (uint8_t)(call->used_batches | (uint8_t)(1 << i));
1039
- return &call->active_batches[i];
1040
- }
1013
+ static int batch_slot_for_op(grpc_op_type type) {
1014
+ switch (type) {
1015
+ case GRPC_OP_SEND_INITIAL_METADATA:
1016
+ return 0;
1017
+ case GRPC_OP_SEND_MESSAGE:
1018
+ return 1;
1019
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
1020
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
1021
+ return 2;
1022
+ case GRPC_OP_RECV_INITIAL_METADATA:
1023
+ return 3;
1024
+ case GRPC_OP_RECV_MESSAGE:
1025
+ return 4;
1026
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
1027
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
1028
+ return 5;
1029
+ }
1030
+ GPR_UNREACHABLE_CODE(return 123456789);
1031
+ }
1032
+
1033
+ static batch_control *allocate_batch_control(grpc_call *call,
1034
+ const grpc_op *ops,
1035
+ size_t num_ops) {
1036
+ int slot = batch_slot_for_op(ops[0].op);
1037
+ for (size_t i = 1; i < num_ops; i++) {
1038
+ int op_slot = batch_slot_for_op(ops[i].op);
1039
+ slot = GPR_MIN(slot, op_slot);
1040
+ }
1041
+ batch_control *bctl = &call->active_batches[slot];
1042
+ if (bctl->call != NULL) {
1043
+ return NULL;
1041
1044
  }
1042
- return NULL;
1045
+ memset(bctl, 0, sizeof(*bctl));
1046
+ bctl->call = call;
1047
+ return bctl;
1043
1048
  }
1044
1049
 
1045
1050
  static void finish_batch_completion(grpc_exec_ctx *exec_ctx, void *user_data,
1046
1051
  grpc_cq_completion *storage) {
1047
1052
  batch_control *bctl = user_data;
1048
1053
  grpc_call *call = bctl->call;
1049
- gpr_mu_lock(&call->mu);
1050
- call->used_batches = (uint8_t)(
1051
- call->used_batches & ~(uint8_t)(1 << (bctl - call->active_batches)));
1052
- gpr_mu_unlock(&call->mu);
1054
+ bctl->call = NULL;
1053
1055
  GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
1054
1056
  }
1055
1057
 
1058
+ static grpc_error *consolidate_batch_errors(batch_control *bctl) {
1059
+ size_t n = (size_t)gpr_atm_no_barrier_load(&bctl->num_errors);
1060
+ if (n == 0) {
1061
+ return GRPC_ERROR_NONE;
1062
+ } else if (n == 1) {
1063
+ /* Skip creating a composite error in the case that only one error was
1064
+ logged */
1065
+ grpc_error *e = bctl->errors[0];
1066
+ bctl->errors[0] = NULL;
1067
+ return e;
1068
+ } else {
1069
+ grpc_error *error =
1070
+ GRPC_ERROR_CREATE_REFERENCING("Call batch failed", bctl->errors, n);
1071
+ for (size_t i = 0; i < n; i++) {
1072
+ GRPC_ERROR_UNREF(bctl->errors[i]);
1073
+ bctl->errors[i] = NULL;
1074
+ }
1075
+ return error;
1076
+ }
1077
+ }
1078
+
1056
1079
  static void post_batch_completion(grpc_exec_ctx *exec_ctx,
1057
1080
  batch_control *bctl) {
1081
+ grpc_call *child_call;
1082
+ grpc_call *next_child_call;
1058
1083
  grpc_call *call = bctl->call;
1059
- grpc_error *error = bctl->error;
1084
+ grpc_error *error = consolidate_batch_errors(bctl);
1085
+
1086
+ gpr_mu_lock(&call->mu);
1087
+
1088
+ if (bctl->send_initial_metadata) {
1089
+ grpc_metadata_batch_destroy(
1090
+ exec_ctx,
1091
+ &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
1092
+ }
1093
+ if (bctl->send_message) {
1094
+ call->sending_message = false;
1095
+ }
1096
+ if (bctl->send_final_op) {
1097
+ grpc_metadata_batch_destroy(
1098
+ exec_ctx,
1099
+ &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
1100
+ }
1060
1101
  if (bctl->recv_final_op) {
1102
+ grpc_metadata_batch *md =
1103
+ &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
1104
+ recv_trailing_filter(exec_ctx, call, md);
1105
+
1106
+ call->received_final_op = true;
1107
+ /* propagate cancellation to any interested children */
1108
+ child_call = call->first_child;
1109
+ if (child_call != NULL) {
1110
+ do {
1111
+ next_child_call = child_call->sibling_next;
1112
+ if (child_call->cancellation_is_inherited) {
1113
+ GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
1114
+ grpc_call_cancel(child_call, NULL);
1115
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
1116
+ }
1117
+ child_call = next_child_call;
1118
+ } while (child_call != call->first_child);
1119
+ }
1120
+
1121
+ if (call->is_client) {
1122
+ get_final_status(call, set_status_value_directly,
1123
+ call->final_op.client.status,
1124
+ call->final_op.client.status_details);
1125
+ } else {
1126
+ get_final_status(call, set_cancelled_value,
1127
+ call->final_op.server.cancelled, NULL);
1128
+ }
1129
+
1061
1130
  GRPC_ERROR_UNREF(error);
1062
1131
  error = GRPC_ERROR_NONE;
1063
1132
  }
1133
+ gpr_mu_unlock(&call->mu);
1134
+
1064
1135
  if (bctl->is_notify_tag_closure) {
1065
1136
  /* unrefs bctl->error */
1137
+ bctl->call = NULL;
1066
1138
  grpc_closure_run(exec_ctx, bctl->notify_tag, error);
1067
- gpr_mu_lock(&call->mu);
1068
- bctl->call->used_batches =
1069
- (uint8_t)(bctl->call->used_batches &
1070
- ~(uint8_t)(1 << (bctl - bctl->call->active_batches)));
1071
- gpr_mu_unlock(&call->mu);
1072
1139
  GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
1073
1140
  } else {
1074
1141
  /* unrefs bctl->error */
@@ -1077,6 +1144,12 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
1077
1144
  }
1078
1145
  }
1079
1146
 
1147
+ static void finish_batch_step(grpc_exec_ctx *exec_ctx, batch_control *bctl) {
1148
+ if (gpr_unref(&bctl->steps_to_complete)) {
1149
+ post_batch_completion(exec_ctx, bctl);
1150
+ }
1151
+ }
1152
+
1080
1153
  static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
1081
1154
  batch_control *bctl) {
1082
1155
  grpc_call *call = bctl->call;
@@ -1087,9 +1160,7 @@ static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
1087
1160
  call->receiving_message = 0;
1088
1161
  grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
1089
1162
  call->receiving_stream = NULL;
1090
- if (gpr_unref(&bctl->steps_to_complete)) {
1091
- post_batch_completion(exec_ctx, bctl);
1092
- }
1163
+ finish_batch_step(exec_ctx, bctl);
1093
1164
  return;
1094
1165
  }
1095
1166
  if (grpc_byte_stream_next(exec_ctx, call->receiving_stream,
@@ -1120,9 +1191,7 @@ static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
1120
1191
  call->receiving_stream = NULL;
1121
1192
  grpc_byte_buffer_destroy(*call->receiving_buffer);
1122
1193
  *call->receiving_buffer = NULL;
1123
- if (gpr_unref(&bctl->steps_to_complete)) {
1124
- post_batch_completion(exec_ctx, bctl);
1125
- }
1194
+ finish_batch_step(exec_ctx, bctl);
1126
1195
  }
1127
1196
  }
1128
1197
 
@@ -1132,9 +1201,7 @@ static void process_data_after_md(grpc_exec_ctx *exec_ctx,
1132
1201
  if (call->receiving_stream == NULL) {
1133
1202
  *call->receiving_buffer = NULL;
1134
1203
  call->receiving_message = 0;
1135
- if (gpr_unref(&bctl->steps_to_complete)) {
1136
- post_batch_completion(exec_ctx, bctl);
1137
- }
1204
+ finish_batch_step(exec_ctx, bctl);
1138
1205
  } else {
1139
1206
  call->test_only_last_message_flags = call->receiving_stream->flags;
1140
1207
  if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
@@ -1154,14 +1221,17 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
1154
1221
  grpc_error *error) {
1155
1222
  batch_control *bctl = bctlp;
1156
1223
  grpc_call *call = bctl->call;
1224
+ gpr_mu_lock(&bctl->call->mu);
1157
1225
  if (error != GRPC_ERROR_NONE) {
1158
- grpc_status_code status;
1159
- const char *msg;
1160
- grpc_error_get_status(error, &status, &msg);
1161
- close_with_status(exec_ctx, call, status, msg);
1226
+ if (call->receiving_stream != NULL) {
1227
+ grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
1228
+ call->receiving_stream = NULL;
1229
+ }
1230
+ add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error), true);
1231
+ cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE,
1232
+ GRPC_ERROR_REF(error));
1162
1233
  }
1163
- gpr_mu_lock(&bctl->call->mu);
1164
- if (bctl->call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
1234
+ if (call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
1165
1235
  call->receiving_stream == NULL) {
1166
1236
  gpr_mu_unlock(&bctl->call->mu);
1167
1237
  process_data_after_md(exec_ctx, bctlp);
@@ -1186,7 +1256,8 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
1186
1256
  gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
1187
1257
  algo);
1188
1258
  gpr_log(GPR_ERROR, "%s", error_msg);
1189
- close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
1259
+ cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE,
1260
+ GRPC_STATUS_UNIMPLEMENTED, error_msg);
1190
1261
  } else if (grpc_compression_options_is_algorithm_enabled(
1191
1262
  &compression_options, algo) == 0) {
1192
1263
  /* check if algorithm is supported by current channel config */
@@ -1195,7 +1266,8 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
1195
1266
  gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
1196
1267
  algo_name);
1197
1268
  gpr_log(GPR_ERROR, "%s", error_msg);
1198
- close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
1269
+ cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE,
1270
+ GRPC_STATUS_UNIMPLEMENTED, error_msg);
1199
1271
  } else {
1200
1272
  call->incoming_compression_algorithm = algo;
1201
1273
  }
@@ -1221,12 +1293,15 @@ static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
1221
1293
  }
1222
1294
  }
1223
1295
 
1224
- static void add_batch_error(batch_control *bctl, grpc_error *error) {
1296
+ static void add_batch_error(grpc_exec_ctx *exec_ctx, batch_control *bctl,
1297
+ grpc_error *error, bool has_cancelled) {
1225
1298
  if (error == GRPC_ERROR_NONE) return;
1226
- if (bctl->error == GRPC_ERROR_NONE) {
1227
- bctl->error = GRPC_ERROR_CREATE("Call batch operation failed");
1299
+ int idx = (int)gpr_atm_no_barrier_fetch_add(&bctl->num_errors, 1);
1300
+ if (idx == 0 && !has_cancelled) {
1301
+ cancel_with_error(exec_ctx, bctl->call, STATUS_FROM_CORE,
1302
+ GRPC_ERROR_REF(error));
1228
1303
  }
1229
- bctl->error = grpc_error_add_child(bctl->error, error);
1304
+ bctl->errors[idx] = error;
1230
1305
  }
1231
1306
 
1232
1307
  static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
@@ -1236,12 +1311,13 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
1236
1311
 
1237
1312
  gpr_mu_lock(&call->mu);
1238
1313
 
1239
- add_batch_error(bctl, GRPC_ERROR_REF(error));
1314
+ add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error), false);
1240
1315
  if (error == GRPC_ERROR_NONE) {
1241
1316
  grpc_metadata_batch *md =
1242
1317
  &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
1243
- grpc_metadata_batch_filter(exec_ctx, md, recv_initial_filter, call);
1318
+ recv_initial_filter(exec_ctx, call, md);
1244
1319
 
1320
+ /* TODO(ctiller): this could be moved into recv_initial_filter now */
1245
1321
  GPR_TIMER_BEGIN("validate_filtered_metadata", 0);
1246
1322
  validate_filtered_metadata(exec_ctx, bctl);
1247
1323
  GPR_TIMER_END("validate_filtered_metadata", 0);
@@ -1260,90 +1336,25 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
1260
1336
  receiving_stream_ready, call->saved_receiving_stream_ready_bctlp,
1261
1337
  grpc_schedule_on_exec_ctx);
1262
1338
  call->saved_receiving_stream_ready_bctlp = NULL;
1263
- grpc_closure_sched(exec_ctx, saved_rsr_closure, error);
1339
+ grpc_closure_sched(exec_ctx, saved_rsr_closure, GRPC_ERROR_REF(error));
1264
1340
  }
1265
1341
 
1266
1342
  gpr_mu_unlock(&call->mu);
1267
1343
 
1268
- if (gpr_unref(&bctl->steps_to_complete)) {
1269
- post_batch_completion(exec_ctx, bctl);
1270
- }
1344
+ finish_batch_step(exec_ctx, bctl);
1271
1345
  }
1272
1346
 
1273
1347
  static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp,
1274
1348
  grpc_error *error) {
1275
1349
  batch_control *bctl = bctlp;
1276
- grpc_call *call = bctl->call;
1277
- grpc_call *child_call;
1278
- grpc_call *next_child_call;
1279
-
1280
- GRPC_ERROR_REF(error);
1281
-
1282
- gpr_mu_lock(&call->mu);
1283
-
1284
- // If the error has an associated status code, set the call's status.
1285
- intptr_t status;
1286
- if (error != GRPC_ERROR_NONE &&
1287
- grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status)) {
1288
- set_status_from_error(exec_ctx, call, STATUS_FROM_CORE, error);
1289
- }
1290
-
1291
- if (bctl->send_initial_metadata) {
1292
- if (error != GRPC_ERROR_NONE) {
1293
- set_status_from_error(exec_ctx, call, STATUS_FROM_CORE, error);
1294
- }
1295
- grpc_metadata_batch_destroy(
1296
- exec_ctx,
1297
- &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
1298
- }
1299
- if (bctl->send_message) {
1300
- call->sending_message = 0;
1301
- }
1302
- if (bctl->send_final_op) {
1303
- grpc_metadata_batch_destroy(
1304
- exec_ctx,
1305
- &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
1306
- }
1307
- if (bctl->recv_final_op) {
1308
- grpc_metadata_batch *md =
1309
- &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
1310
- grpc_metadata_batch_filter(exec_ctx, md, recv_trailing_filter, call);
1311
-
1312
- call->received_final_op = true;
1313
- /* propagate cancellation to any interested children */
1314
- child_call = call->first_child;
1315
- if (child_call != NULL) {
1316
- do {
1317
- next_child_call = child_call->sibling_next;
1318
- if (child_call->cancellation_is_inherited) {
1319
- GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
1320
- grpc_call_cancel(child_call, NULL);
1321
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
1322
- }
1323
- child_call = next_child_call;
1324
- } while (child_call != call->first_child);
1325
- }
1326
1350
 
1327
- if (call->is_client) {
1328
- get_final_status(call, set_status_value_directly,
1329
- call->final_op.client.status);
1330
- get_final_details(call, call->final_op.client.status_details,
1331
- call->final_op.client.status_details_capacity);
1332
- } else {
1333
- get_final_status(call, set_cancelled_value,
1334
- call->final_op.server.cancelled);
1335
- }
1336
-
1337
- GRPC_ERROR_UNREF(error);
1338
- error = GRPC_ERROR_NONE;
1339
- }
1340
- add_batch_error(bctl, GRPC_ERROR_REF(error));
1341
- gpr_mu_unlock(&call->mu);
1342
- if (gpr_unref(&bctl->steps_to_complete)) {
1343
- post_batch_completion(exec_ctx, bctl);
1344
- }
1351
+ add_batch_error(exec_ctx, bctl, GRPC_ERROR_REF(error), false);
1352
+ finish_batch_step(exec_ctx, bctl);
1353
+ }
1345
1354
 
1346
- GRPC_ERROR_UNREF(error);
1355
+ static void free_no_op_completion(grpc_exec_ctx *exec_ctx, void *p,
1356
+ grpc_cq_completion *completion) {
1357
+ gpr_free(completion);
1347
1358
  }
1348
1359
 
1349
1360
  static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
@@ -1360,33 +1371,33 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
1360
1371
  grpc_metadata compression_md;
1361
1372
 
1362
1373
  GPR_TIMER_BEGIN("grpc_call_start_batch", 0);
1363
-
1364
1374
  GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag);
1365
1375
 
1366
- /* TODO(ctiller): this feels like it could be made lock-free */
1367
- gpr_mu_lock(&call->mu);
1368
- bctl = allocate_batch_control(call);
1369
- memset(bctl, 0, sizeof(*bctl));
1370
- bctl->call = call;
1371
- bctl->notify_tag = notify_tag;
1372
- bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
1373
-
1374
- grpc_transport_stream_op *stream_op = &bctl->op;
1375
- memset(stream_op, 0, sizeof(*stream_op));
1376
- stream_op->covered_by_poller = true;
1377
-
1378
1376
  if (nops == 0) {
1379
- GRPC_CALL_INTERNAL_REF(call, "completion");
1380
- bctl->error = GRPC_ERROR_NONE;
1381
1377
  if (!is_notify_tag_closure) {
1382
1378
  grpc_cq_begin_op(call->cq, notify_tag);
1379
+ grpc_cq_end_op(exec_ctx, call->cq, notify_tag, GRPC_ERROR_NONE,
1380
+ free_no_op_completion, NULL,
1381
+ gpr_malloc(sizeof(grpc_cq_completion)));
1382
+ } else {
1383
+ grpc_closure_sched(exec_ctx, notify_tag, GRPC_ERROR_NONE);
1383
1384
  }
1384
- gpr_mu_unlock(&call->mu);
1385
- post_batch_completion(exec_ctx, bctl);
1386
1385
  error = GRPC_CALL_OK;
1387
1386
  goto done;
1388
1387
  }
1389
1388
 
1389
+ bctl = allocate_batch_control(call, ops, nops);
1390
+ if (bctl == NULL) {
1391
+ return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
1392
+ }
1393
+ bctl->notify_tag = notify_tag;
1394
+ bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
1395
+
1396
+ gpr_mu_lock(&call->mu);
1397
+ grpc_transport_stream_op *stream_op = &bctl->op;
1398
+ memset(stream_op, 0, sizeof(*stream_op));
1399
+ stream_op->covered_by_poller = true;
1400
+
1390
1401
  /* rewrite batch ops into a transport op */
1391
1402
  for (i = 0; i < nops; i++) {
1392
1403
  op = &ops[i];
@@ -1426,13 +1437,10 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
1426
1437
  const grpc_compression_algorithm calgo =
1427
1438
  compression_algorithm_for_level_locked(
1428
1439
  call, effective_compression_level);
1429
- char *calgo_name = NULL;
1430
- grpc_compression_algorithm_name(calgo, &calgo_name);
1431
1440
  // the following will be picked up by the compress filter and used as
1432
1441
  // the call's compression algorithm.
1433
- compression_md.key = GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY;
1434
- compression_md.value = calgo_name;
1435
- compression_md.value_length = strlen(calgo_name);
1442
+ compression_md.key = GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST;
1443
+ compression_md.value = grpc_compression_algorithm_slice(calgo);
1436
1444
  additional_metadata_count++;
1437
1445
  }
1438
1446
 
@@ -1524,28 +1532,39 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
1524
1532
  }
1525
1533
  bctl->send_final_op = 1;
1526
1534
  call->sent_final_op = 1;
1535
+ GPR_ASSERT(call->send_extra_metadata_count == 0);
1527
1536
  call->send_extra_metadata_count = 1;
1528
1537
  call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
1529
1538
  exec_ctx, call->channel, op->data.send_status_from_server.status);
1530
- if (op->data.send_status_from_server.status_details != NULL) {
1531
- call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings(
1532
- exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
1533
- grpc_mdstr_from_string(
1534
- op->data.send_status_from_server.status_details));
1535
- call->send_extra_metadata_count++;
1536
- set_status_details(
1537
- exec_ctx, call, STATUS_FROM_API_OVERRIDE,
1538
- GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value));
1539
- }
1540
- if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
1541
- set_status_code(call, STATUS_FROM_API_OVERRIDE,
1542
- (uint32_t)op->data.send_status_from_server.status);
1539
+ {
1540
+ grpc_error *override_error = GRPC_ERROR_NONE;
1541
+ if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
1542
+ override_error = GRPC_ERROR_CREATE("Error from server send status");
1543
+ }
1544
+ if (op->data.send_status_from_server.status_details != NULL) {
1545
+ call->send_extra_metadata[1].md = grpc_mdelem_from_slices(
1546
+ exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
1547
+ grpc_slice_ref_internal(
1548
+ *op->data.send_status_from_server.status_details));
1549
+ call->send_extra_metadata_count++;
1550
+ char *msg = grpc_slice_to_c_string(
1551
+ GRPC_MDVALUE(call->send_extra_metadata[1].md));
1552
+ override_error = grpc_error_set_str(
1553
+ override_error, GRPC_ERROR_STR_GRPC_MESSAGE, msg);
1554
+ gpr_free(msg);
1555
+ }
1556
+ set_status_from_error(exec_ctx, call, STATUS_FROM_API_OVERRIDE,
1557
+ override_error);
1543
1558
  }
1544
1559
  if (!prepare_application_metadata(
1545
1560
  exec_ctx, call,
1546
1561
  (int)op->data.send_status_from_server.trailing_metadata_count,
1547
1562
  op->data.send_status_from_server.trailing_metadata, 1, 1, NULL,
1548
1563
  0)) {
1564
+ for (int n = 0; n < call->send_extra_metadata_count; n++) {
1565
+ GRPC_MDELEM_UNREF(exec_ctx, call->send_extra_metadata[n].md);
1566
+ }
1567
+ call->send_extra_metadata_count = 0;
1549
1568
  error = GRPC_CALL_ERROR_INVALID_METADATA;
1550
1569
  goto done_with_error;
1551
1570
  }
@@ -1618,8 +1637,6 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
1618
1637
  call->final_op.client.status = op->data.recv_status_on_client.status;
1619
1638
  call->final_op.client.status_details =
1620
1639
  op->data.recv_status_on_client.status_details;
1621
- call->final_op.client.status_details_capacity =
1622
- op->data.recv_status_on_client.status_details_capacity;
1623
1640
  bctl->recv_final_op = 1;
1624
1641
  stream_op->recv_trailing_metadata =
1625
1642
  &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
@@ -1662,6 +1679,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
1662
1679
  grpc_closure_init(&bctl->finish_batch, finish_batch, bctl,
1663
1680
  grpc_schedule_on_exec_ctx);
1664
1681
  stream_op->on_complete = &bctl->finish_batch;
1682
+ call->sent_any_op = true;
1665
1683
  gpr_mu_unlock(&call->mu);
1666
1684
 
1667
1685
  execute_op(exec_ctx, call, stream_op);