grpc 1.2.5 → 1.3.4

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

Potentially problematic release.


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

Files changed (327) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +1434 -399
  3. data/etc/roots.pem +34 -150
  4. data/include/grpc/grpc.h +71 -0
  5. data/include/grpc/impl/codegen/atm.h +5 -0
  6. data/include/grpc/impl/codegen/atm_gcc_atomic.h +6 -0
  7. data/include/grpc/impl/codegen/atm_gcc_sync.h +2 -0
  8. data/include/grpc/impl/codegen/atm_windows.h +11 -0
  9. data/include/grpc/impl/codegen/grpc_types.h +54 -13
  10. data/include/grpc/impl/codegen/port_platform.h +15 -1
  11. data/include/grpc/support/alloc.h +2 -1
  12. data/include/grpc/support/sync.h +4 -0
  13. data/include/grpc/support/tls.h +1 -1
  14. data/src/core/ext/census/gen/trace_context.pb.h +1 -1
  15. data/src/core/ext/census/grpc_filter.c +14 -10
  16. data/src/core/ext/census/grpc_plugin.c +3 -1
  17. data/src/core/ext/census/trace_label.h +1 -1
  18. data/src/core/ext/census/trace_propagation.h +1 -1
  19. data/src/core/ext/census/trace_status.h +1 -1
  20. data/src/core/ext/census/trace_string.h +1 -1
  21. data/src/core/ext/census/tracing.h +1 -1
  22. data/src/core/ext/{client_channel → filters/client_channel}/channel_connectivity.c +56 -27
  23. data/src/core/ext/{client_channel → filters/client_channel}/client_channel.c +407 -202
  24. data/src/core/ext/{client_channel → filters/client_channel}/client_channel.h +10 -6
  25. data/src/core/ext/{client_channel → filters/client_channel}/client_channel_factory.c +1 -1
  26. data/src/core/ext/{client_channel → filters/client_channel}/client_channel_factory.h +4 -4
  27. data/src/core/ext/{client_channel → filters/client_channel}/client_channel_plugin.c +12 -7
  28. data/src/core/ext/{client_channel → filters/client_channel}/connector.c +1 -1
  29. data/src/core/ext/{client_channel → filters/client_channel}/connector.h +3 -5
  30. data/src/core/ext/{client_channel → filters/client_channel}/http_connect_handshaker.c +6 -6
  31. data/src/core/ext/{client_channel → filters/client_channel}/http_connect_handshaker.h +3 -3
  32. data/src/core/ext/{client_channel → filters/client_channel}/http_proxy.c +4 -4
  33. data/src/core/ext/{client_channel → filters/client_channel}/http_proxy.h +3 -3
  34. data/src/core/ext/{client_channel → filters/client_channel}/lb_policy.c +1 -1
  35. data/src/core/ext/{client_channel → filters/client_channel}/lb_policy.h +4 -4
  36. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/grpclb/grpclb.c +22 -20
  37. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/grpclb/grpclb.h +4 -4
  38. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/grpclb/grpclb_channel.h +5 -4
  39. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/grpclb/grpclb_channel_secure.c +2 -2
  40. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/grpclb/load_balancer_api.c +1 -1
  41. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/grpclb/load_balancer_api.h +6 -5
  42. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/grpclb/proto/grpc/lb/v1/load_balancer.pb.c +1 -1
  43. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/grpclb/proto/grpc/lb/v1/load_balancer.pb.h +0 -0
  44. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/pick_first/pick_first.c +20 -15
  45. data/src/core/ext/{lb_policy → filters/client_channel/lb_policy}/round_robin/round_robin.c +21 -16
  46. data/src/core/ext/{client_channel → filters/client_channel}/lb_policy_factory.c +1 -1
  47. data/src/core/ext/{client_channel → filters/client_channel}/lb_policy_factory.h +5 -5
  48. data/src/core/ext/{client_channel → filters/client_channel}/lb_policy_registry.c +1 -1
  49. data/src/core/ext/{client_channel → filters/client_channel}/lb_policy_registry.h +4 -4
  50. data/src/core/ext/{client_channel → filters/client_channel}/parse_address.c +1 -1
  51. data/src/core/ext/{client_channel → filters/client_channel}/parse_address.h +4 -4
  52. data/src/core/ext/{client_channel → filters/client_channel}/proxy_mapper.c +1 -1
  53. data/src/core/ext/{client_channel → filters/client_channel}/proxy_mapper.h +3 -3
  54. data/src/core/ext/{client_channel → filters/client_channel}/proxy_mapper_registry.c +10 -4
  55. data/src/core/ext/{client_channel → filters/client_channel}/proxy_mapper_registry.h +4 -4
  56. data/src/core/ext/{client_channel → filters/client_channel}/resolver.c +1 -1
  57. data/src/core/ext/{client_channel → filters/client_channel}/resolver.h +4 -4
  58. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c +350 -0
  59. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h +66 -0
  60. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c +319 -0
  61. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c +289 -0
  62. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +64 -0
  63. data/src/core/ext/{resolver → filters/client_channel/resolver}/dns/native/dns_resolver.c +21 -5
  64. data/src/core/ext/{resolver → filters/client_channel/resolver}/sockaddr/sockaddr_resolver.c +3 -3
  65. data/src/core/ext/{client_channel → filters/client_channel}/resolver_factory.c +1 -1
  66. data/src/core/ext/{client_channel → filters/client_channel}/resolver_factory.h +6 -6
  67. data/src/core/ext/{client_channel → filters/client_channel}/resolver_registry.c +1 -2
  68. data/src/core/ext/{client_channel → filters/client_channel}/resolver_registry.h +4 -4
  69. data/src/core/ext/filters/client_channel/retry_throttle.c +210 -0
  70. data/src/core/ext/filters/client_channel/retry_throttle.h +65 -0
  71. data/src/core/ext/{client_channel → filters/client_channel}/subchannel.c +49 -43
  72. data/src/core/ext/{client_channel → filters/client_channel}/subchannel.h +21 -7
  73. data/src/core/ext/{client_channel → filters/client_channel}/subchannel_index.c +1 -1
  74. data/src/core/ext/{client_channel → filters/client_channel}/subchannel_index.h +5 -5
  75. data/src/core/ext/{client_channel → filters/client_channel}/uri_parser.c +1 -1
  76. data/src/core/ext/{client_channel → filters/client_channel}/uri_parser.h +3 -3
  77. data/src/core/ext/{load_reporting → filters/load_reporting}/load_reporting.c +4 -2
  78. data/src/core/ext/{load_reporting → filters/load_reporting}/load_reporting.h +3 -3
  79. data/src/core/ext/{load_reporting → filters/load_reporting}/load_reporting_filter.c +17 -14
  80. data/src/core/ext/{load_reporting → filters/load_reporting}/load_reporting_filter.h +4 -4
  81. data/src/core/ext/filters/max_age/max_age_filter.c +439 -0
  82. data/src/core/ext/filters/max_age/max_age_filter.h +39 -0
  83. data/src/core/ext/transport/chttp2/client/chttp2_connector.c +6 -41
  84. data/src/core/ext/transport/chttp2/client/chttp2_connector.h +1 -1
  85. data/src/core/ext/transport/chttp2/client/insecure/channel_create.c +2 -2
  86. data/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c +3 -3
  87. data/src/core/ext/transport/chttp2/server/chttp2_server.c +2 -2
  88. data/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c +2 -5
  89. data/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c +2 -2
  90. data/src/core/ext/transport/chttp2/transport/chttp2_transport.c +449 -204
  91. data/src/core/ext/transport/chttp2/transport/frame_data.c +10 -7
  92. data/src/core/ext/transport/chttp2/transport/frame_goaway.c +3 -2
  93. data/src/core/ext/transport/chttp2/transport/frame_ping.c +37 -7
  94. data/src/core/ext/transport/chttp2/transport/frame_ping.h +3 -0
  95. data/src/core/ext/transport/chttp2/transport/frame_rst_stream.c +4 -3
  96. data/src/core/ext/transport/chttp2/transport/frame_settings.c +18 -38
  97. data/src/core/ext/transport/chttp2/transport/frame_settings.h +1 -29
  98. data/src/core/ext/transport/chttp2/transport/frame_window_update.c +2 -2
  99. data/src/core/ext/transport/chttp2/transport/hpack_encoder.c +64 -37
  100. data/src/core/ext/transport/chttp2/transport/hpack_encoder.h +11 -4
  101. data/src/core/ext/transport/chttp2/transport/hpack_parser.c +60 -39
  102. data/src/core/ext/transport/chttp2/transport/hpack_table.c +2 -2
  103. data/src/core/ext/transport/chttp2/transport/http2_settings.c +75 -0
  104. data/src/core/ext/transport/chttp2/transport/http2_settings.h +74 -0
  105. data/src/core/ext/transport/chttp2/transport/incoming_metadata.c +22 -43
  106. data/src/core/ext/transport/chttp2/transport/incoming_metadata.h +8 -10
  107. data/src/core/ext/transport/chttp2/transport/internal.h +24 -2
  108. data/src/core/ext/transport/chttp2/transport/parsing.c +33 -15
  109. data/src/core/ext/transport/chttp2/transport/writing.c +56 -10
  110. data/src/core/lib/channel/channel_args.c +7 -0
  111. data/src/core/lib/channel/channel_args.h +2 -0
  112. data/src/core/lib/channel/channel_stack.c +20 -27
  113. data/src/core/lib/channel/channel_stack.h +18 -16
  114. data/src/core/lib/channel/compress_filter.c +20 -18
  115. data/src/core/lib/channel/connected_channel.c +9 -8
  116. data/src/core/lib/channel/deadline_filter.c +28 -24
  117. data/src/core/lib/channel/deadline_filter.h +3 -3
  118. data/src/core/lib/channel/handshaker.c +3 -2
  119. data/src/core/lib/channel/http_client_filter.c +119 -61
  120. data/src/core/lib/channel/http_server_filter.c +124 -69
  121. data/src/core/lib/channel/message_size_filter.c +23 -19
  122. data/src/core/lib/http/httpcli.c +8 -6
  123. data/src/core/lib/http/httpcli_security_connector.c +5 -5
  124. data/src/core/lib/http/parser.c +57 -31
  125. data/src/core/lib/iomgr/closure.c +15 -0
  126. data/src/core/lib/iomgr/closure.h +4 -0
  127. data/src/core/lib/iomgr/combiner.c +8 -0
  128. data/src/core/lib/iomgr/endpoint_pair.h +2 -3
  129. data/src/core/lib/iomgr/endpoint_pair_posix.c +10 -7
  130. data/src/core/lib/iomgr/endpoint_pair_uv.c +2 -3
  131. data/src/core/lib/iomgr/endpoint_pair_windows.c +9 -6
  132. data/src/core/lib/iomgr/error.c +360 -177
  133. data/src/core/lib/iomgr/error.h +31 -33
  134. data/src/core/lib/iomgr/error_internal.h +30 -9
  135. data/src/core/lib/iomgr/ev_epoll_linux.c +25 -239
  136. data/src/core/lib/iomgr/ev_poll_posix.c +11 -7
  137. data/src/core/lib/iomgr/ev_posix.c +6 -0
  138. data/src/core/lib/iomgr/ev_posix.h +3 -0
  139. data/src/core/lib/iomgr/exec_ctx.c +6 -0
  140. data/src/core/lib/iomgr/executor.c +8 -2
  141. data/src/core/lib/iomgr/load_file.c +6 -3
  142. data/src/core/lib/iomgr/lockfree_event.c +238 -0
  143. data/src/core/{ext/client_channel/initial_connect_string.h → lib/iomgr/lockfree_event.h} +17 -13
  144. data/src/core/lib/iomgr/pollset.h +4 -0
  145. data/src/core/lib/iomgr/pollset_windows.c +2 -2
  146. data/src/core/lib/iomgr/port.h +9 -0
  147. data/src/core/lib/iomgr/resolve_address_posix.c +15 -9
  148. data/src/core/lib/iomgr/resolve_address_uv.c +8 -6
  149. data/src/core/lib/iomgr/resolve_address_windows.c +2 -2
  150. data/src/core/lib/iomgr/resource_quota.c +19 -4
  151. data/src/core/lib/iomgr/resource_quota.h +2 -0
  152. data/src/core/lib/iomgr/sockaddr_utils.c +3 -1
  153. data/src/core/lib/iomgr/socket_factory_posix.c +110 -0
  154. data/src/core/lib/iomgr/socket_factory_posix.h +90 -0
  155. data/src/core/lib/iomgr/socket_utils_common_posix.c +25 -9
  156. data/src/core/lib/iomgr/socket_utils_posix.h +7 -0
  157. data/src/core/lib/iomgr/tcp_client.h +0 -4
  158. data/src/core/lib/iomgr/tcp_client_posix.c +15 -31
  159. data/src/core/lib/iomgr/tcp_client_uv.c +10 -6
  160. data/src/core/lib/iomgr/tcp_client_windows.c +9 -19
  161. data/src/core/lib/iomgr/tcp_posix.c +111 -22
  162. data/src/core/lib/iomgr/tcp_posix.h +3 -4
  163. data/src/core/lib/iomgr/tcp_server_posix.c +39 -417
  164. data/src/core/lib/iomgr/tcp_server_utils_posix.h +135 -0
  165. data/src/core/lib/iomgr/tcp_server_utils_posix_common.c +221 -0
  166. data/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c +196 -0
  167. data/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c +49 -0
  168. data/src/core/lib/iomgr/tcp_server_uv.c +43 -16
  169. data/src/core/lib/iomgr/tcp_server_windows.c +10 -22
  170. data/src/core/lib/iomgr/tcp_uv.c +16 -13
  171. data/src/core/lib/iomgr/tcp_windows.c +24 -12
  172. data/src/core/lib/iomgr/tcp_windows.h +2 -2
  173. data/src/core/lib/iomgr/timer.h +3 -0
  174. data/src/core/lib/iomgr/timer_generic.c +257 -72
  175. data/src/core/lib/iomgr/timer_generic.h +1 -1
  176. data/src/core/lib/iomgr/timer_heap.c +8 -8
  177. data/src/core/lib/iomgr/udp_server.c +54 -24
  178. data/src/core/lib/iomgr/udp_server.h +7 -7
  179. data/src/core/lib/iomgr/unix_sockets_posix.c +1 -1
  180. data/src/core/lib/iomgr/unix_sockets_posix_noop.c +2 -1
  181. data/src/core/lib/iomgr/wakeup_fd_posix.h +1 -1
  182. data/src/core/lib/profiling/basic_timers.c +1 -1
  183. data/src/core/lib/security/credentials/credentials.h +1 -1
  184. data/src/core/lib/security/credentials/google_default/google_default_credentials.c +10 -9
  185. data/src/core/lib/security/credentials/jwt/json_token.c +1 -1
  186. data/src/core/lib/security/credentials/jwt/jwt_verifier.c +2 -2
  187. data/src/core/lib/security/transport/client_auth_filter.c +33 -26
  188. data/src/core/lib/security/transport/secure_endpoint.c +8 -5
  189. data/src/core/lib/security/transport/security_connector.c +37 -37
  190. data/src/core/lib/security/transport/security_connector.h +1 -1
  191. data/src/core/lib/security/transport/security_handshaker.c +15 -12
  192. data/src/core/lib/security/transport/server_auth_filter.c +20 -18
  193. data/src/core/lib/security/transport/tsi_error.c +5 -3
  194. data/src/core/lib/security/transport/tsi_error.h +1 -1
  195. data/src/core/lib/{security/util → slice}/b64.c +21 -6
  196. data/src/core/lib/{security/util → slice}/b64.h +16 -4
  197. data/src/core/lib/slice/slice.c +4 -2
  198. data/src/core/lib/slice/slice_buffer.c +16 -14
  199. data/src/core/lib/support/arena.c +98 -0
  200. data/src/core/{ext/client_channel/initial_connect_string.c → lib/support/arena.h} +17 -15
  201. data/src/core/{ext/client_channel/default_initial_connect_string.c → lib/support/atm.c} +14 -5
  202. data/src/core/lib/support/cpu_linux.c +5 -0
  203. data/src/core/lib/support/sync.c +4 -0
  204. data/src/core/lib/support/time.c +4 -10
  205. data/src/core/lib/support/wrap_memcpy.c +3 -1
  206. data/src/core/lib/surface/call.c +252 -221
  207. data/src/core/lib/surface/channel.c +72 -21
  208. data/src/core/lib/surface/channel.h +8 -0
  209. data/src/core/lib/surface/completion_queue.c +2 -3
  210. data/src/core/lib/surface/completion_queue_factory.c +77 -0
  211. data/src/core/lib/surface/completion_queue_factory.h +51 -0
  212. data/src/core/lib/surface/init_secure.c +3 -1
  213. data/src/core/lib/surface/lame_client.c +18 -14
  214. data/src/core/lib/surface/server.c +43 -41
  215. data/src/core/lib/surface/validate_metadata.c +8 -4
  216. data/src/core/lib/surface/version.c +2 -2
  217. data/src/core/lib/transport/bdp_estimator.h +1 -1
  218. data/src/core/lib/transport/connectivity_state.c +2 -1
  219. data/src/core/lib/transport/error_utils.c +17 -17
  220. data/src/core/lib/transport/error_utils.h +1 -1
  221. data/src/core/lib/transport/metadata_batch.c +6 -7
  222. data/src/core/lib/transport/pid_controller.c +1 -0
  223. data/src/core/lib/transport/service_config.c +12 -0
  224. data/src/core/lib/transport/service_config.h +6 -0
  225. data/src/core/lib/transport/transport.c +29 -17
  226. data/src/core/lib/transport/transport.h +85 -42
  227. data/src/core/lib/transport/transport_impl.h +5 -3
  228. data/src/core/lib/transport/transport_op_string.c +20 -14
  229. data/src/core/plugin_registry/grpc_plugin_registry.c +8 -0
  230. data/src/core/{lib/tsi → tsi}/fake_transport_security.c +2 -2
  231. data/src/core/{lib/tsi → tsi}/fake_transport_security.h +4 -4
  232. data/src/core/{lib/tsi → tsi}/ssl_transport_security.c +40 -79
  233. data/src/core/{lib/tsi → tsi}/ssl_transport_security.h +44 -21
  234. data/src/core/{lib/tsi → tsi}/ssl_types.h +3 -3
  235. data/src/core/{lib/tsi → tsi}/transport_security.c +2 -2
  236. data/src/core/{lib/tsi → tsi}/transport_security.h +4 -4
  237. data/src/core/{lib/tsi → tsi}/transport_security_interface.h +3 -3
  238. data/src/ruby/ext/grpc/extconf.rb +1 -0
  239. data/src/ruby/ext/grpc/rb_call_credentials.c +2 -2
  240. data/src/ruby/ext/grpc/rb_channel.c +520 -93
  241. data/src/ruby/ext/grpc/rb_channel.h +2 -0
  242. data/src/ruby/ext/grpc/rb_channel_credentials.c +3 -0
  243. data/src/ruby/ext/grpc/rb_compression_options.c +5 -2
  244. data/src/ruby/ext/grpc/rb_event_thread.c +6 -6
  245. data/src/ruby/ext/grpc/rb_grpc.c +29 -7
  246. data/src/ruby/ext/grpc/rb_grpc.h +2 -0
  247. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +10 -0
  248. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +15 -0
  249. data/src/ruby/ext/grpc/rb_server.c +5 -3
  250. data/src/ruby/lib/grpc/version.rb +1 -1
  251. data/src/ruby/spec/channel_connection_spec.rb +173 -0
  252. data/src/ruby/spec/channel_spec.rb +29 -0
  253. data/src/ruby/spec/generic/rpc_server_pool_spec.rb +27 -17
  254. data/third_party/cares/ares_build.h +264 -0
  255. data/third_party/cares/cares/ares.h +636 -0
  256. data/third_party/cares/cares/ares__close_sockets.c +61 -0
  257. data/third_party/cares/cares/ares__get_hostent.c +261 -0
  258. data/third_party/cares/cares/ares__read_line.c +73 -0
  259. data/third_party/cares/cares/ares__timeval.c +111 -0
  260. data/third_party/cares/cares/ares_cancel.c +63 -0
  261. data/third_party/cares/cares/ares_create_query.c +202 -0
  262. data/third_party/cares/cares/ares_data.c +221 -0
  263. data/third_party/cares/cares/ares_data.h +72 -0
  264. data/third_party/cares/cares/ares_destroy.c +108 -0
  265. data/third_party/cares/cares/ares_dns.h +103 -0
  266. data/third_party/cares/cares/ares_expand_name.c +205 -0
  267. data/third_party/cares/cares/ares_expand_string.c +70 -0
  268. data/third_party/cares/cares/ares_fds.c +59 -0
  269. data/third_party/cares/cares/ares_free_hostent.c +41 -0
  270. data/third_party/cares/cares/ares_free_string.c +25 -0
  271. data/third_party/cares/cares/ares_getenv.c +30 -0
  272. data/third_party/cares/cares/ares_getenv.h +26 -0
  273. data/third_party/cares/cares/ares_gethostbyaddr.c +294 -0
  274. data/third_party/cares/cares/ares_gethostbyname.c +518 -0
  275. data/third_party/cares/cares/ares_getnameinfo.c +422 -0
  276. data/third_party/cares/cares/ares_getopt.c +122 -0
  277. data/third_party/cares/cares/ares_getopt.h +53 -0
  278. data/third_party/cares/cares/ares_getsock.c +66 -0
  279. data/third_party/cares/cares/ares_inet_net_pton.h +25 -0
  280. data/third_party/cares/cares/ares_init.c +2146 -0
  281. data/third_party/cares/cares/ares_iphlpapi.h +221 -0
  282. data/third_party/cares/cares/ares_ipv6.h +78 -0
  283. data/third_party/cares/cares/ares_library_init.c +167 -0
  284. data/third_party/cares/cares/ares_library_init.h +42 -0
  285. data/third_party/cares/cares/ares_llist.c +63 -0
  286. data/third_party/cares/cares/ares_llist.h +39 -0
  287. data/third_party/cares/cares/ares_mkquery.c +24 -0
  288. data/third_party/cares/cares/ares_nowarn.c +260 -0
  289. data/third_party/cares/cares/ares_nowarn.h +61 -0
  290. data/third_party/cares/cares/ares_options.c +402 -0
  291. data/third_party/cares/cares/ares_parse_a_reply.c +264 -0
  292. data/third_party/cares/cares/ares_parse_aaaa_reply.c +264 -0
  293. data/third_party/cares/cares/ares_parse_mx_reply.c +170 -0
  294. data/third_party/cares/cares/ares_parse_naptr_reply.c +188 -0
  295. data/third_party/cares/cares/ares_parse_ns_reply.c +183 -0
  296. data/third_party/cares/cares/ares_parse_ptr_reply.c +219 -0
  297. data/third_party/cares/cares/ares_parse_soa_reply.c +133 -0
  298. data/third_party/cares/cares/ares_parse_srv_reply.c +179 -0
  299. data/third_party/cares/cares/ares_parse_txt_reply.c +220 -0
  300. data/third_party/cares/cares/ares_platform.c +11035 -0
  301. data/third_party/cares/cares/ares_platform.h +43 -0
  302. data/third_party/cares/cares/ares_private.h +363 -0
  303. data/third_party/cares/cares/ares_process.c +1359 -0
  304. data/third_party/cares/cares/ares_query.c +186 -0
  305. data/third_party/cares/cares/ares_rules.h +125 -0
  306. data/third_party/cares/cares/ares_search.c +316 -0
  307. data/third_party/cares/cares/ares_send.c +131 -0
  308. data/third_party/cares/cares/ares_setup.h +217 -0
  309. data/third_party/cares/cares/ares_strcasecmp.c +66 -0
  310. data/third_party/cares/cares/ares_strcasecmp.h +30 -0
  311. data/third_party/cares/cares/ares_strdup.c +49 -0
  312. data/third_party/cares/cares/ares_strdup.h +24 -0
  313. data/third_party/cares/cares/ares_strerror.c +56 -0
  314. data/third_party/cares/cares/ares_timeout.c +88 -0
  315. data/third_party/cares/cares/ares_version.c +11 -0
  316. data/third_party/cares/cares/ares_version.h +24 -0
  317. data/third_party/cares/cares/ares_writev.c +79 -0
  318. data/third_party/cares/cares/bitncmp.c +59 -0
  319. data/third_party/cares/cares/bitncmp.h +26 -0
  320. data/third_party/cares/cares/config-win32.h +377 -0
  321. data/third_party/cares/cares/inet_net_pton.c +450 -0
  322. data/third_party/cares/cares/inet_ntop.c +208 -0
  323. data/third_party/cares/cares/setup_once.h +554 -0
  324. data/third_party/cares/cares/windows_port.c +22 -0
  325. data/third_party/cares/config_darwin/ares_config.h +523 -0
  326. data/third_party/cares/config_linux/ares_config.h +524 -0
  327. metadata +164 -68
@@ -157,7 +157,6 @@
157
157
  #define GPR_GETPID_IN_UNISTD_H 1
158
158
  #define GPR_SUPPORT_CHANNELS_FROM_FD 1
159
159
  #elif defined(__linux__)
160
- #define GPR_POSIX_CRASH_HANDLER 1
161
160
  #define GPR_PLATFORM_STRING "linux"
162
161
  #ifndef _BSD_SOURCE
163
162
  #define _BSD_SOURCE
@@ -187,6 +186,11 @@
187
186
  #else /* _LP64 */
188
187
  #define GPR_ARCH_32 1
189
188
  #endif /* _LP64 */
189
+ #ifdef __GLIBC__
190
+ #define GPR_POSIX_CRASH_HANDLER 1
191
+ #else /* musl libc */
192
+ #define GPR_MUSL_LIBC_COMPAT 1
193
+ #endif
190
194
  #elif defined(__APPLE__)
191
195
  #include <Availability.h>
192
196
  #include <TargetConditionals.h>
@@ -364,11 +368,21 @@ typedef unsigned __int64 uint64_t;
364
368
  power of two */
365
369
  #define GPR_MAX_ALIGNMENT 16
366
370
 
371
+ #ifndef GRPC_ARES
372
+ #ifdef GPR_WINDOWS
373
+ #define GRPC_ARES 0
374
+ #else
375
+ #define GRPC_ARES 1
376
+ #endif
377
+ #endif
378
+
367
379
  #ifndef GRPC_MUST_USE_RESULT
368
380
  #if defined(__GNUC__) && !defined(__MINGW32__)
369
381
  #define GRPC_MUST_USE_RESULT __attribute__((warn_unused_result))
382
+ #define GPR_ALIGN_STRUCT(n) __attribute__((aligned(n)))
370
383
  #else
371
384
  #define GRPC_MUST_USE_RESULT
385
+ #define GPR_ALIGN_STRUCT(n)
372
386
  #endif
373
387
  #endif
374
388
 
@@ -68,7 +68,8 @@ GPRAPI void gpr_free_aligned(void *ptr);
68
68
 
69
69
  /** Request the family of allocation functions in \a functions be used. NOTE
70
70
  * that this request will be honored in a *best effort* basis and that no
71
- * guarantees are made about the default functions (eg, malloc) being called. */
71
+ * guarantees are made about the default functions (eg, malloc) being called.
72
+ * The functions.free_fn implementation must be a no-op for NULL input. */
72
73
  GPRAPI void gpr_set_allocation_functions(gpr_allocation_functions functions);
73
74
 
74
75
  /** Return the family of allocation functions currently in effect. */
@@ -164,6 +164,10 @@ GPRAPI void gpr_refn(gpr_refcount *r, int n);
164
164
  zero. . Requires *r initialized. */
165
165
  GPRAPI int gpr_unref(gpr_refcount *r);
166
166
 
167
+ /* Return non-zero iff the reference count of *r is one, and thus is owned
168
+ by exactly one object. */
169
+ GPRAPI int gpr_ref_is_unique(gpr_refcount *r);
170
+
167
171
  /* --- Stats counters ---
168
172
 
169
173
  These calls act on the integral type gpr_stats_counter. It requires no
@@ -58,7 +58,7 @@
58
58
  gpr_tls_set(&foo, new_value);
59
59
 
60
60
  Accessing a thread local:
61
- current_value = gpr_tls_get(&foo, value);
61
+ current_value = gpr_tls_get(&foo);
62
62
 
63
63
  ALL functions here may be implemented as macros. */
64
64
 
@@ -90,4 +90,4 @@ extern const pb_field_t google_trace_TraceContext_fields[5];
90
90
  #endif
91
91
  /* @@protoc_insertion_point(eof) */
92
92
 
93
- #endif
93
+ #endif /* GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H */
@@ -74,17 +74,18 @@ static void extract_and_annotate_method_tag(grpc_metadata_batch *md,
74
74
  }
75
75
 
76
76
  static void client_mutate_op(grpc_call_element *elem,
77
- grpc_transport_stream_op *op) {
77
+ grpc_transport_stream_op_batch *op) {
78
78
  call_data *calld = elem->call_data;
79
79
  channel_data *chand = elem->channel_data;
80
80
  if (op->send_initial_metadata) {
81
- extract_and_annotate_method_tag(op->send_initial_metadata, calld, chand);
81
+ extract_and_annotate_method_tag(
82
+ op->payload->send_initial_metadata.send_initial_metadata, calld, chand);
82
83
  }
83
84
  }
84
85
 
85
86
  static void client_start_transport_op(grpc_exec_ctx *exec_ctx,
86
87
  grpc_call_element *elem,
87
- grpc_transport_stream_op *op) {
88
+ grpc_transport_stream_op_batch *op) {
88
89
  client_mutate_op(elem, op);
89
90
  grpc_call_next_op(exec_ctx, elem, op);
90
91
  }
@@ -103,19 +104,22 @@ static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr,
103
104
  }
104
105
 
105
106
  static void server_mutate_op(grpc_call_element *elem,
106
- grpc_transport_stream_op *op) {
107
+ grpc_transport_stream_op_batch *op) {
107
108
  call_data *calld = elem->call_data;
108
109
  if (op->recv_initial_metadata) {
109
110
  /* substitute our callback for the op callback */
110
- calld->recv_initial_metadata = op->recv_initial_metadata;
111
- calld->on_done_recv = op->recv_initial_metadata_ready;
112
- op->recv_initial_metadata_ready = &calld->finish_recv;
111
+ calld->recv_initial_metadata =
112
+ op->payload->recv_initial_metadata.recv_initial_metadata;
113
+ calld->on_done_recv =
114
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready;
115
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready =
116
+ &calld->finish_recv;
113
117
  }
114
118
  }
115
119
 
116
120
  static void server_start_transport_op(grpc_exec_ctx *exec_ctx,
117
121
  grpc_call_element *elem,
118
- grpc_transport_stream_op *op) {
122
+ grpc_transport_stream_op_batch *op) {
119
123
  /* TODO(ctiller): this code fails. I don't know why. I expect it's
120
124
  incomplete, and someone should look at it soon.
121
125
 
@@ -138,7 +142,7 @@ static grpc_error *client_init_call_elem(grpc_exec_ctx *exec_ctx,
138
142
  static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
139
143
  grpc_call_element *elem,
140
144
  const grpc_call_final_info *final_info,
141
- void *ignored) {
145
+ grpc_closure *ignored) {
142
146
  call_data *d = elem->call_data;
143
147
  GPR_ASSERT(d != NULL);
144
148
  /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
@@ -160,7 +164,7 @@ static grpc_error *server_init_call_elem(grpc_exec_ctx *exec_ctx,
160
164
  static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
161
165
  grpc_call_element *elem,
162
166
  const grpc_call_final_info *final_info,
163
- void *ignored) {
167
+ grpc_closure *ignored) {
164
168
  call_data *d = elem->call_data;
165
169
  GPR_ASSERT(d != NULL);
166
170
  /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */
@@ -31,6 +31,8 @@
31
31
  *
32
32
  */
33
33
 
34
+ #include <grpc/support/port_platform.h>
35
+
34
36
  #include <limits.h>
35
37
  #include <string.h>
36
38
 
@@ -48,7 +50,7 @@ static bool is_census_enabled(const grpc_channel_args *a) {
48
50
  return a->args[i].value.integer != 0 && census_enabled();
49
51
  }
50
52
  }
51
- return census_enabled();
53
+ return census_enabled() && !grpc_channel_args_want_minimal_stack(a);
52
54
  }
53
55
 
54
56
  static bool maybe_add_census_filter(grpc_exec_ctx *exec_ctx,
@@ -58,4 +58,4 @@ typedef struct trace_label {
58
58
  } value;
59
59
  } trace_label;
60
60
 
61
- #endif
61
+ #endif /* GRPC_CORE_EXT_CENSUS_TRACE_LABEL_H */
@@ -60,4 +60,4 @@ size_t trace_span_context_to_http_format(const trace_span_context *ctxt,
60
60
  size_t http_format_to_trace_span_context(const char *buf, size_t buf_size,
61
61
  trace_span_context *ctxt);
62
62
 
63
- #endif
63
+ #endif /* GRPC_CORE_EXT_CENSUS_TRACE_PROPAGATION_H */
@@ -42,4 +42,4 @@ typedef struct trace_status {
42
42
  trace_string errorMessage;
43
43
  } trace_status;
44
44
 
45
- #endif
45
+ #endif /* GRPC_CORE_EXT_CENSUS_TRACE_STATUS_H */
@@ -47,4 +47,4 @@ typedef struct trace_string {
47
47
  size_t length;
48
48
  } trace_string;
49
49
 
50
- #endif
50
+ #endif /* GRPC_CORE_EXT_CENSUS_TRACE_STRING_H */
@@ -121,4 +121,4 @@ free to ignore all further calls using the Span. EndSpanOptions can
121
121
  optionally be NULL. */
122
122
  void trace_end_span(const trace_status *status, trace_span_context *span_ctxt);
123
123
 
124
- #endif
124
+ #endif /* GRPC_CORE_EXT_CENSUS_TRACING_H */
@@ -36,7 +36,7 @@
36
36
  #include <grpc/support/alloc.h>
37
37
  #include <grpc/support/log.h>
38
38
 
39
- #include "src/core/ext/client_channel/client_channel.h"
39
+ #include "src/core/ext/filters/client_channel/client_channel.h"
40
40
  #include "src/core/lib/iomgr/timer.h"
41
41
  #include "src/core/lib/surface/api_trace.h"
42
42
  #include "src/core/lib/surface/completion_queue.h"
@@ -67,9 +67,8 @@ grpc_connectivity_state grpc_channel_check_connectivity_state(
67
67
 
68
68
  typedef enum {
69
69
  WAITING,
70
- CALLING_BACK,
70
+ READY_TO_CALL_BACK,
71
71
  CALLING_BACK_AND_FINISHED,
72
- CALLED_BACK
73
72
  } callback_phase;
74
73
 
75
74
  typedef struct {
@@ -77,11 +76,13 @@ typedef struct {
77
76
  callback_phase phase;
78
77
  grpc_closure on_complete;
79
78
  grpc_closure on_timeout;
79
+ grpc_closure watcher_timer_init;
80
80
  grpc_timer alarm;
81
81
  grpc_connectivity_state state;
82
82
  grpc_completion_queue *cq;
83
83
  grpc_cq_completion completion_storage;
84
84
  grpc_channel *channel;
85
+ grpc_error *error;
85
86
  void *tag;
86
87
  } state_watcher;
87
88
 
@@ -105,11 +106,8 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
105
106
  gpr_mu_lock(&w->mu);
106
107
  switch (w->phase) {
107
108
  case WAITING:
108
- case CALLED_BACK:
109
+ case READY_TO_CALL_BACK:
109
110
  GPR_UNREACHABLE_CODE(return );
110
- case CALLING_BACK:
111
- w->phase = CALLED_BACK;
112
- break;
113
111
  case CALLING_BACK_AND_FINISHED:
114
112
  delete = 1;
115
113
  break;
@@ -123,10 +121,14 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
123
121
 
124
122
  static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
125
123
  bool due_to_completion, grpc_error *error) {
126
- int delete = 0;
127
-
128
124
  if (due_to_completion) {
129
125
  grpc_timer_cancel(exec_ctx, &w->alarm);
126
+ } else {
127
+ grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(
128
+ grpc_channel_get_channel_stack(w->channel));
129
+ grpc_client_channel_watch_connectivity_state(exec_ctx, client_channel_elem,
130
+ grpc_cq_pollset(w->cq), NULL,
131
+ &w->on_complete, NULL);
130
132
  }
131
133
 
132
134
  gpr_mu_lock(&w->mu);
@@ -139,33 +141,35 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
139
141
  error = GRPC_ERROR_NONE;
140
142
  } else {
141
143
  if (error == GRPC_ERROR_NONE) {
142
- error =
143
- GRPC_ERROR_CREATE("Timed out waiting for connection state change");
144
+ error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
145
+ "Timed out waiting for connection state change");
144
146
  } else if (error == GRPC_ERROR_CANCELLED) {
145
147
  error = GRPC_ERROR_NONE;
146
148
  }
147
149
  }
148
150
  switch (w->phase) {
149
151
  case WAITING:
150
- w->phase = CALLING_BACK;
151
- grpc_cq_end_op(exec_ctx, w->cq, w->tag, GRPC_ERROR_REF(error),
152
- finished_completion, w, &w->completion_storage);
152
+ GRPC_ERROR_REF(error);
153
+ w->error = error;
154
+ w->phase = READY_TO_CALL_BACK;
153
155
  break;
154
- case CALLING_BACK:
156
+ case READY_TO_CALL_BACK:
157
+ if (error != GRPC_ERROR_NONE) {
158
+ GPR_ASSERT(!due_to_completion);
159
+ GRPC_ERROR_UNREF(w->error);
160
+ GRPC_ERROR_REF(error);
161
+ w->error = error;
162
+ }
155
163
  w->phase = CALLING_BACK_AND_FINISHED;
164
+ grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->error, finished_completion, w,
165
+ &w->completion_storage);
156
166
  break;
157
167
  case CALLING_BACK_AND_FINISHED:
158
168
  GPR_UNREACHABLE_CODE(return );
159
- case CALLED_BACK:
160
- delete = 1;
161
169
  break;
162
170
  }
163
171
  gpr_mu_unlock(&w->mu);
164
172
 
165
- if (delete) {
166
- delete_state_watcher(exec_ctx, w);
167
- }
168
-
169
173
  GRPC_ERROR_UNREF(error);
170
174
  }
171
175
 
@@ -179,6 +183,28 @@ static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw,
179
183
  partly_done(exec_ctx, pw, false, GRPC_ERROR_REF(error));
180
184
  }
181
185
 
186
+ int grpc_channel_num_external_connectivity_watchers(grpc_channel *channel) {
187
+ grpc_channel_element *client_channel_elem =
188
+ grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
189
+ return grpc_client_channel_num_external_connectivity_watchers(
190
+ client_channel_elem);
191
+ }
192
+
193
+ typedef struct watcher_timer_init_arg {
194
+ state_watcher *w;
195
+ gpr_timespec deadline;
196
+ } watcher_timer_init_arg;
197
+
198
+ static void watcher_timer_init(grpc_exec_ctx *exec_ctx, void *arg,
199
+ grpc_error *error_ignored) {
200
+ watcher_timer_init_arg *wa = (watcher_timer_init_arg *)arg;
201
+
202
+ grpc_timer_init(exec_ctx, &wa->w->alarm,
203
+ gpr_convert_clock_type(wa->deadline, GPR_CLOCK_MONOTONIC),
204
+ &wa->w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
205
+ gpr_free(wa);
206
+ }
207
+
182
208
  void grpc_channel_watch_connectivity_state(
183
209
  grpc_channel *channel, grpc_connectivity_state last_observed_state,
184
210
  gpr_timespec deadline, grpc_completion_queue *cq, void *tag) {
@@ -208,16 +234,19 @@ void grpc_channel_watch_connectivity_state(
208
234
  w->cq = cq;
209
235
  w->tag = tag;
210
236
  w->channel = channel;
237
+ w->error = NULL;
211
238
 
212
- grpc_timer_init(&exec_ctx, &w->alarm,
213
- gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
214
- &w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
239
+ watcher_timer_init_arg *wa = gpr_malloc(sizeof(watcher_timer_init_arg));
240
+ wa->w = w;
241
+ wa->deadline = deadline;
242
+ grpc_closure_init(&w->watcher_timer_init, watcher_timer_init, wa,
243
+ grpc_schedule_on_exec_ctx);
215
244
 
216
245
  if (client_channel_elem->filter == &grpc_client_channel_filter) {
217
246
  GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
218
- grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem,
219
- grpc_cq_pollset(cq), &w->state,
220
- &w->on_complete);
247
+ grpc_client_channel_watch_connectivity_state(
248
+ &exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state,
249
+ &w->on_complete, &w->watcher_timer_init);
221
250
  } else {
222
251
  abort();
223
252
  }
@@ -31,7 +31,7 @@
31
31
  *
32
32
  */
33
33
 
34
- #include "src/core/ext/client_channel/client_channel.h"
34
+ #include "src/core/ext/filters/client_channel/client_channel.h"
35
35
 
36
36
  #include <stdbool.h>
37
37
  #include <stdio.h>
@@ -43,11 +43,12 @@
43
43
  #include <grpc/support/sync.h>
44
44
  #include <grpc/support/useful.h>
45
45
 
46
- #include "src/core/ext/client_channel/http_connect_handshaker.h"
47
- #include "src/core/ext/client_channel/lb_policy_registry.h"
48
- #include "src/core/ext/client_channel/proxy_mapper_registry.h"
49
- #include "src/core/ext/client_channel/resolver_registry.h"
50
- #include "src/core/ext/client_channel/subchannel.h"
46
+ #include "src/core/ext/filters/client_channel/http_connect_handshaker.h"
47
+ #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
48
+ #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
49
+ #include "src/core/ext/filters/client_channel/resolver_registry.h"
50
+ #include "src/core/ext/filters/client_channel/retry_throttle.h"
51
+ #include "src/core/ext/filters/client_channel/subchannel.h"
51
52
  #include "src/core/lib/channel/channel_args.h"
52
53
  #include "src/core/lib/channel/connected_channel.h"
53
54
  #include "src/core/lib/channel/deadline_filter.h"
@@ -71,7 +72,8 @@
71
72
  */
72
73
 
73
74
  typedef enum {
74
- WAIT_FOR_READY_UNSET,
75
+ /* zero so it can be default initialized */
76
+ WAIT_FOR_READY_UNSET = 0,
75
77
  WAIT_FOR_READY_FALSE,
76
78
  WAIT_FOR_READY_TRUE
77
79
  } wait_for_ready_value;
@@ -172,6 +174,8 @@ static void *method_parameters_create_from_json(const grpc_json *json) {
172
174
  return value;
173
175
  }
174
176
 
177
+ struct external_connectivity_watcher;
178
+
175
179
  /*************************************************************************
176
180
  * CHANNEL-WIDE FUNCTIONS
177
181
  */
@@ -188,6 +192,8 @@ typedef struct client_channel_channel_data {
188
192
  grpc_combiner *combiner;
189
193
  /** currently active load balancer */
190
194
  grpc_lb_policy *lb_policy;
195
+ /** retry throttle data */
196
+ grpc_server_retry_throttle_data *retry_throttle_data;
191
197
  /** maps method names to method_parameters structs */
192
198
  grpc_slice_hash_table *method_params_table;
193
199
  /** incoming resolver result - set by resolver.next() */
@@ -205,6 +211,11 @@ typedef struct client_channel_channel_data {
205
211
  /** interested parties (owned) */
206
212
  grpc_pollset_set *interested_parties;
207
213
 
214
+ /* external_connectivity_watcher_list head is guarded by its own mutex, since
215
+ * counts need to be grabbed immediately without polling on a cq */
216
+ gpr_mu external_connectivity_watcher_list_mu;
217
+ struct external_connectivity_watcher *external_connectivity_watcher_list_head;
218
+
208
219
  /* the following properties are guarded by a mutex since API's require them
209
220
  to be instantaneously available */
210
221
  gpr_mu info_mu;
@@ -283,6 +294,65 @@ static void watch_lb_policy_locked(grpc_exec_ctx *exec_ctx, channel_data *chand,
283
294
  &w->on_changed);
284
295
  }
285
296
 
297
+ typedef struct {
298
+ char *server_name;
299
+ grpc_server_retry_throttle_data *retry_throttle_data;
300
+ } service_config_parsing_state;
301
+
302
+ static void parse_retry_throttle_params(const grpc_json *field, void *arg) {
303
+ service_config_parsing_state *parsing_state = arg;
304
+ if (strcmp(field->key, "retryThrottling") == 0) {
305
+ if (parsing_state->retry_throttle_data != NULL) return; // Duplicate.
306
+ if (field->type != GRPC_JSON_OBJECT) return;
307
+ int max_milli_tokens = 0;
308
+ int milli_token_ratio = 0;
309
+ for (grpc_json *sub_field = field->child; sub_field != NULL;
310
+ sub_field = sub_field->next) {
311
+ if (sub_field->key == NULL) return;
312
+ if (strcmp(sub_field->key, "maxTokens") == 0) {
313
+ if (max_milli_tokens != 0) return; // Duplicate.
314
+ if (sub_field->type != GRPC_JSON_NUMBER) return;
315
+ max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value);
316
+ if (max_milli_tokens == -1) return;
317
+ max_milli_tokens *= 1000;
318
+ } else if (strcmp(sub_field->key, "tokenRatio") == 0) {
319
+ if (milli_token_ratio != 0) return; // Duplicate.
320
+ if (sub_field->type != GRPC_JSON_NUMBER) return;
321
+ // We support up to 3 decimal digits.
322
+ size_t whole_len = strlen(sub_field->value);
323
+ uint32_t multiplier = 1;
324
+ uint32_t decimal_value = 0;
325
+ const char *decimal_point = strchr(sub_field->value, '.');
326
+ if (decimal_point != NULL) {
327
+ whole_len = (size_t)(decimal_point - sub_field->value);
328
+ multiplier = 1000;
329
+ size_t decimal_len = strlen(decimal_point + 1);
330
+ if (decimal_len > 3) decimal_len = 3;
331
+ if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
332
+ &decimal_value)) {
333
+ return;
334
+ }
335
+ uint32_t decimal_multiplier = 1;
336
+ for (size_t i = 0; i < (3 - decimal_len); ++i) {
337
+ decimal_multiplier *= 10;
338
+ }
339
+ decimal_value *= decimal_multiplier;
340
+ }
341
+ uint32_t whole_value;
342
+ if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len,
343
+ &whole_value)) {
344
+ return;
345
+ }
346
+ milli_token_ratio = (int)((whole_value * multiplier) + decimal_value);
347
+ if (milli_token_ratio <= 0) return;
348
+ }
349
+ }
350
+ parsing_state->retry_throttle_data =
351
+ grpc_retry_throttle_map_get_data_for_server(
352
+ parsing_state->server_name, max_milli_tokens, milli_token_ratio);
353
+ }
354
+ }
355
+
286
356
  static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
287
357
  void *arg, grpc_error *error) {
288
358
  channel_data *chand = arg;
@@ -292,8 +362,11 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
292
362
  grpc_slice_hash_table *method_params_table = NULL;
293
363
  grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
294
364
  bool exit_idle = false;
295
- grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
365
+ grpc_error *state_error =
366
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("No load balancing policy");
296
367
  char *service_config_json = NULL;
368
+ service_config_parsing_state parsing_state;
369
+ memset(&parsing_state, 0, sizeof(parsing_state));
297
370
 
298
371
  if (chand->resolver_result != NULL) {
299
372
  // Find LB policy name.
@@ -308,8 +381,7 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
308
381
  // resolver actually specified.
309
382
  channel_arg =
310
383
  grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
311
- if (channel_arg != NULL) {
312
- GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
384
+ if (channel_arg != NULL && channel_arg->type == GRPC_ARG_POINTER) {
313
385
  grpc_lb_addresses *addresses = channel_arg->value.pointer.p;
314
386
  bool found_backend_address = false;
315
387
  for (size_t i = 0; i < addresses->num_addresses; ++i) {
@@ -354,6 +426,19 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
354
426
  grpc_service_config *service_config =
355
427
  grpc_service_config_create(service_config_json);
356
428
  if (service_config != NULL) {
429
+ channel_arg =
430
+ grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVER_URI);
431
+ GPR_ASSERT(channel_arg != NULL);
432
+ GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
433
+ grpc_uri *uri =
434
+ grpc_uri_parse(exec_ctx, channel_arg->value.string, true);
435
+ GPR_ASSERT(uri->path[0] != '\0');
436
+ parsing_state.server_name =
437
+ uri->path[0] == '/' ? uri->path + 1 : uri->path;
438
+ grpc_service_config_parse_global_params(
439
+ service_config, parse_retry_throttle_params, &parsing_state);
440
+ parsing_state.server_name = NULL;
441
+ grpc_uri_destroy(uri);
357
442
  method_params_table = grpc_service_config_create_method_config_table(
358
443
  exec_ctx, service_config, method_parameters_create_from_json,
359
444
  &method_parameters_vtable);
@@ -385,6 +470,11 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
385
470
  chand->info_service_config_json = service_config_json;
386
471
  }
387
472
  gpr_mu_unlock(&chand->info_mu);
473
+
474
+ if (chand->retry_throttle_data != NULL) {
475
+ grpc_server_retry_throttle_data_unref(chand->retry_throttle_data);
476
+ }
477
+ chand->retry_throttle_data = parsing_state.retry_throttle_data;
388
478
  if (chand->method_params_table != NULL) {
389
479
  grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
390
480
  }
@@ -392,9 +482,9 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
392
482
  if (lb_policy != NULL) {
393
483
  grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures);
394
484
  } else if (chand->resolver == NULL /* disconnected */) {
395
- grpc_closure_list_fail_all(
396
- &chand->waiting_for_config_closures,
397
- GRPC_ERROR_CREATE_REFERENCING("Channel disconnected", &error, 1));
485
+ grpc_closure_list_fail_all(&chand->waiting_for_config_closures,
486
+ GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
487
+ "Channel disconnected", &error, 1));
398
488
  grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures);
399
489
  }
400
490
  if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) {
@@ -422,8 +512,8 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
422
512
  grpc_error *refs[] = {error, state_error};
423
513
  set_channel_connectivity_state_locked(
424
514
  exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
425
- GRPC_ERROR_CREATE_REFERENCING("Got config after disconnection", refs,
426
- GPR_ARRAY_SIZE(refs)),
515
+ GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
516
+ "Got config after disconnection", refs, GPR_ARRAY_SIZE(refs)),
427
517
  "resolver_gone");
428
518
  }
429
519
 
@@ -449,7 +539,7 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
449
539
  static void start_transport_op_locked(grpc_exec_ctx *exec_ctx, void *arg,
450
540
  grpc_error *error_ignored) {
451
541
  grpc_transport_op *op = arg;
452
- grpc_channel_element *elem = op->transport_private.args[0];
542
+ grpc_channel_element *elem = op->handler_private.extra_arg;
453
543
  channel_data *chand = elem->channel_data;
454
544
 
455
545
  if (op->on_connectivity_state_change != NULL) {
@@ -462,8 +552,9 @@ static void start_transport_op_locked(grpc_exec_ctx *exec_ctx, void *arg,
462
552
 
463
553
  if (op->send_ping != NULL) {
464
554
  if (chand->lb_policy == NULL) {
465
- grpc_closure_sched(exec_ctx, op->send_ping,
466
- GRPC_ERROR_CREATE("Ping with no load balancing"));
555
+ grpc_closure_sched(
556
+ exec_ctx, op->send_ping,
557
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("Ping with no load balancing"));
467
558
  } else {
468
559
  grpc_lb_policy_ping_one_locked(exec_ctx, chand->lb_policy, op->send_ping);
469
560
  op->bind_pollset = NULL;
@@ -510,12 +601,12 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
510
601
  op->bind_pollset);
511
602
  }
512
603
 
513
- op->transport_private.args[0] = elem;
604
+ op->handler_private.extra_arg = elem;
514
605
  GRPC_CHANNEL_STACK_REF(chand->owning_stack, "start_transport_op");
515
606
  grpc_closure_sched(
516
- exec_ctx, grpc_closure_init(
517
- &op->transport_private.closure, start_transport_op_locked,
518
- op, grpc_combiner_scheduler(chand->combiner, false)),
607
+ exec_ctx,
608
+ grpc_closure_init(&op->handler_private.closure, start_transport_op_locked,
609
+ op, grpc_combiner_scheduler(chand->combiner, false)),
519
610
  GRPC_ERROR_NONE);
520
611
  }
521
612
 
@@ -548,6 +639,12 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
548
639
  // Initialize data members.
549
640
  chand->combiner = grpc_combiner_create(NULL);
550
641
  gpr_mu_init(&chand->info_mu);
642
+ gpr_mu_init(&chand->external_connectivity_watcher_list_mu);
643
+
644
+ gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
645
+ chand->external_connectivity_watcher_list_head = NULL;
646
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
647
+
551
648
  chand->owning_stack = args->channel_stack;
552
649
  grpc_closure_init(&chand->on_resolver_result_changed,
553
650
  on_resolver_result_changed_locked, chand,
@@ -558,14 +655,26 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
558
655
  // Record client channel factory.
559
656
  const grpc_arg *arg = grpc_channel_args_find(args->channel_args,
560
657
  GRPC_ARG_CLIENT_CHANNEL_FACTORY);
561
- GPR_ASSERT(arg != NULL);
562
- GPR_ASSERT(arg->type == GRPC_ARG_POINTER);
658
+ if (arg == NULL) {
659
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
660
+ "Missing client channel factory in args for client channel filter");
661
+ }
662
+ if (arg->type != GRPC_ARG_POINTER) {
663
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
664
+ "client channel factory arg must be a pointer");
665
+ }
563
666
  grpc_client_channel_factory_ref(arg->value.pointer.p);
564
667
  chand->client_channel_factory = arg->value.pointer.p;
565
668
  // Get server name to resolve, using proxy mapper if needed.
566
669
  arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI);
567
- GPR_ASSERT(arg != NULL);
568
- GPR_ASSERT(arg->type == GRPC_ARG_STRING);
670
+ if (arg == NULL) {
671
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
672
+ "Missing server uri in args for client channel filter");
673
+ }
674
+ if (arg->type != GRPC_ARG_STRING) {
675
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
676
+ "server uri arg must be a string");
677
+ }
569
678
  char *proxy_name = NULL;
570
679
  grpc_channel_args *new_args = NULL;
571
680
  grpc_proxy_mappers_map_name(exec_ctx, arg->value.string, args->channel_args,
@@ -578,7 +687,7 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
578
687
  if (proxy_name != NULL) gpr_free(proxy_name);
579
688
  if (new_args != NULL) grpc_channel_args_destroy(exec_ctx, new_args);
580
689
  if (chand->resolver == NULL) {
581
- return GRPC_ERROR_CREATE("resolver creation failed");
690
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING("resolver creation failed");
582
691
  }
583
692
  return GRPC_ERROR_NONE;
584
693
  }
@@ -612,6 +721,9 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
612
721
  }
613
722
  gpr_free(chand->info_lb_policy_name);
614
723
  gpr_free(chand->info_service_config_json);
724
+ if (chand->retry_throttle_data != NULL) {
725
+ grpc_server_retry_throttle_data_unref(chand->retry_throttle_data);
726
+ }
615
727
  if (chand->method_params_table != NULL) {
616
728
  grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
617
729
  }
@@ -619,6 +731,7 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
619
731
  grpc_pollset_set_destroy(exec_ctx, chand->interested_parties);
620
732
  GRPC_COMBINER_UNREF(exec_ctx, chand->combiner, "client_channel");
621
733
  gpr_mu_destroy(&chand->info_mu);
734
+ gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu);
622
735
  }
623
736
 
624
737
  /*************************************************************************
@@ -631,7 +744,8 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
631
744
  #define CANCELLED_CALL ((grpc_subchannel_call *)1)
632
745
 
633
746
  typedef enum {
634
- GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING,
747
+ /* zero so that it can be default-initialized */
748
+ GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING = 0,
635
749
  GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL
636
750
  } subchannel_creation_phase;
637
751
 
@@ -652,20 +766,21 @@ typedef struct client_channel_call_data {
652
766
  grpc_slice path; // Request path.
653
767
  gpr_timespec call_start_time;
654
768
  gpr_timespec deadline;
769
+ grpc_server_retry_throttle_data *retry_throttle_data;
655
770
  method_parameters *method_params;
656
- grpc_closure read_service_config;
657
771
 
658
772
  grpc_error *cancel_error;
659
773
 
660
774
  /** either 0 for no call, 1 for cancelled, or a pointer to a
661
775
  grpc_subchannel_call */
662
776
  gpr_atm subchannel_call;
777
+ gpr_arena *arena;
663
778
 
664
779
  subchannel_creation_phase creation_phase;
665
780
  grpc_connected_subchannel *connected_subchannel;
666
781
  grpc_polling_entity *pollent;
667
782
 
668
- grpc_transport_stream_op **waiting_ops;
783
+ grpc_transport_stream_op_batch **waiting_ops;
669
784
  size_t waiting_ops_count;
670
785
  size_t waiting_ops_capacity;
671
786
 
@@ -674,6 +789,9 @@ typedef struct client_channel_call_data {
674
789
  grpc_call_stack *owning_call;
675
790
 
676
791
  grpc_linked_mdelem lb_token_mdelem;
792
+
793
+ grpc_closure on_complete;
794
+ grpc_closure *original_on_complete;
677
795
  } call_data;
678
796
 
679
797
  grpc_subchannel_call *grpc_client_channel_get_subchannel_call(
@@ -682,7 +800,8 @@ grpc_subchannel_call *grpc_client_channel_get_subchannel_call(
682
800
  return scc == CANCELLED_CALL ? NULL : scc;
683
801
  }
684
802
 
685
- static void add_waiting_locked(call_data *calld, grpc_transport_stream_op *op) {
803
+ static void add_waiting_locked(call_data *calld,
804
+ grpc_transport_stream_op_batch *op) {
686
805
  GPR_TIMER_BEGIN("add_waiting_locked", 0);
687
806
  if (calld->waiting_ops_count == calld->waiting_ops_capacity) {
688
807
  calld->waiting_ops_capacity = GPR_MAX(3, 2 * calld->waiting_ops_capacity);
@@ -698,7 +817,7 @@ static void fail_locked(grpc_exec_ctx *exec_ctx, call_data *calld,
698
817
  grpc_error *error) {
699
818
  size_t i;
700
819
  for (i = 0; i < calld->waiting_ops_count; i++) {
701
- grpc_transport_stream_op_finish_with_failure(
820
+ grpc_transport_stream_op_batch_finish_with_failure(
702
821
  exec_ctx, calld->waiting_ops[i], GRPC_ERROR_REF(error));
703
822
  }
704
823
  calld->waiting_ops_count = 0;
@@ -711,7 +830,7 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) {
711
830
  }
712
831
 
713
832
  grpc_subchannel_call *call = GET_CALL(calld);
714
- grpc_transport_stream_op **ops = calld->waiting_ops;
833
+ grpc_transport_stream_op_batch **ops = calld->waiting_ops;
715
834
  size_t nops = calld->waiting_ops_count;
716
835
  if (call == CANCELLED_CALL) {
717
836
  fail_locked(exec_ctx, calld, GRPC_ERROR_CANCELLED);
@@ -726,6 +845,51 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) {
726
845
  gpr_free(ops);
727
846
  }
728
847
 
848
+ // Sets calld->method_params and calld->retry_throttle_data.
849
+ // If the method params specify a timeout, populates
850
+ // *per_method_deadline and returns true.
851
+ static bool set_call_method_params_from_service_config_locked(
852
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
853
+ gpr_timespec *per_method_deadline) {
854
+ channel_data *chand = elem->channel_data;
855
+ call_data *calld = elem->call_data;
856
+ if (chand->retry_throttle_data != NULL) {
857
+ calld->retry_throttle_data =
858
+ grpc_server_retry_throttle_data_ref(chand->retry_throttle_data);
859
+ }
860
+ if (chand->method_params_table != NULL) {
861
+ calld->method_params = grpc_method_config_table_get(
862
+ exec_ctx, chand->method_params_table, calld->path);
863
+ if (calld->method_params != NULL) {
864
+ method_parameters_ref(calld->method_params);
865
+ if (gpr_time_cmp(calld->method_params->timeout,
866
+ gpr_time_0(GPR_TIMESPAN)) != 0) {
867
+ *per_method_deadline =
868
+ gpr_time_add(calld->call_start_time, calld->method_params->timeout);
869
+ return true;
870
+ }
871
+ }
872
+ }
873
+ return false;
874
+ }
875
+
876
+ static void apply_final_configuration_locked(grpc_exec_ctx *exec_ctx,
877
+ grpc_call_element *elem) {
878
+ /* apply service-config level configuration to the call (now that we're
879
+ * certain it exists) */
880
+ call_data *calld = elem->call_data;
881
+ gpr_timespec per_method_deadline;
882
+ if (set_call_method_params_from_service_config_locked(exec_ctx, elem,
883
+ &per_method_deadline)) {
884
+ // If the deadline from the service config is shorter than the one
885
+ // from the client API, reset the deadline timer.
886
+ if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) {
887
+ calld->deadline = per_method_deadline;
888
+ grpc_deadline_state_reset(exec_ctx, elem, calld->deadline);
889
+ }
890
+ }
891
+ }
892
+
729
893
  static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
730
894
  grpc_error *error) {
731
895
  grpc_call_element *elem = arg;
@@ -738,12 +902,14 @@ static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
738
902
  calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
739
903
  if (calld->connected_subchannel == NULL) {
740
904
  gpr_atm_no_barrier_store(&calld->subchannel_call, 1);
741
- fail_locked(exec_ctx, calld, GRPC_ERROR_CREATE_REFERENCING(
742
- "Failed to create subchannel", &error, 1));
905
+ fail_locked(exec_ctx, calld,
906
+ GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
907
+ "Failed to create subchannel", &error, 1));
743
908
  } else if (GET_CALL(calld) == CANCELLED_CALL) {
744
909
  /* already cancelled before subchannel became ready */
745
- grpc_error *cancellation_error = GRPC_ERROR_CREATE_REFERENCING(
746
- "Cancelled before creating subchannel", &error, 1);
910
+ grpc_error *cancellation_error =
911
+ GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
912
+ "Cancelled before creating subchannel", &error, 1);
747
913
  /* if due to deadline, attach the deadline exceeded status to the error */
748
914
  if (gpr_time_cmp(calld->deadline, gpr_now(GPR_CLOCK_MONOTONIC)) < 0) {
749
915
  cancellation_error =
@@ -754,17 +920,22 @@ static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
754
920
  } else {
755
921
  /* Create call on subchannel. */
756
922
  grpc_subchannel_call *subchannel_call = NULL;
923
+ const grpc_connected_subchannel_call_args call_args = {
924
+ .pollent = calld->pollent,
925
+ .path = calld->path,
926
+ .start_time = calld->call_start_time,
927
+ .deadline = calld->deadline,
928
+ .arena = calld->arena};
757
929
  grpc_error *new_error = grpc_connected_subchannel_create_call(
758
- exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
759
- calld->call_start_time, calld->deadline, &subchannel_call);
930
+ exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
931
+ gpr_atm_rel_store(&calld->subchannel_call,
932
+ (gpr_atm)(uintptr_t)subchannel_call);
760
933
  if (new_error != GRPC_ERROR_NONE) {
761
934
  new_error = grpc_error_add_child(new_error, error);
762
- subchannel_call = CANCELLED_CALL;
763
935
  fail_locked(exec_ctx, calld, new_error);
936
+ } else {
937
+ retry_waiting_locked(exec_ctx, calld);
764
938
  }
765
- gpr_atm_rel_store(&calld->subchannel_call,
766
- (gpr_atm)(uintptr_t)subchannel_call);
767
- retry_waiting_locked(exec_ctx, calld);
768
939
  }
769
940
  GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel");
770
941
  }
@@ -840,9 +1011,9 @@ static bool pick_subchannel_locked(
840
1011
  cpa = closure->cb_arg;
841
1012
  if (cpa->connected_subchannel == connected_subchannel) {
842
1013
  cpa->connected_subchannel = NULL;
843
- grpc_closure_sched(
844
- exec_ctx, cpa->on_ready,
845
- GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
1014
+ grpc_closure_sched(exec_ctx, cpa->on_ready,
1015
+ GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
1016
+ "Pick cancelled", &error, 1));
846
1017
  }
847
1018
  }
848
1019
  GPR_TIMER_END("pick_subchannel", 0);
@@ -851,6 +1022,7 @@ static bool pick_subchannel_locked(
851
1022
  }
852
1023
  GPR_ASSERT(error == GRPC_ERROR_NONE);
853
1024
  if (chand->lb_policy != NULL) {
1025
+ apply_final_configuration_locked(exec_ctx, elem);
854
1026
  grpc_lb_policy *lb_policy = chand->lb_policy;
855
1027
  GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel");
856
1028
  // If the application explicitly set wait_for_ready, use that.
@@ -898,16 +1070,17 @@ static bool pick_subchannel_locked(
898
1070
  grpc_closure_list_append(&chand->waiting_for_config_closures, &cpa->closure,
899
1071
  GRPC_ERROR_NONE);
900
1072
  } else {
901
- grpc_closure_sched(exec_ctx, on_ready, GRPC_ERROR_CREATE("Disconnected"));
1073
+ grpc_closure_sched(exec_ctx, on_ready,
1074
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("Disconnected"));
902
1075
  }
903
1076
 
904
1077
  GPR_TIMER_END("pick_subchannel", 0);
905
1078
  return false;
906
1079
  }
907
1080
 
908
- static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
909
- grpc_transport_stream_op *op,
910
- grpc_call_element *elem) {
1081
+ static void start_transport_stream_op_batch_locked_inner(
1082
+ grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op,
1083
+ grpc_call_element *elem) {
911
1084
  channel_data *chand = elem->channel_data;
912
1085
  call_data *calld = elem->call_data;
913
1086
  grpc_subchannel_call *call;
@@ -915,7 +1088,7 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
915
1088
  /* need to recheck that another thread hasn't set the call */
916
1089
  call = GET_CALL(calld);
917
1090
  if (call == CANCELLED_CALL) {
918
- grpc_transport_stream_op_finish_with_failure(
1091
+ grpc_transport_stream_op_batch_finish_with_failure(
919
1092
  exec_ctx, op, GRPC_ERROR_REF(calld->cancel_error));
920
1093
  /* early out */
921
1094
  return;
@@ -926,11 +1099,11 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
926
1099
  return;
927
1100
  }
928
1101
  /* if this is a cancellation, then we can raise our cancelled flag */
929
- if (op->cancel_error != GRPC_ERROR_NONE) {
1102
+ if (op->cancel_stream) {
930
1103
  if (!gpr_atm_rel_cas(&calld->subchannel_call, 0,
931
1104
  (gpr_atm)(uintptr_t)CANCELLED_CALL)) {
932
1105
  /* recurse to retry */
933
- start_transport_stream_op_locked_inner(exec_ctx, op, elem);
1106
+ start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
934
1107
  /* early out */
935
1108
  return;
936
1109
  } else {
@@ -939,27 +1112,29 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
939
1112
  cancelled before any ops are passed down (e.g., if the deadline
940
1113
  is in the past when the call starts), we can return the right
941
1114
  error to the caller when the first op does get passed down. */
942
- calld->cancel_error = GRPC_ERROR_REF(op->cancel_error);
1115
+ calld->cancel_error =
1116
+ GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error);
943
1117
  switch (calld->creation_phase) {
944
1118
  case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
945
- fail_locked(exec_ctx, calld, GRPC_ERROR_REF(op->cancel_error));
1119
+ fail_locked(exec_ctx, calld,
1120
+ GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error));
946
1121
  break;
947
1122
  case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
948
- pick_subchannel_locked(exec_ctx, elem, NULL, 0,
949
- &calld->connected_subchannel, NULL,
950
- GRPC_ERROR_REF(op->cancel_error));
1123
+ pick_subchannel_locked(
1124
+ exec_ctx, elem, NULL, 0, &calld->connected_subchannel, NULL,
1125
+ GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error));
951
1126
  break;
952
1127
  }
953
- grpc_transport_stream_op_finish_with_failure(
954
- exec_ctx, op, GRPC_ERROR_REF(op->cancel_error));
1128
+ grpc_transport_stream_op_batch_finish_with_failure(
1129
+ exec_ctx, op,
1130
+ GRPC_ERROR_REF(op->payload->cancel_stream.cancel_error));
955
1131
  /* early out */
956
1132
  return;
957
1133
  }
958
1134
  }
959
1135
  /* if we don't have a subchannel, try to get one */
960
1136
  if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
961
- calld->connected_subchannel == NULL &&
962
- op->send_initial_metadata != NULL) {
1137
+ calld->connected_subchannel == NULL && op->send_initial_metadata) {
963
1138
  calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
964
1139
  grpc_closure_init(&calld->next_step, subchannel_ready_locked, elem,
965
1140
  grpc_combiner_scheduler(chand->combiner, true));
@@ -967,10 +1142,11 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
967
1142
  /* If a subchannel is not available immediately, the polling entity from
968
1143
  call_data should be provided to channel_data's interested_parties, so
969
1144
  that IO of the lb_policy and resolver could be done under it. */
970
- if (pick_subchannel_locked(exec_ctx, elem, op->send_initial_metadata,
971
- op->send_initial_metadata_flags,
972
- &calld->connected_subchannel, &calld->next_step,
973
- GRPC_ERROR_NONE)) {
1145
+ if (pick_subchannel_locked(
1146
+ exec_ctx, elem,
1147
+ op->payload->send_initial_metadata.send_initial_metadata,
1148
+ op->payload->send_initial_metadata.send_initial_metadata_flags,
1149
+ &calld->connected_subchannel, &calld->next_step, GRPC_ERROR_NONE)) {
974
1150
  calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
975
1151
  GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel");
976
1152
  } else {
@@ -982,19 +1158,24 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
982
1158
  if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
983
1159
  calld->connected_subchannel != NULL) {
984
1160
  grpc_subchannel_call *subchannel_call = NULL;
1161
+ const grpc_connected_subchannel_call_args call_args = {
1162
+ .pollent = calld->pollent,
1163
+ .path = calld->path,
1164
+ .start_time = calld->call_start_time,
1165
+ .deadline = calld->deadline,
1166
+ .arena = calld->arena};
985
1167
  grpc_error *error = grpc_connected_subchannel_create_call(
986
- exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
987
- calld->call_start_time, calld->deadline, &subchannel_call);
1168
+ exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
1169
+ gpr_atm_rel_store(&calld->subchannel_call,
1170
+ (gpr_atm)(uintptr_t)subchannel_call);
988
1171
  if (error != GRPC_ERROR_NONE) {
989
- subchannel_call = CANCELLED_CALL;
990
1172
  fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
991
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
1173
+ grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
1174
+ } else {
1175
+ retry_waiting_locked(exec_ctx, calld);
1176
+ /* recurse to retry */
1177
+ start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
992
1178
  }
993
- gpr_atm_rel_store(&calld->subchannel_call,
994
- (gpr_atm)(uintptr_t)subchannel_call);
995
- retry_waiting_locked(exec_ctx, calld);
996
- /* recurse to retry */
997
- start_transport_stream_op_locked_inner(exec_ctx, op, elem);
998
1179
  /* early out */
999
1180
  return;
1000
1181
  }
@@ -1002,19 +1183,48 @@ static void start_transport_stream_op_locked_inner(grpc_exec_ctx *exec_ctx,
1002
1183
  add_waiting_locked(calld, op);
1003
1184
  }
1004
1185
 
1005
- static void start_transport_stream_op_locked(grpc_exec_ctx *exec_ctx, void *arg,
1006
- grpc_error *error_ignored) {
1007
- GPR_TIMER_BEGIN("start_transport_stream_op_locked", 0);
1186
+ static void on_complete(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
1187
+ grpc_call_element *elem = arg;
1188
+ call_data *calld = elem->call_data;
1189
+ if (calld->retry_throttle_data != NULL) {
1190
+ if (error == GRPC_ERROR_NONE) {
1191
+ grpc_server_retry_throttle_data_record_success(
1192
+ calld->retry_throttle_data);
1193
+ } else {
1194
+ // TODO(roth): In a subsequent PR, check the return value here and
1195
+ // decide whether or not to retry. Note that we should only
1196
+ // record failures whose statuses match the configured retryable
1197
+ // or non-fatal status codes.
1198
+ grpc_server_retry_throttle_data_record_failure(
1199
+ calld->retry_throttle_data);
1200
+ }
1201
+ }
1202
+ grpc_closure_run(exec_ctx, calld->original_on_complete,
1203
+ GRPC_ERROR_REF(error));
1204
+ }
1205
+
1206
+ static void start_transport_stream_op_batch_locked(grpc_exec_ctx *exec_ctx,
1207
+ void *arg,
1208
+ grpc_error *error_ignored) {
1209
+ GPR_TIMER_BEGIN("start_transport_stream_op_batch_locked", 0);
1008
1210
 
1009
- grpc_transport_stream_op *op = arg;
1010
- grpc_call_element *elem = op->handler_private.args[0];
1211
+ grpc_transport_stream_op_batch *op = arg;
1212
+ grpc_call_element *elem = op->handler_private.extra_arg;
1011
1213
  call_data *calld = elem->call_data;
1012
1214
 
1013
- start_transport_stream_op_locked_inner(exec_ctx, op, elem);
1215
+ if (op->recv_trailing_metadata) {
1216
+ GPR_ASSERT(op->on_complete != NULL);
1217
+ calld->original_on_complete = op->on_complete;
1218
+ grpc_closure_init(&calld->on_complete, on_complete, elem,
1219
+ grpc_schedule_on_exec_ctx);
1220
+ op->on_complete = &calld->on_complete;
1221
+ }
1222
+
1223
+ start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
1014
1224
 
1015
1225
  GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call,
1016
- "start_transport_stream_op");
1017
- GPR_TIMER_END("start_transport_stream_op_locked", 0);
1226
+ "start_transport_stream_op_batch");
1227
+ GPR_TIMER_END("start_transport_stream_op_batch_locked", 0);
1018
1228
  }
1019
1229
 
1020
1230
  /* The logic here is fairly complicated, due to (a) the fact that we
@@ -1025,149 +1235,55 @@ static void start_transport_stream_op_locked(grpc_exec_ctx *exec_ctx, void *arg,
1025
1235
  We use double-checked locking to initially see if initialization has been
1026
1236
  performed. If it has not, we acquire the combiner and perform initialization.
1027
1237
  If it has, we proceed on the fast path. */
1028
- static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
1029
- grpc_call_element *elem,
1030
- grpc_transport_stream_op *op) {
1238
+ static void cc_start_transport_stream_op_batch(
1239
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
1240
+ grpc_transport_stream_op_batch *op) {
1031
1241
  call_data *calld = elem->call_data;
1032
1242
  channel_data *chand = elem->channel_data;
1033
1243
  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
1034
- grpc_deadline_state_client_start_transport_stream_op(exec_ctx, elem, op);
1244
+ grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem,
1245
+ op);
1035
1246
  /* try to (atomically) get the call */
1036
1247
  grpc_subchannel_call *call = GET_CALL(calld);
1037
- GPR_TIMER_BEGIN("cc_start_transport_stream_op", 0);
1248
+ GPR_TIMER_BEGIN("cc_start_transport_stream_op_batch", 0);
1038
1249
  if (call == CANCELLED_CALL) {
1039
- grpc_transport_stream_op_finish_with_failure(
1250
+ grpc_transport_stream_op_batch_finish_with_failure(
1040
1251
  exec_ctx, op, GRPC_ERROR_REF(calld->cancel_error));
1041
- GPR_TIMER_END("cc_start_transport_stream_op", 0);
1252
+ GPR_TIMER_END("cc_start_transport_stream_op_batch", 0);
1042
1253
  /* early out */
1043
1254
  return;
1044
1255
  }
1045
1256
  if (call != NULL) {
1046
1257
  grpc_subchannel_call_process_op(exec_ctx, call, op);
1047
- GPR_TIMER_END("cc_start_transport_stream_op", 0);
1258
+ GPR_TIMER_END("cc_start_transport_stream_op_batch", 0);
1048
1259
  /* early out */
1049
1260
  return;
1050
1261
  }
1051
1262
  /* we failed; lock and figure out what to do */
1052
- GRPC_CALL_STACK_REF(calld->owning_call, "start_transport_stream_op");
1053
- op->handler_private.args[0] = elem;
1263
+ GRPC_CALL_STACK_REF(calld->owning_call, "start_transport_stream_op_batch");
1264
+ op->handler_private.extra_arg = elem;
1054
1265
  grpc_closure_sched(
1055
1266
  exec_ctx,
1056
1267
  grpc_closure_init(&op->handler_private.closure,
1057
- start_transport_stream_op_locked, op,
1268
+ start_transport_stream_op_batch_locked, op,
1058
1269
  grpc_combiner_scheduler(chand->combiner, false)),
1059
1270
  GRPC_ERROR_NONE);
1060
- GPR_TIMER_END("cc_start_transport_stream_op", 0);
1061
- }
1062
-
1063
- // Sets calld->method_params.
1064
- // If the method params specify a timeout, populates
1065
- // *per_method_deadline and returns true.
1066
- static bool set_call_method_params_from_service_config_locked(
1067
- grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
1068
- gpr_timespec *per_method_deadline) {
1069
- channel_data *chand = elem->channel_data;
1070
- call_data *calld = elem->call_data;
1071
- if (chand->method_params_table != NULL) {
1072
- calld->method_params = grpc_method_config_table_get(
1073
- exec_ctx, chand->method_params_table, calld->path);
1074
- if (calld->method_params != NULL) {
1075
- method_parameters_ref(calld->method_params);
1076
- if (gpr_time_cmp(calld->method_params->timeout,
1077
- gpr_time_0(GPR_TIMESPAN)) != 0) {
1078
- *per_method_deadline =
1079
- gpr_time_add(calld->call_start_time, calld->method_params->timeout);
1080
- return true;
1081
- }
1082
- }
1083
- }
1084
- return false;
1085
- }
1086
-
1087
- // Gets data from the service config. Invoked when the resolver returns
1088
- // its initial result.
1089
- static void read_service_config_locked(grpc_exec_ctx *exec_ctx, void *arg,
1090
- grpc_error *error) {
1091
- grpc_call_element *elem = arg;
1092
- call_data *calld = elem->call_data;
1093
- // If this is an error, there's no point in looking at the service config.
1094
- if (error == GRPC_ERROR_NONE) {
1095
- gpr_timespec per_method_deadline;
1096
- if (set_call_method_params_from_service_config_locked(
1097
- exec_ctx, elem, &per_method_deadline)) {
1098
- // If the deadline from the service config is shorter than the one
1099
- // from the client API, reset the deadline timer.
1100
- if (gpr_time_cmp(per_method_deadline, calld->deadline) < 0) {
1101
- calld->deadline = per_method_deadline;
1102
- grpc_deadline_state_reset(exec_ctx, elem, calld->deadline);
1103
- }
1104
- }
1105
- }
1106
- GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "read_service_config");
1107
- }
1108
-
1109
- static void initial_read_service_config_locked(grpc_exec_ctx *exec_ctx,
1110
- void *arg,
1111
- grpc_error *error_ignored) {
1112
- grpc_call_element *elem = arg;
1113
- channel_data *chand = elem->channel_data;
1114
- call_data *calld = elem->call_data;
1115
- // If the resolver has already returned results, then we can access
1116
- // the service config parameters immediately. Otherwise, we need to
1117
- // defer that work until the resolver returns an initial result.
1118
- if (chand->lb_policy != NULL) {
1119
- // We already have a resolver result, so check for service config.
1120
- gpr_timespec per_method_deadline;
1121
- if (set_call_method_params_from_service_config_locked(
1122
- exec_ctx, elem, &per_method_deadline)) {
1123
- calld->deadline = gpr_time_min(calld->deadline, per_method_deadline);
1124
- }
1125
- } else {
1126
- // We don't yet have a resolver result, so register a callback to
1127
- // get the service config data once the resolver returns.
1128
- // Take a reference to the call stack to be owned by the callback.
1129
- GRPC_CALL_STACK_REF(calld->owning_call, "read_service_config");
1130
- grpc_closure_init(&calld->read_service_config, read_service_config_locked,
1131
- elem, grpc_combiner_scheduler(chand->combiner, false));
1132
- grpc_closure_list_append(&chand->waiting_for_config_closures,
1133
- &calld->read_service_config, GRPC_ERROR_NONE);
1134
- }
1135
- // Start the deadline timer with the current deadline value. If we
1136
- // do not yet have service config data, then the timer may be reset
1137
- // later.
1138
- grpc_deadline_state_start(exec_ctx, elem, calld->deadline);
1139
- GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call,
1140
- "initial_read_service_config");
1271
+ GPR_TIMER_END("cc_start_transport_stream_op_batch", 0);
1141
1272
  }
1142
1273
 
1143
1274
  /* Constructor for call_data */
1144
1275
  static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
1145
1276
  grpc_call_element *elem,
1146
1277
  const grpc_call_element_args *args) {
1147
- channel_data *chand = elem->channel_data;
1148
1278
  call_data *calld = elem->call_data;
1149
1279
  // Initialize data members.
1150
1280
  grpc_deadline_state_init(exec_ctx, elem, args->call_stack);
1151
1281
  calld->path = grpc_slice_ref_internal(args->path);
1152
1282
  calld->call_start_time = args->start_time;
1153
1283
  calld->deadline = gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
1154
- calld->method_params = NULL;
1155
- calld->cancel_error = GRPC_ERROR_NONE;
1156
- gpr_atm_rel_store(&calld->subchannel_call, 0);
1157
- calld->connected_subchannel = NULL;
1158
- calld->waiting_ops = NULL;
1159
- calld->waiting_ops_count = 0;
1160
- calld->waiting_ops_capacity = 0;
1161
- calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
1162
1284
  calld->owning_call = args->call_stack;
1163
- calld->pollent = NULL;
1164
- GRPC_CALL_STACK_REF(calld->owning_call, "initial_read_service_config");
1165
- grpc_closure_sched(
1166
- exec_ctx,
1167
- grpc_closure_init(&calld->read_service_config,
1168
- initial_read_service_config_locked, elem,
1169
- grpc_combiner_scheduler(chand->combiner, false)),
1170
- GRPC_ERROR_NONE);
1285
+ calld->arena = args->arena;
1286
+ grpc_deadline_state_start(exec_ctx, elem, calld->deadline);
1171
1287
  return GRPC_ERROR_NONE;
1172
1288
  }
1173
1289
 
@@ -1175,7 +1291,7 @@ static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
1175
1291
  static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
1176
1292
  grpc_call_element *elem,
1177
1293
  const grpc_call_final_info *final_info,
1178
- void *and_free_memory) {
1294
+ grpc_closure *then_schedule_closure) {
1179
1295
  call_data *calld = elem->call_data;
1180
1296
  grpc_deadline_state_destroy(exec_ctx, elem);
1181
1297
  grpc_slice_unref_internal(exec_ctx, calld->path);
@@ -1185,6 +1301,8 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
1185
1301
  GRPC_ERROR_UNREF(calld->cancel_error);
1186
1302
  grpc_subchannel_call *call = GET_CALL(calld);
1187
1303
  if (call != NULL && call != CANCELLED_CALL) {
1304
+ grpc_subchannel_call_set_cleanup_closure(call, then_schedule_closure);
1305
+ then_schedule_closure = NULL;
1188
1306
  GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "client_channel_destroy_call");
1189
1307
  }
1190
1308
  GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
@@ -1194,7 +1312,7 @@ static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
1194
1312
  "picked");
1195
1313
  }
1196
1314
  gpr_free(calld->waiting_ops);
1197
- gpr_free(and_free_memory);
1315
+ grpc_closure_sched(exec_ctx, then_schedule_closure, GRPC_ERROR_NONE);
1198
1316
  }
1199
1317
 
1200
1318
  static void cc_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
@@ -1209,7 +1327,7 @@ static void cc_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
1209
1327
  */
1210
1328
 
1211
1329
  const grpc_channel_filter grpc_client_channel_filter = {
1212
- cc_start_transport_stream_op,
1330
+ cc_start_transport_stream_op_batch,
1213
1331
  cc_start_transport_op,
1214
1332
  sizeof(call_data),
1215
1333
  cc_init_call_elem,
@@ -1257,14 +1375,79 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
1257
1375
  return out;
1258
1376
  }
1259
1377
 
1260
- typedef struct {
1378
+ typedef struct external_connectivity_watcher {
1261
1379
  channel_data *chand;
1262
1380
  grpc_pollset *pollset;
1263
1381
  grpc_closure *on_complete;
1382
+ grpc_closure *watcher_timer_init;
1264
1383
  grpc_connectivity_state *state;
1265
1384
  grpc_closure my_closure;
1385
+ struct external_connectivity_watcher *next;
1266
1386
  } external_connectivity_watcher;
1267
1387
 
1388
+ static external_connectivity_watcher *lookup_external_connectivity_watcher(
1389
+ channel_data *chand, grpc_closure *on_complete) {
1390
+ gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
1391
+ external_connectivity_watcher *w =
1392
+ chand->external_connectivity_watcher_list_head;
1393
+ while (w != NULL && w->on_complete != on_complete) {
1394
+ w = w->next;
1395
+ }
1396
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
1397
+ return w;
1398
+ }
1399
+
1400
+ static void external_connectivity_watcher_list_append(
1401
+ channel_data *chand, external_connectivity_watcher *w) {
1402
+ GPR_ASSERT(!lookup_external_connectivity_watcher(chand, w->on_complete));
1403
+
1404
+ gpr_mu_lock(&w->chand->external_connectivity_watcher_list_mu);
1405
+ GPR_ASSERT(!w->next);
1406
+ w->next = chand->external_connectivity_watcher_list_head;
1407
+ chand->external_connectivity_watcher_list_head = w;
1408
+ gpr_mu_unlock(&w->chand->external_connectivity_watcher_list_mu);
1409
+ }
1410
+
1411
+ static void external_connectivity_watcher_list_remove(
1412
+ channel_data *chand, external_connectivity_watcher *too_remove) {
1413
+ GPR_ASSERT(
1414
+ lookup_external_connectivity_watcher(chand, too_remove->on_complete));
1415
+ gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
1416
+ if (too_remove == chand->external_connectivity_watcher_list_head) {
1417
+ chand->external_connectivity_watcher_list_head = too_remove->next;
1418
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
1419
+ return;
1420
+ }
1421
+ external_connectivity_watcher *w =
1422
+ chand->external_connectivity_watcher_list_head;
1423
+ while (w != NULL) {
1424
+ if (w->next == too_remove) {
1425
+ w->next = w->next->next;
1426
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
1427
+ return;
1428
+ }
1429
+ w = w->next;
1430
+ }
1431
+ GPR_UNREACHABLE_CODE(return );
1432
+ }
1433
+
1434
+ int grpc_client_channel_num_external_connectivity_watchers(
1435
+ grpc_channel_element *elem) {
1436
+ channel_data *chand = elem->channel_data;
1437
+ int count = 0;
1438
+
1439
+ gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
1440
+ external_connectivity_watcher *w =
1441
+ chand->external_connectivity_watcher_list_head;
1442
+ while (w != NULL) {
1443
+ count++;
1444
+ w = w->next;
1445
+ }
1446
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
1447
+
1448
+ return count;
1449
+ }
1450
+
1268
1451
  static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
1269
1452
  grpc_error *error) {
1270
1453
  external_connectivity_watcher *w = arg;
@@ -1273,6 +1456,7 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
1273
1456
  w->pollset);
1274
1457
  GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
1275
1458
  "external_connectivity_watcher");
1459
+ external_connectivity_watcher_list_remove(w->chand, w);
1276
1460
  gpr_free(w);
1277
1461
  grpc_closure_run(exec_ctx, follow_up, GRPC_ERROR_REF(error));
1278
1462
  }
@@ -1280,21 +1464,42 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
1280
1464
  static void watch_connectivity_state_locked(grpc_exec_ctx *exec_ctx, void *arg,
1281
1465
  grpc_error *error_ignored) {
1282
1466
  external_connectivity_watcher *w = arg;
1283
- grpc_closure_init(&w->my_closure, on_external_watch_complete, w,
1284
- grpc_schedule_on_exec_ctx);
1285
- grpc_connectivity_state_notify_on_state_change(
1286
- exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure);
1467
+ external_connectivity_watcher *found = NULL;
1468
+ if (w->state != NULL) {
1469
+ external_connectivity_watcher_list_append(w->chand, w);
1470
+ grpc_closure_run(exec_ctx, w->watcher_timer_init, GRPC_ERROR_NONE);
1471
+ grpc_closure_init(&w->my_closure, on_external_watch_complete, w,
1472
+ grpc_schedule_on_exec_ctx);
1473
+ grpc_connectivity_state_notify_on_state_change(
1474
+ exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure);
1475
+ } else {
1476
+ GPR_ASSERT(w->watcher_timer_init == NULL);
1477
+ found = lookup_external_connectivity_watcher(w->chand, w->on_complete);
1478
+ if (found) {
1479
+ GPR_ASSERT(found->on_complete == w->on_complete);
1480
+ grpc_connectivity_state_notify_on_state_change(
1481
+ exec_ctx, &found->chand->state_tracker, NULL, &found->my_closure);
1482
+ }
1483
+ grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties,
1484
+ w->pollset);
1485
+ GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
1486
+ "external_connectivity_watcher");
1487
+ gpr_free(w);
1488
+ }
1287
1489
  }
1288
1490
 
1289
1491
  void grpc_client_channel_watch_connectivity_state(
1290
1492
  grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
1291
- grpc_connectivity_state *state, grpc_closure *on_complete) {
1493
+ grpc_connectivity_state *state, grpc_closure *on_complete,
1494
+ grpc_closure *watcher_timer_init) {
1292
1495
  channel_data *chand = elem->channel_data;
1293
- external_connectivity_watcher *w = gpr_malloc(sizeof(*w));
1496
+ external_connectivity_watcher *w = gpr_zalloc(sizeof(*w));
1294
1497
  w->chand = chand;
1295
1498
  w->pollset = pollset;
1296
1499
  w->on_complete = on_complete;
1297
1500
  w->state = state;
1501
+ w->watcher_timer_init = watcher_timer_init;
1502
+
1298
1503
  grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset);
1299
1504
  GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
1300
1505
  "external_connectivity_watcher");