Merge github.com:grpc/grpc into census_suite

pull/4392/head
Craig Tiller 9 years ago
commit a75ae6ee8a
  1. 202
      Makefile
  2. 22
      build.yaml
  3. 8
      include/grpc/support/cmdline.h
  4. 17
      src/core/channel/channel_stack.c
  5. 41
      src/core/channel/channel_stack.h
  6. 152
      src/core/channel/client_channel.c
  7. 12
      src/core/channel/client_channel.h
  8. 80
      src/core/channel/client_uchannel.c
  9. 16
      src/core/channel/client_uchannel.h
  10. 3
      src/core/channel/compress_filter.c
  11. 6
      src/core/channel/connected_channel.c
  12. 3
      src/core/channel/http_server_filter.c
  13. 74
      src/core/channel/subchannel_call_holder.c
  14. 14
      src/core/channel/subchannel_call_holder.h
  15. 149
      src/core/client_config/lb_policies/pick_first.c
  16. 234
      src/core/client_config/lb_policies/round_robin.c
  17. 76
      src/core/client_config/lb_policy.c
  18. 35
      src/core/client_config/lb_policy.h
  19. 7
      src/core/client_config/resolver.c
  20. 10
      src/core/client_config/resolver.h
  21. 7
      src/core/client_config/resolvers/dns_resolver.c
  22. 13
      src/core/client_config/resolvers/sockaddr_resolver.c
  23. 7
      src/core/client_config/resolvers/zookeeper_resolver.c
  24. 692
      src/core/client_config/subchannel.c
  25. 83
      src/core/client_config/subchannel.h
  26. 7
      src/core/httpcli/httpcli.c
  27. 2
      src/core/httpcli/httpcli.h
  28. 6
      src/core/iomgr/fd_posix.c
  29. 1
      src/core/iomgr/fd_posix.h
  30. 6
      src/core/iomgr/pollset_set.h
  31. 51
      src/core/iomgr/pollset_set_posix.c
  32. 4
      src/core/iomgr/pollset_set_posix.h
  33. 8
      src/core/iomgr/pollset_set_windows.c
  34. 14
      src/core/security/credentials.c
  35. 60
      src/core/support/cmdline.c
  36. 30
      src/core/surface/call.c
  37. 45
      src/core/surface/channel.c
  38. 2
      src/core/surface/channel.h
  39. 33
      src/core/surface/channel_connectivity.c
  40. 1
      src/core/surface/channel_create.c
  41. 6
      src/core/surface/lame_client.c
  42. 1
      src/core/surface/secure_channel_create.c
  43. 4
      src/core/surface/server_chttp2.c
  44. 2
      src/core/transport/chttp2_transport.c
  45. 49
      src/core/transport/connectivity_state.c
  46. 11
      src/core/transport/connectivity_state.h
  47. 2
      src/core/transport/metadata.c
  48. 103
      src/core/transport/static_metadata.c
  49. 21
      src/core/transport/transport.c
  50. 17
      src/core/transport/transport.h
  51. 2
      src/php/bin/run_tests.sh
  52. 25
      test/core/channel/channel_stack_test.c
  53. 13
      test/core/client_config/lb_policies_test.c
  54. 66
      test/core/end2end/fixtures/h2_uchannel.c
  55. 2
      test/core/end2end/gen_build_yaml.py
  56. 2
      test/core/end2end/tests/binary_metadata.c
  57. 2
      test/core/end2end/tests/cancel_after_accept.c
  58. 2
      test/core/end2end/tests/cancel_after_client_done.c
  59. 2
      test/core/end2end/tests/cancel_after_invoke.c
  60. 2
      test/core/end2end/tests/cancel_before_invoke.c
  61. 2
      test/core/end2end/tests/cancel_in_a_vacuum.c
  62. 2
      test/core/end2end/tests/cancel_with_status.c
  63. 2
      test/core/end2end/tests/channel_connectivity.c
  64. 2
      test/core/end2end/tests/compressed_payload.c
  65. 2
      test/core/end2end/tests/empty_batch.c
  66. 2
      test/core/end2end/tests/graceful_server_shutdown.c
  67. 12
      test/core/end2end/tests/high_initial_seqno.c
  68. 8
      test/core/end2end/tests/hpack_size.c
  69. 2
      test/core/end2end/tests/invoke_large_request.c
  70. 2
      test/core/end2end/tests/large_metadata.c
  71. 2
      test/core/end2end/tests/max_concurrent_streams.c
  72. 2
      test/core/end2end/tests/max_message_length.c
  73. 2
      test/core/end2end/tests/metadata.c
  74. 2
      test/core/end2end/tests/negative_deadline.c
  75. 2
      test/core/end2end/tests/no_op.c
  76. 2
      test/core/end2end/tests/payload.c
  77. 2
      test/core/end2end/tests/ping_pong_streaming.c
  78. 2
      test/core/end2end/tests/registered_call.c
  79. 2
      test/core/end2end/tests/request_with_flags.c
  80. 2
      test/core/end2end/tests/request_with_payload.c
  81. 2
      test/core/end2end/tests/server_finishes_request.c
  82. 2
      test/core/end2end/tests/shutdown_finishes_calls.c
  83. 2
      test/core/end2end/tests/shutdown_finishes_tags.c
  84. 2
      test/core/end2end/tests/simple_request.c
  85. 2
      test/core/end2end/tests/trailing_metadata.c
  86. 16
      test/core/httpcli/httpcli_test.c
  87. 188
      test/core/httpcli/httpscli_test.c
  88. 14
      test/core/httpcli/test_server.py
  89. 2
      test/core/security/credentials_test.c
  90. 187
      test/core/support/cmdline_test.c
  91. 33
      test/core/surface/lame_client_test.c
  92. 49
      test/core/surface/server_chttp2_test.c
  93. 1
      tools/codegen/core/gen_legal_metadata_characters.c
  94. 24
      tools/run_tests/interop_html_report.template
  95. 25
      tools/run_tests/jobset.py
  96. 7
      tools/run_tests/report_utils.py
  97. 42
      tools/run_tests/run_interop_tests.py
  98. 6
      tools/run_tests/run_tests.py
  99. 144
      tools/run_tests/sources_and_headers.json
  100. 174
      tools/run_tests/tests.json
  101. Some files were not shown because too many files have changed in this diff Show More

@ -833,6 +833,7 @@ hpack_table_test: $(BINDIR)/$(CONFIG)/hpack_table_test
httpcli_format_request_test: $(BINDIR)/$(CONFIG)/httpcli_format_request_test httpcli_format_request_test: $(BINDIR)/$(CONFIG)/httpcli_format_request_test
httpcli_parser_test: $(BINDIR)/$(CONFIG)/httpcli_parser_test httpcli_parser_test: $(BINDIR)/$(CONFIG)/httpcli_parser_test
httpcli_test: $(BINDIR)/$(CONFIG)/httpcli_test httpcli_test: $(BINDIR)/$(CONFIG)/httpcli_test
httpscli_test: $(BINDIR)/$(CONFIG)/httpscli_test
init_test: $(BINDIR)/$(CONFIG)/init_test init_test: $(BINDIR)/$(CONFIG)/init_test
invalid_call_argument_test: $(BINDIR)/$(CONFIG)/invalid_call_argument_test invalid_call_argument_test: $(BINDIR)/$(CONFIG)/invalid_call_argument_test
json_rewrite: $(BINDIR)/$(CONFIG)/json_rewrite json_rewrite: $(BINDIR)/$(CONFIG)/json_rewrite
@ -847,6 +848,7 @@ murmur_hash_test: $(BINDIR)/$(CONFIG)/murmur_hash_test
no_server_test: $(BINDIR)/$(CONFIG)/no_server_test no_server_test: $(BINDIR)/$(CONFIG)/no_server_test
resolve_address_test: $(BINDIR)/$(CONFIG)/resolve_address_test resolve_address_test: $(BINDIR)/$(CONFIG)/resolve_address_test
secure_endpoint_test: $(BINDIR)/$(CONFIG)/secure_endpoint_test secure_endpoint_test: $(BINDIR)/$(CONFIG)/secure_endpoint_test
server_chttp2_test: $(BINDIR)/$(CONFIG)/server_chttp2_test
set_initial_connect_string_test: $(BINDIR)/$(CONFIG)/set_initial_connect_string_test set_initial_connect_string_test: $(BINDIR)/$(CONFIG)/set_initial_connect_string_test
sockaddr_utils_test: $(BINDIR)/$(CONFIG)/sockaddr_utils_test sockaddr_utils_test: $(BINDIR)/$(CONFIG)/sockaddr_utils_test
tcp_client_posix_test: $(BINDIR)/$(CONFIG)/tcp_client_posix_test tcp_client_posix_test: $(BINDIR)/$(CONFIG)/tcp_client_posix_test
@ -1349,10 +1351,7 @@ h2_uchannel_cancel_after_invoke_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_aft
h2_uchannel_cancel_before_invoke_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_test h2_uchannel_cancel_before_invoke_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_test
h2_uchannel_cancel_in_a_vacuum_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_test h2_uchannel_cancel_in_a_vacuum_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_test
h2_uchannel_cancel_with_status_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_test h2_uchannel_cancel_with_status_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_test
h2_uchannel_channel_connectivity_test: $(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_test
h2_uchannel_compressed_payload_test: $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_test h2_uchannel_compressed_payload_test: $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_test
h2_uchannel_default_host_test: $(BINDIR)/$(CONFIG)/h2_uchannel_default_host_test
h2_uchannel_disappearing_server_test: $(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_test
h2_uchannel_empty_batch_test: $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_test h2_uchannel_empty_batch_test: $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_test
h2_uchannel_graceful_server_shutdown_test: $(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_test h2_uchannel_graceful_server_shutdown_test: $(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_test
h2_uchannel_high_initial_seqno_test: $(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_test h2_uchannel_high_initial_seqno_test: $(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_test
@ -1372,7 +1371,6 @@ h2_uchannel_request_with_payload_test: $(BINDIR)/$(CONFIG)/h2_uchannel_request_w
h2_uchannel_server_finishes_request_test: $(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_test h2_uchannel_server_finishes_request_test: $(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_test
h2_uchannel_shutdown_finishes_calls_test: $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_test h2_uchannel_shutdown_finishes_calls_test: $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_test
h2_uchannel_shutdown_finishes_tags_test: $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_test h2_uchannel_shutdown_finishes_tags_test: $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_test
h2_uchannel_simple_delayed_request_test: $(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_test
h2_uchannel_simple_request_test: $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_test h2_uchannel_simple_request_test: $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_test
h2_uchannel_trailing_metadata_test: $(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_test h2_uchannel_trailing_metadata_test: $(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_test
h2_uds_bad_hostname_test: $(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_test h2_uds_bad_hostname_test: $(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_test
@ -1705,10 +1703,7 @@ h2_uchannel_cancel_after_invoke_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_canc
h2_uchannel_cancel_before_invoke_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_nosec_test h2_uchannel_cancel_before_invoke_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_nosec_test
h2_uchannel_cancel_in_a_vacuum_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_nosec_test h2_uchannel_cancel_in_a_vacuum_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_nosec_test
h2_uchannel_cancel_with_status_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_nosec_test h2_uchannel_cancel_with_status_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_nosec_test
h2_uchannel_channel_connectivity_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_nosec_test
h2_uchannel_compressed_payload_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test h2_uchannel_compressed_payload_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test
h2_uchannel_default_host_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_default_host_nosec_test
h2_uchannel_disappearing_server_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_nosec_test
h2_uchannel_empty_batch_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_nosec_test h2_uchannel_empty_batch_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_nosec_test
h2_uchannel_graceful_server_shutdown_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_nosec_test h2_uchannel_graceful_server_shutdown_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_nosec_test
h2_uchannel_high_initial_seqno_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_nosec_test h2_uchannel_high_initial_seqno_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_nosec_test
@ -1728,7 +1723,6 @@ h2_uchannel_request_with_payload_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_req
h2_uchannel_server_finishes_request_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_nosec_test h2_uchannel_server_finishes_request_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_nosec_test
h2_uchannel_shutdown_finishes_calls_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_nosec_test h2_uchannel_shutdown_finishes_calls_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_nosec_test
h2_uchannel_shutdown_finishes_tags_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_nosec_test h2_uchannel_shutdown_finishes_tags_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_nosec_test
h2_uchannel_simple_delayed_request_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_nosec_test
h2_uchannel_simple_request_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_nosec_test h2_uchannel_simple_request_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_nosec_test
h2_uchannel_trailing_metadata_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_nosec_test h2_uchannel_trailing_metadata_nosec_test: $(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_nosec_test
h2_uds_bad_hostname_nosec_test: $(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_nosec_test h2_uds_bad_hostname_nosec_test: $(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_nosec_test
@ -1977,6 +1971,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/httpcli_format_request_test \ $(BINDIR)/$(CONFIG)/httpcli_format_request_test \
$(BINDIR)/$(CONFIG)/httpcli_parser_test \ $(BINDIR)/$(CONFIG)/httpcli_parser_test \
$(BINDIR)/$(CONFIG)/httpcli_test \ $(BINDIR)/$(CONFIG)/httpcli_test \
$(BINDIR)/$(CONFIG)/httpscli_test \
$(BINDIR)/$(CONFIG)/init_test \ $(BINDIR)/$(CONFIG)/init_test \
$(BINDIR)/$(CONFIG)/invalid_call_argument_test \ $(BINDIR)/$(CONFIG)/invalid_call_argument_test \
$(BINDIR)/$(CONFIG)/json_rewrite \ $(BINDIR)/$(CONFIG)/json_rewrite \
@ -1990,6 +1985,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/no_server_test \ $(BINDIR)/$(CONFIG)/no_server_test \
$(BINDIR)/$(CONFIG)/resolve_address_test \ $(BINDIR)/$(CONFIG)/resolve_address_test \
$(BINDIR)/$(CONFIG)/secure_endpoint_test \ $(BINDIR)/$(CONFIG)/secure_endpoint_test \
$(BINDIR)/$(CONFIG)/server_chttp2_test \
$(BINDIR)/$(CONFIG)/set_initial_connect_string_test \ $(BINDIR)/$(CONFIG)/set_initial_connect_string_test \
$(BINDIR)/$(CONFIG)/sockaddr_utils_test \ $(BINDIR)/$(CONFIG)/sockaddr_utils_test \
$(BINDIR)/$(CONFIG)/tcp_client_posix_test \ $(BINDIR)/$(CONFIG)/tcp_client_posix_test \
@ -2447,10 +2443,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_default_host_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_test \
@ -2470,7 +2463,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_test \
$(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_test \ $(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_test \
@ -2803,10 +2795,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_before_invoke_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_default_host_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_graceful_server_shutdown_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_high_initial_seqno_nosec_test \
@ -2826,7 +2815,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_server_finishes_request_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uchannel_trailing_metadata_nosec_test \
$(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_nosec_test \ $(BINDIR)/$(CONFIG)/h2_uds_bad_hostname_nosec_test \
@ -3052,6 +3040,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/httpcli_parser_test || ( echo test httpcli_parser_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/httpcli_parser_test || ( echo test httpcli_parser_test failed ; exit 1 )
$(E) "[RUN] Testing httpcli_test" $(E) "[RUN] Testing httpcli_test"
$(Q) $(BINDIR)/$(CONFIG)/httpcli_test || ( echo test httpcli_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/httpcli_test || ( echo test httpcli_test failed ; exit 1 )
$(E) "[RUN] Testing httpscli_test"
$(Q) $(BINDIR)/$(CONFIG)/httpscli_test || ( echo test httpscli_test failed ; exit 1 )
$(E) "[RUN] Testing init_test" $(E) "[RUN] Testing init_test"
$(Q) $(BINDIR)/$(CONFIG)/init_test || ( echo test init_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/init_test || ( echo test init_test failed ; exit 1 )
$(E) "[RUN] Testing invalid_call_argument_test" $(E) "[RUN] Testing invalid_call_argument_test"
@ -3076,6 +3066,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/resolve_address_test || ( echo test resolve_address_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/resolve_address_test || ( echo test resolve_address_test failed ; exit 1 )
$(E) "[RUN] Testing secure_endpoint_test" $(E) "[RUN] Testing secure_endpoint_test"
$(Q) $(BINDIR)/$(CONFIG)/secure_endpoint_test || ( echo test secure_endpoint_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/secure_endpoint_test || ( echo test secure_endpoint_test failed ; exit 1 )
$(E) "[RUN] Testing server_chttp2_test"
$(Q) $(BINDIR)/$(CONFIG)/server_chttp2_test || ( echo test server_chttp2_test failed ; exit 1 )
$(E) "[RUN] Testing set_initial_connect_string_test" $(E) "[RUN] Testing set_initial_connect_string_test"
$(Q) $(BINDIR)/$(CONFIG)/set_initial_connect_string_test || ( echo test set_initial_connect_string_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/set_initial_connect_string_test || ( echo test set_initial_connect_string_test failed ; exit 1 )
$(E) "[RUN] Testing sockaddr_utils_test" $(E) "[RUN] Testing sockaddr_utils_test"
@ -3990,14 +3982,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_test || ( echo test h2_uchannel_cancel_in_a_vacuum_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_test || ( echo test h2_uchannel_cancel_in_a_vacuum_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_cancel_with_status_test" $(E) "[RUN] Testing h2_uchannel_cancel_with_status_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_test || ( echo test h2_uchannel_cancel_with_status_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_test || ( echo test h2_uchannel_cancel_with_status_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_channel_connectivity_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_test || ( echo test h2_uchannel_channel_connectivity_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_compressed_payload_test" $(E) "[RUN] Testing h2_uchannel_compressed_payload_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_test || ( echo test h2_uchannel_compressed_payload_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_test || ( echo test h2_uchannel_compressed_payload_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_default_host_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_default_host_test || ( echo test h2_uchannel_default_host_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_disappearing_server_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_test || ( echo test h2_uchannel_disappearing_server_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_empty_batch_test" $(E) "[RUN] Testing h2_uchannel_empty_batch_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_test || ( echo test h2_uchannel_empty_batch_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_test || ( echo test h2_uchannel_empty_batch_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_graceful_server_shutdown_test" $(E) "[RUN] Testing h2_uchannel_graceful_server_shutdown_test"
@ -4036,8 +4022,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_test || ( echo test h2_uchannel_shutdown_finishes_calls_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_test || ( echo test h2_uchannel_shutdown_finishes_calls_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_shutdown_finishes_tags_test" $(E) "[RUN] Testing h2_uchannel_shutdown_finishes_tags_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_test || ( echo test h2_uchannel_shutdown_finishes_tags_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_test || ( echo test h2_uchannel_shutdown_finishes_tags_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_simple_delayed_request_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_test || ( echo test h2_uchannel_simple_delayed_request_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_simple_request_test" $(E) "[RUN] Testing h2_uchannel_simple_request_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_test || ( echo test h2_uchannel_simple_request_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_test || ( echo test h2_uchannel_simple_request_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_trailing_metadata_test" $(E) "[RUN] Testing h2_uchannel_trailing_metadata_test"
@ -4702,14 +4686,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_nosec_test || ( echo test h2_uchannel_cancel_in_a_vacuum_nosec_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_in_a_vacuum_nosec_test || ( echo test h2_uchannel_cancel_in_a_vacuum_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_cancel_with_status_nosec_test" $(E) "[RUN] Testing h2_uchannel_cancel_with_status_nosec_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_nosec_test || ( echo test h2_uchannel_cancel_with_status_nosec_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_nosec_test || ( echo test h2_uchannel_cancel_with_status_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_channel_connectivity_nosec_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_nosec_test || ( echo test h2_uchannel_channel_connectivity_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_compressed_payload_nosec_test" $(E) "[RUN] Testing h2_uchannel_compressed_payload_nosec_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test || ( echo test h2_uchannel_compressed_payload_nosec_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test || ( echo test h2_uchannel_compressed_payload_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_default_host_nosec_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_default_host_nosec_test || ( echo test h2_uchannel_default_host_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_disappearing_server_nosec_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_nosec_test || ( echo test h2_uchannel_disappearing_server_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_empty_batch_nosec_test" $(E) "[RUN] Testing h2_uchannel_empty_batch_nosec_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_nosec_test || ( echo test h2_uchannel_empty_batch_nosec_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_nosec_test || ( echo test h2_uchannel_empty_batch_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_graceful_server_shutdown_nosec_test" $(E) "[RUN] Testing h2_uchannel_graceful_server_shutdown_nosec_test"
@ -4748,8 +4726,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_nosec_test || ( echo test h2_uchannel_shutdown_finishes_calls_nosec_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_calls_nosec_test || ( echo test h2_uchannel_shutdown_finishes_calls_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_shutdown_finishes_tags_nosec_test" $(E) "[RUN] Testing h2_uchannel_shutdown_finishes_tags_nosec_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_nosec_test || ( echo test h2_uchannel_shutdown_finishes_tags_nosec_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_nosec_test || ( echo test h2_uchannel_shutdown_finishes_tags_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_simple_delayed_request_nosec_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_nosec_test || ( echo test h2_uchannel_simple_delayed_request_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_simple_request_nosec_test" $(E) "[RUN] Testing h2_uchannel_simple_request_nosec_test"
$(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_nosec_test || ( echo test h2_uchannel_simple_request_nosec_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_nosec_test || ( echo test h2_uchannel_simple_request_nosec_test failed ; exit 1 )
$(E) "[RUN] Testing h2_uchannel_trailing_metadata_nosec_test" $(E) "[RUN] Testing h2_uchannel_trailing_metadata_nosec_test"
@ -11006,6 +10982,35 @@ endif
endif endif
HTTPSCLI_TEST_SRC = \
test/core/httpcli/httpscli_test.c \
HTTPSCLI_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HTTPSCLI_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/httpscli_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/httpscli_test: $(HTTPSCLI_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(HTTPSCLI_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/httpscli_test
endif
$(OBJDIR)/$(CONFIG)/test/core/httpcli/httpscli_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_httpscli_test: $(HTTPSCLI_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(HTTPSCLI_TEST_OBJS:.o=.dep)
endif
endif
INIT_TEST_SRC = \ INIT_TEST_SRC = \
test/core/surface/init_test.c \ test/core/surface/init_test.c \
@ -11412,6 +11417,35 @@ endif
endif endif
SERVER_CHTTP2_TEST_SRC = \
test/core/surface/server_chttp2_test.c \
SERVER_CHTTP2_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SERVER_CHTTP2_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/server_chttp2_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/server_chttp2_test: $(SERVER_CHTTP2_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(SERVER_CHTTP2_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/server_chttp2_test
endif
$(OBJDIR)/$(CONFIG)/test/core/surface/server_chttp2_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_server_chttp2_test: $(SERVER_CHTTP2_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(SERVER_CHTTP2_TEST_OBJS:.o=.dep)
endif
endif
SET_INITIAL_CONNECT_STRING_TEST_SRC = \ SET_INITIAL_CONNECT_STRING_TEST_SRC = \
test/core/client_config/set_initial_connect_string_test.c \ test/core/client_config/set_initial_connect_string_test.c \
@ -21567,24 +21601,6 @@ endif
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_test: $(LIBDIR)/$(CONFIG)/libend2end_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_test_channel_connectivity.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LIBDIR)/$(CONFIG)/libend2end_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_test_channel_connectivity.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_test
endif
ifeq ($(NO_SECURE),true) ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL. # You can't build secure targets if you don't have OpenSSL.
@ -21603,42 +21619,6 @@ endif
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/h2_uchannel_default_host_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/h2_uchannel_default_host_test: $(LIBDIR)/$(CONFIG)/libend2end_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_test_default_host.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LIBDIR)/$(CONFIG)/libend2end_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_test_default_host.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/h2_uchannel_default_host_test
endif
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_test: $(LIBDIR)/$(CONFIG)/libend2end_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LIBDIR)/$(CONFIG)/libend2end_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_test
endif
ifeq ($(NO_SECURE),true) ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL. # You can't build secure targets if you don't have OpenSSL.
@ -21981,24 +21961,6 @@ endif
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_test: $(LIBDIR)/$(CONFIG)/libend2end_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LIBDIR)/$(CONFIG)/libend2end_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_test
endif
ifeq ($(NO_SECURE),true) ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL. # You can't build secure targets if you don't have OpenSSL.
@ -25355,14 +25317,6 @@ $(BINDIR)/$(CONFIG)/h2_uchannel_cancel_with_status_nosec_test: $(LIBDIR)/$(CONF
$(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_channel_connectivity.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_channel_connectivity.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/h2_uchannel_channel_connectivity_nosec_test
$(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_compressed_payload.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@" $(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -25371,22 +25325,6 @@ $(BINDIR)/$(CONFIG)/h2_uchannel_compressed_payload_nosec_test: $(LIBDIR)/$(CONF
$(BINDIR)/$(CONFIG)/h2_uchannel_default_host_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_default_host.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_default_host.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/h2_uchannel_default_host_nosec_test
$(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/h2_uchannel_disappearing_server_nosec_test
$(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(BINDIR)/$(CONFIG)/h2_uchannel_empty_batch_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@" $(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -25539,14 +25477,6 @@ $(BINDIR)/$(CONFIG)/h2_uchannel_shutdown_finishes_tags_nosec_test: $(LIBDIR)/$(
$(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/h2_uchannel_simple_delayed_request_nosec_test
$(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_simple_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(BINDIR)/$(CONFIG)/h2_uchannel_simple_request_nosec_test: $(LIBDIR)/$(CONFIG)/libend2end_nosec_fixture_h2_uchannel.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_test_simple_request.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@" $(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`

@ -1357,6 +1357,18 @@ targets:
- mac - mac
- linux - linux
- posix - posix
- name: httpscli_test
build: test
language: c
src:
- test/core/httpcli/httpscli_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
platforms:
- linux
- name: init_test - name: init_test
build: test build: test
language: c language: c
@ -1498,6 +1510,16 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: server_chttp2_test
build: test
language: c
src:
- test/core/surface/server_chttp2_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: set_initial_connect_string_test - name: set_initial_connect_string_test
build: test build: test
language: c language: c

@ -83,8 +83,12 @@ void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help,
void gpr_cmdline_on_extra_arg( void gpr_cmdline_on_extra_arg(
gpr_cmdline *cl, const char *name, const char *help, gpr_cmdline *cl, const char *name, const char *help,
void (*on_extra_arg)(void *user_data, const char *arg), void *user_data); void (*on_extra_arg)(void *user_data, const char *arg), void *user_data);
/* Parse the command line */ /* Enable surviving failure: default behavior is to exit the process */
void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv); void gpr_cmdline_set_survive_failure(gpr_cmdline *cl);
/* Parse the command line; returns 1 on success, on failure either dies
(by default) or returns 0 if gpr_cmdline_set_survive_failure() has been
called */
int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv);
/* Destroy the parser */ /* Destroy the parser */
void gpr_cmdline_destroy(gpr_cmdline *cl); void gpr_cmdline_destroy(gpr_cmdline *cl);
/* Get a string describing usage */ /* Get a string describing usage */

@ -101,11 +101,12 @@ grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack,
return CALL_ELEMS_FROM_STACK(call_stack) + index; return CALL_ELEMS_FROM_STACK(call_stack) + index;
} }
void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
grpc_iomgr_cb_func destroy, void *destroy_arg,
const grpc_channel_filter **filters, const grpc_channel_filter **filters,
size_t filter_count, grpc_channel *master, size_t filter_count,
const grpc_channel_args *channel_args, const grpc_channel_args *channel_args,
grpc_channel_stack *stack) { const char *name, grpc_channel_stack *stack) {
size_t call_size = size_t call_size =
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) + ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element)); ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element));
@ -115,6 +116,8 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
size_t i; size_t i;
stack->count = filter_count; stack->count = filter_count;
GRPC_STREAM_REF_INIT(&stack->refcount, initial_refs, destroy, destroy_arg,
name);
elems = CHANNEL_ELEMS_FROM_STACK(stack); elems = CHANNEL_ELEMS_FROM_STACK(stack);
user_data = user_data =
((char *)elems) + ((char *)elems) +
@ -122,7 +125,7 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
/* init per-filter data */ /* init per-filter data */
for (i = 0; i < filter_count; i++) { for (i = 0; i < filter_count; i++) {
args.master = master; args.channel_stack = stack;
args.channel_args = channel_args; args.channel_args = channel_args;
args.is_first = i == 0; args.is_first = i == 0;
args.is_last = i == (filter_count - 1); args.is_last = i == (filter_count - 1);
@ -166,15 +169,15 @@ void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
size_t i; size_t i;
call_stack->count = count; call_stack->count = count;
gpr_ref_init(&call_stack->refcount.refs, initial_refs); GRPC_STREAM_REF_INIT(&call_stack->refcount, initial_refs, destroy,
grpc_closure_init(&call_stack->refcount.destroy, destroy, destroy_arg); destroy_arg, "CALL_STACK");
call_elems = CALL_ELEMS_FROM_STACK(call_stack); call_elems = CALL_ELEMS_FROM_STACK(call_stack);
user_data = ((char *)call_elems) + user_data = ((char *)call_elems) +
ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element)); ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
/* init per-filter data */ /* init per-filter data */
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
args.refcount = &call_stack->refcount; args.call_stack = call_stack;
args.server_transport_data = transport_server_data; args.server_transport_data = transport_server_data;
args.context = context; args.context = context;
call_elems[i].filter = channel_elems[i].filter; call_elems[i].filter = channel_elems[i].filter;

@ -51,15 +51,18 @@
typedef struct grpc_channel_element grpc_channel_element; typedef struct grpc_channel_element grpc_channel_element;
typedef struct grpc_call_element grpc_call_element; typedef struct grpc_call_element grpc_call_element;
typedef struct grpc_channel_stack grpc_channel_stack;
typedef struct grpc_call_stack grpc_call_stack;
typedef struct { typedef struct {
grpc_channel *master; grpc_channel_stack *channel_stack;
const grpc_channel_args *channel_args; const grpc_channel_args *channel_args;
int is_first; int is_first;
int is_last; int is_last;
} grpc_channel_element_args; } grpc_channel_element_args;
typedef struct { typedef struct {
grpc_stream_refcount *refcount; grpc_call_stack *call_stack;
const void *server_transport_data; const void *server_transport_data;
grpc_call_context_element *context; grpc_call_context_element *context;
} grpc_call_element_args; } grpc_call_element_args;
@ -144,23 +147,24 @@ struct grpc_call_element {
/* A channel stack tracks a set of related filters for one channel, and /* A channel stack tracks a set of related filters for one channel, and
guarantees they live within a single malloc() allocation */ guarantees they live within a single malloc() allocation */
typedef struct { struct grpc_channel_stack {
grpc_stream_refcount refcount;
size_t count; size_t count;
/* Memory required for a call stack (computed at channel stack /* Memory required for a call stack (computed at channel stack
initialization) */ initialization) */
size_t call_stack_size; size_t call_stack_size;
} grpc_channel_stack; };
/* A call stack tracks a set of related filters for one call, and guarantees /* A call stack tracks a set of related filters for one call, and guarantees
they live within a single malloc() allocation */ they live within a single malloc() allocation */
typedef struct { struct grpc_call_stack {
/* shared refcount for this channel stack. /* shared refcount for this channel stack.
MUST be the first element: the underlying code calls destroy MUST be the first element: the underlying code calls destroy
with the address of the refcount, but higher layers prefer to think with the address of the refcount, but higher layers prefer to think
about the address of the call stack itself. */ about the address of the call stack itself. */
grpc_stream_refcount refcount; grpc_stream_refcount refcount;
size_t count; size_t count;
} grpc_call_stack; };
/* Get a channel element given a channel stack and its index */ /* Get a channel element given a channel stack and its index */
grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack, grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack,
@ -175,11 +179,11 @@ grpc_call_element *grpc_call_stack_element(grpc_call_stack *stack, size_t i);
size_t grpc_channel_stack_size(const grpc_channel_filter **filters, size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
size_t filter_count); size_t filter_count);
/* Initialize a channel stack given some filters */ /* Initialize a channel stack given some filters */
void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
grpc_iomgr_cb_func destroy, void *destroy_arg,
const grpc_channel_filter **filters, const grpc_channel_filter **filters,
size_t filter_count, grpc_channel *master, size_t filter_count, const grpc_channel_args *args,
const grpc_channel_args *args, const char *name, grpc_channel_stack *stack);
grpc_channel_stack *stack);
/* Destroy a channel stack */ /* Destroy a channel stack */
void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx, void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
grpc_channel_stack *stack); grpc_channel_stack *stack);
@ -199,14 +203,23 @@ void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset); grpc_pollset *pollset);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG
#define grpc_call_stack_ref(call_stack, reason) \ #define GRPC_CALL_STACK_REF(call_stack, reason) \
grpc_stream_ref(&(call_stack)->refcount, reason) grpc_stream_ref(&(call_stack)->refcount, reason)
#define grpc_call_stack_unref(exec_ctx, call_stack, reason) \ #define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \
grpc_stream_unref(exec_ctx, &(call_stack)->refcount, reason) grpc_stream_unref(exec_ctx, &(call_stack)->refcount, reason)
#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \
grpc_stream_ref(&(channel_stack)->refcount, reason)
#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \
grpc_stream_unref(exec_ctx, &(channel_stack)->refcount, reason)
#else #else
#define grpc_call_stack_ref(call_stack) grpc_stream_ref(&(call_stack)->refcount) #define GRPC_CALL_STACK_REF(call_stack, reason) \
#define grpc_call_stack_unref(exec_ctx, call_stack) \ grpc_stream_ref(&(call_stack)->refcount)
#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \
grpc_stream_unref(exec_ctx, &(call_stack)->refcount) grpc_stream_unref(exec_ctx, &(call_stack)->refcount)
#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \
grpc_stream_ref(&(channel_stack)->refcount)
#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \
grpc_stream_unref(exec_ctx, &(channel_stack)->refcount)
#endif #endif
/* Destroy a call stack */ /* Destroy a call stack */

@ -59,11 +59,6 @@ typedef struct client_channel_channel_data {
grpc_resolver *resolver; grpc_resolver *resolver;
/** have we started resolving this channel */ /** have we started resolving this channel */
int started_resolving; int started_resolving;
/** master channel - the grpc_channel instance that ultimately owns
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
to keep ourselves alive through an asynchronous operation. */
grpc_channel *master;
/** mutex protecting client configuration, including all /** mutex protecting client configuration, including all
variables below in this data structure */ variables below in this data structure */
@ -81,8 +76,10 @@ typedef struct client_channel_channel_data {
grpc_connectivity_state_tracker state_tracker; grpc_connectivity_state_tracker state_tracker;
/** when an lb_policy arrives, should we try to exit idle */ /** when an lb_policy arrives, should we try to exit idle */
int exit_idle_when_lb_policy_arrives; int exit_idle_when_lb_policy_arrives;
/** pollset_set of interested parties in a new connection */ /** owning stack */
grpc_pollset_set pollset_set; grpc_channel_stack *owning_stack;
/** interested parties */
grpc_pollset_set interested_parties;
} channel_data; } channel_data;
/** We create one watcher for each new lb_policy that is returned from a /** We create one watcher for each new lb_policy that is returned from a
@ -103,9 +100,7 @@ typedef struct {
} waiting_call; } waiting_call;
static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
channel_data *chand = elem->channel_data; return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data);
return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data,
chand->master);
} }
static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx, static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
@ -121,10 +116,18 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
static void on_lb_policy_state_changed_locked( static void on_lb_policy_state_changed_locked(
grpc_exec_ctx *exec_ctx, lb_policy_connectivity_watcher *w) { grpc_exec_ctx *exec_ctx, lb_policy_connectivity_watcher *w) {
grpc_connectivity_state publish_state = w->state;
/* check if the notification is for a stale policy */ /* check if the notification is for a stale policy */
if (w->lb_policy != w->chand->lb_policy) return; if (w->lb_policy != w->chand->lb_policy) return;
grpc_connectivity_state_set(exec_ctx, &w->chand->state_tracker, w->state, if (publish_state == GRPC_CHANNEL_FATAL_FAILURE &&
w->chand->resolver != NULL) {
publish_state = GRPC_CHANNEL_TRANSIENT_FAILURE;
grpc_resolver_channel_saw_error(exec_ctx, w->chand->resolver);
GRPC_LB_POLICY_UNREF(exec_ctx, w->chand->lb_policy, "channel");
w->chand->lb_policy = NULL;
}
grpc_connectivity_state_set(exec_ctx, &w->chand->state_tracker, publish_state,
"lb_changed"); "lb_changed");
if (w->state != GRPC_CHANNEL_FATAL_FAILURE) { if (w->state != GRPC_CHANNEL_FATAL_FAILURE) {
watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state); watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state);
@ -139,7 +142,7 @@ static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg,
on_lb_policy_state_changed_locked(exec_ctx, w); on_lb_policy_state_changed_locked(exec_ctx, w);
gpr_mu_unlock(&w->chand->mu_config); gpr_mu_unlock(&w->chand->mu_config);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->chand->master, "watch_lb_policy"); GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy");
gpr_free(w); gpr_free(w);
} }
@ -147,7 +150,7 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
grpc_lb_policy *lb_policy, grpc_lb_policy *lb_policy,
grpc_connectivity_state current_state) { grpc_connectivity_state current_state) {
lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w)); lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w));
GRPC_CHANNEL_INTERNAL_REF(chand->master, "watch_lb_policy"); GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy");
w->chand = chand; w->chand = chand;
grpc_closure_init(&w->on_changed, on_lb_policy_state_changed, w); grpc_closure_init(&w->on_changed, on_lb_policy_state_changed, w);
@ -179,6 +182,11 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
chand->incoming_configuration = NULL; chand->incoming_configuration = NULL;
if (lb_policy != NULL) {
grpc_pollset_set_add_pollset_set(exec_ctx, &lb_policy->interested_parties,
&chand->interested_parties);
}
gpr_mu_lock(&chand->mu_config); gpr_mu_lock(&chand->mu_config);
old_lb_policy = chand->lb_policy; old_lb_policy = chand->lb_policy;
chand->lb_policy = lb_policy; chand->lb_policy = lb_policy;
@ -200,7 +208,7 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
watch_lb_policy(exec_ctx, chand, lb_policy, state); watch_lb_policy(exec_ctx, chand, lb_policy, state);
} }
gpr_mu_unlock(&chand->mu_config); gpr_mu_unlock(&chand->mu_config);
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration, grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration,
&chand->on_config_changed); &chand->on_config_changed);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "channel-next"); GRPC_RESOLVER_UNREF(exec_ctx, resolver, "channel-next");
@ -222,7 +230,9 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
} }
if (old_lb_policy != NULL) { if (old_lb_policy != NULL) {
grpc_lb_policy_shutdown(exec_ctx, old_lb_policy); grpc_pollset_set_del_pollset_set(exec_ctx,
&old_lb_policy->interested_parties,
&chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel"); GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel");
} }
@ -230,13 +240,12 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change"); GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change");
} }
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->master, "resolver"); GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver");
} }
static void cc_start_transport_op(grpc_exec_ctx *exec_ctx, static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem, grpc_channel_element *elem,
grpc_transport_op *op) { grpc_transport_op *op) {
grpc_lb_policy *lb_policy = NULL;
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
grpc_resolver *destroy_resolver = NULL; grpc_resolver *destroy_resolver = NULL;
@ -254,18 +263,15 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
op->connectivity_state = NULL; op->connectivity_state = NULL;
} }
lb_policy = chand->lb_policy;
if (lb_policy) {
GRPC_LB_POLICY_REF(lb_policy, "broadcast");
}
if (op->disconnect && chand->resolver != NULL) { if (op->disconnect && chand->resolver != NULL) {
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE, "disconnect"); GRPC_CHANNEL_FATAL_FAILURE, "disconnect");
destroy_resolver = chand->resolver; destroy_resolver = chand->resolver;
chand->resolver = NULL; chand->resolver = NULL;
if (chand->lb_policy != NULL) { if (chand->lb_policy != NULL) {
grpc_lb_policy_shutdown(exec_ctx, chand->lb_policy); grpc_pollset_set_del_pollset_set(exec_ctx,
&chand->lb_policy->interested_parties,
&chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
chand->lb_policy = NULL; chand->lb_policy = NULL;
} }
@ -276,16 +282,11 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_resolver_shutdown(exec_ctx, destroy_resolver); grpc_resolver_shutdown(exec_ctx, destroy_resolver);
GRPC_RESOLVER_UNREF(exec_ctx, destroy_resolver, "channel"); GRPC_RESOLVER_UNREF(exec_ctx, destroy_resolver, "channel");
} }
if (lb_policy) {
grpc_lb_policy_broadcast(exec_ctx, lb_policy, op);
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "broadcast");
}
} }
typedef struct { typedef struct {
grpc_metadata_batch *initial_metadata; grpc_metadata_batch *initial_metadata;
grpc_subchannel **subchannel; grpc_connected_subchannel **connected_subchannel;
grpc_closure *on_ready; grpc_closure *on_ready;
grpc_call_element *elem; grpc_call_element *elem;
grpc_closure closure; grpc_closure closure;
@ -293,17 +294,17 @@ typedef struct {
static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg, static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
grpc_metadata_batch *initial_metadata, grpc_metadata_batch *initial_metadata,
grpc_subchannel **subchannel, grpc_connected_subchannel **connected_subchannel,
grpc_closure *on_ready); grpc_closure *on_ready);
static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, int success) { static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, int success) {
continue_picking_args *cpa = arg; continue_picking_args *cpa = arg;
if (!success) { if (!success) {
grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 0); grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 0);
} else if (cpa->subchannel == NULL) { } else if (cpa->connected_subchannel == NULL) {
/* cancelled, do nothing */ /* cancelled, do nothing */
} else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, } else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
cpa->subchannel, cpa->on_ready)) { cpa->connected_subchannel, cpa->on_ready)) {
grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 1); grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 1);
} }
gpr_free(cpa); gpr_free(cpa);
@ -311,7 +312,7 @@ static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, int success) {
static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp, static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
grpc_metadata_batch *initial_metadata, grpc_metadata_batch *initial_metadata,
grpc_subchannel **subchannel, grpc_connected_subchannel **connected_subchannel,
grpc_closure *on_ready) { grpc_closure *on_ready) {
grpc_call_element *elem = elemp; grpc_call_element *elem = elemp;
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
@ -319,18 +320,19 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
continue_picking_args *cpa; continue_picking_args *cpa;
grpc_closure *closure; grpc_closure *closure;
GPR_ASSERT(subchannel); GPR_ASSERT(connected_subchannel);
gpr_mu_lock(&chand->mu_config); gpr_mu_lock(&chand->mu_config);
if (initial_metadata == NULL) { if (initial_metadata == NULL) {
if (chand->lb_policy != NULL) { if (chand->lb_policy != NULL) {
grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy, subchannel); grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy,
connected_subchannel);
} }
for (closure = chand->waiting_for_config_closures.head; closure != NULL; for (closure = chand->waiting_for_config_closures.head; closure != NULL;
closure = grpc_closure_next(closure)) { closure = grpc_closure_next(closure)) {
cpa = closure->cb_arg; cpa = closure->cb_arg;
if (cpa->subchannel == subchannel) { if (cpa->connected_subchannel == connected_subchannel) {
cpa->subchannel = NULL; cpa->connected_subchannel = NULL;
grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 0); grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 0);
} }
} }
@ -338,21 +340,22 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
return 1; return 1;
} }
if (chand->lb_policy != NULL) { if (chand->lb_policy != NULL) {
int r = grpc_lb_policy_pick(exec_ctx, chand->lb_policy, calld->pollset, int r =
initial_metadata, subchannel, on_ready); grpc_lb_policy_pick(exec_ctx, chand->lb_policy, calld->pollset,
initial_metadata, connected_subchannel, on_ready);
gpr_mu_unlock(&chand->mu_config); gpr_mu_unlock(&chand->mu_config);
return r; return r;
} }
if (chand->resolver != NULL && !chand->started_resolving) { if (chand->resolver != NULL && !chand->started_resolving) {
chand->started_resolving = 1; chand->started_resolving = 1;
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
grpc_resolver_next(exec_ctx, chand->resolver, grpc_resolver_next(exec_ctx, chand->resolver,
&chand->incoming_configuration, &chand->incoming_configuration,
&chand->on_config_changed); &chand->on_config_changed);
} }
cpa = gpr_malloc(sizeof(*cpa)); cpa = gpr_malloc(sizeof(*cpa));
cpa->initial_metadata = initial_metadata; cpa->initial_metadata = initial_metadata;
cpa->subchannel = subchannel; cpa->connected_subchannel = connected_subchannel;
cpa->on_ready = on_ready; cpa->on_ready = on_ready;
cpa->elem = elem; cpa->elem = elem;
grpc_closure_init(&cpa->closure, continue_picking, cpa); grpc_closure_init(&cpa->closure, continue_picking, cpa);
@ -364,7 +367,8 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
/* Constructor for call_data */ /* Constructor for call_data */
static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args) { grpc_call_element_args *args) {
grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem); grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem,
args->call_stack);
} }
/* Destructor for call_data */ /* Destructor for call_data */
@ -385,12 +389,12 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(elem->filter == &grpc_client_channel_filter); GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
gpr_mu_init(&chand->mu_config); gpr_mu_init(&chand->mu_config);
chand->master = args->master;
grpc_pollset_set_init(&chand->pollset_set);
grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand); grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand);
chand->owning_stack = args->channel_stack;
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
"client_channel"); "client_channel");
grpc_pollset_set_init(&chand->interested_parties);
} }
/* Destructor for channel_data */ /* Destructor for channel_data */
@ -403,10 +407,13 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
} }
if (chand->lb_policy != NULL) { if (chand->lb_policy != NULL) {
grpc_pollset_set_del_pollset_set(exec_ctx,
&chand->lb_policy->interested_parties,
&chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
} }
grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
grpc_pollset_set_destroy(&chand->pollset_set); grpc_pollset_set_destroy(&chand->interested_parties);
gpr_mu_destroy(&chand->mu_config); gpr_mu_destroy(&chand->mu_config);
} }
@ -435,7 +442,7 @@ void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx,
if (!grpc_closure_list_empty(chand->waiting_for_config_closures) || if (!grpc_closure_list_empty(chand->waiting_for_config_closures) ||
chand->exit_idle_when_lb_policy_arrives) { chand->exit_idle_when_lb_policy_arrives) {
chand->started_resolving = 1; chand->started_resolving = 1;
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration, grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration,
&chand->on_config_changed); &chand->on_config_changed);
} }
@ -454,7 +461,7 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
} else { } else {
chand->exit_idle_when_lb_policy_arrives = 1; chand->exit_idle_when_lb_policy_arrives = 1;
if (!chand->started_resolving && chand->resolver != NULL) { if (!chand->started_resolving && chand->resolver != NULL) {
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver"); GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
chand->started_resolving = 1; chand->started_resolving = 1;
grpc_resolver_next(exec_ctx, chand->resolver, grpc_resolver_next(exec_ctx, chand->resolver,
&chand->incoming_configuration, &chand->incoming_configuration,
@ -466,32 +473,39 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
return out; return out;
} }
typedef struct {
channel_data *chand;
grpc_pollset *pollset;
grpc_closure *on_complete;
grpc_closure my_closure;
} external_connectivity_watcher;
static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
external_connectivity_watcher *w = arg;
grpc_closure *follow_up = w->on_complete;
grpc_pollset_set_del_pollset(exec_ctx, &w->chand->interested_parties,
w->pollset);
GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
"external_connectivity_watcher");
gpr_free(w);
follow_up->cb(exec_ctx, follow_up->cb_arg, iomgr_success);
}
void grpc_client_channel_watch_connectivity_state( void grpc_client_channel_watch_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
grpc_connectivity_state *state, grpc_closure *on_complete) { grpc_connectivity_state *state, grpc_closure *on_complete) {
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
external_connectivity_watcher *w = gpr_malloc(sizeof(*w));
w->chand = chand;
w->pollset = pollset;
w->on_complete = on_complete;
grpc_pollset_set_add_pollset(exec_ctx, &chand->interested_parties, pollset);
grpc_closure_init(&w->my_closure, on_external_watch_complete, w);
GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
"external_connectivity_watcher");
gpr_mu_lock(&chand->mu_config); gpr_mu_lock(&chand->mu_config);
grpc_connectivity_state_notify_on_state_change( grpc_connectivity_state_notify_on_state_change(
exec_ctx, &chand->state_tracker, state, on_complete); exec_ctx, &chand->state_tracker, state, &w->my_closure);
gpr_mu_unlock(&chand->mu_config); gpr_mu_unlock(&chand->mu_config);
} }
grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(
grpc_channel_element *elem) {
channel_data *chand = elem->channel_data;
return &chand->pollset_set;
}
void grpc_client_channel_add_interested_party(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_pollset *pollset) {
channel_data *chand = elem->channel_data;
grpc_pollset_set_add_pollset(exec_ctx, &chand->pollset_set, pollset);
}
void grpc_client_channel_del_interested_party(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_pollset *pollset) {
channel_data *chand = elem->channel_data;
grpc_pollset_set_del_pollset(exec_ctx, &chand->pollset_set, pollset);
}

@ -57,17 +57,7 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
void grpc_client_channel_watch_connectivity_state( void grpc_client_channel_watch_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
grpc_connectivity_state *state, grpc_closure *on_complete); grpc_connectivity_state *state, grpc_closure *on_complete);
grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(
grpc_channel_element *elem);
void grpc_client_channel_add_interested_party(grpc_exec_ctx *exec_ctx,
grpc_channel_element *channel,
grpc_pollset *pollset);
void grpc_client_channel_del_interested_party(grpc_exec_ctx *exec_ctx,
grpc_channel_element *channel,
grpc_pollset *pollset);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */ #endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */

@ -58,13 +58,13 @@ typedef struct client_uchannel_channel_data {
this channel_data via its channel stack. this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel We occasionally use this to bump the refcount on the master channel
to keep ourselves alive through an asynchronous operation. */ to keep ourselves alive through an asynchronous operation. */
grpc_channel *master; grpc_channel_stack *owning_stack;
/** connectivity state being tracked */ /** connectivity state being tracked */
grpc_connectivity_state_tracker state_tracker; grpc_connectivity_state_tracker state_tracker;
/** the subchannel wrapped by the microchannel */ /** the subchannel wrapped by the microchannel */
grpc_subchannel *subchannel; grpc_connected_subchannel *connected_subchannel;
/** the callback used to stay subscribed to subchannel connectivity /** the callback used to stay subscribed to subchannel connectivity
* notifications */ * notifications */
@ -84,15 +84,13 @@ static void monitor_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
chand->subchannel_connectivity, chand->subchannel_connectivity,
"uchannel_monitor_subchannel"); "uchannel_monitor_subchannel");
grpc_subchannel_notify_on_state_change(exec_ctx, chand->subchannel, grpc_connected_subchannel_notify_on_state_change(
&chand->subchannel_connectivity, exec_ctx, chand->connected_subchannel, NULL,
&chand->connectivity_cb); &chand->subchannel_connectivity, &chand->connectivity_cb);
} }
static char *cuc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { static char *cuc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
channel_data *chand = elem->channel_data; return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data);
return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data,
chand->master);
} }
static void cuc_start_transport_stream_op(grpc_exec_ctx *exec_ctx, static void cuc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
@ -128,11 +126,11 @@ static void cuc_start_transport_op(grpc_exec_ctx *exec_ctx,
static int cuc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg, static int cuc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
grpc_metadata_batch *initial_metadata, grpc_metadata_batch *initial_metadata,
grpc_subchannel **subchannel, grpc_connected_subchannel **connected_subchannel,
grpc_closure *on_ready) { grpc_closure *on_ready) {
channel_data *chand = arg; channel_data *chand = arg;
GPR_ASSERT(initial_metadata != NULL); GPR_ASSERT(initial_metadata != NULL);
*subchannel = chand->subchannel; *connected_subchannel = chand->connected_subchannel;
return 1; return 1;
} }
@ -140,7 +138,7 @@ static int cuc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
static void cuc_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, static void cuc_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args) { grpc_call_element_args *args) {
grpc_subchannel_call_holder_init(elem->call_data, cuc_pick_subchannel, grpc_subchannel_call_holder_init(elem->call_data, cuc_pick_subchannel,
elem->channel_data); elem->channel_data, args->call_stack);
} }
/* Destructor for call_data */ /* Destructor for call_data */
@ -158,7 +156,7 @@ static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_closure_init(&chand->connectivity_cb, monitor_subchannel, chand); grpc_closure_init(&chand->connectivity_cb, monitor_subchannel, chand);
GPR_ASSERT(args->is_last); GPR_ASSERT(args->is_last);
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter); GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter);
chand->master = args->master; chand->owning_stack = args->channel_stack;
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
"client_uchannel"); "client_uchannel");
gpr_mu_init(&chand->mu_state); gpr_mu_init(&chand->mu_state);
@ -168,10 +166,14 @@ static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx,
static void cuc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, static void cuc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) { grpc_channel_element *elem) {
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
grpc_subchannel_state_change_unsubscribe(exec_ctx, chand->subchannel, /* cancel subscription */
grpc_connected_subchannel_notify_on_state_change(
exec_ctx, chand->connected_subchannel, NULL, NULL,
&chand->connectivity_cb); &chand->connectivity_cb);
grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
gpr_mu_destroy(&chand->mu_state); gpr_mu_destroy(&chand->mu_state);
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, chand->connected_subchannel,
"uchannel");
} }
static void cuc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, static void cuc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
@ -191,23 +193,14 @@ grpc_connectivity_state grpc_client_uchannel_check_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) { grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) {
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
grpc_connectivity_state out; grpc_connectivity_state out;
out = grpc_connectivity_state_check(&chand->state_tracker);
gpr_mu_lock(&chand->mu_state); gpr_mu_lock(&chand->mu_state);
if (out == GRPC_CHANNEL_IDLE && try_to_connect) { out = grpc_connectivity_state_check(&chand->state_tracker);
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
GRPC_CHANNEL_CONNECTING,
"uchannel_connecting_changed");
chand->subchannel_connectivity = out;
grpc_subchannel_notify_on_state_change(exec_ctx, chand->subchannel,
&chand->subchannel_connectivity,
&chand->connectivity_cb);
}
gpr_mu_unlock(&chand->mu_state); gpr_mu_unlock(&chand->mu_state);
return out; return out;
} }
void grpc_client_uchannel_watch_connectivity_state( void grpc_client_uchannel_watch_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
grpc_connectivity_state *state, grpc_closure *on_complete) { grpc_connectivity_state *state, grpc_closure *on_complete) {
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
gpr_mu_lock(&chand->mu_state); gpr_mu_lock(&chand->mu_state);
@ -216,40 +209,11 @@ void grpc_client_uchannel_watch_connectivity_state(
gpr_mu_unlock(&chand->mu_state); gpr_mu_unlock(&chand->mu_state);
} }
grpc_pollset_set *grpc_client_uchannel_get_connecting_pollset_set(
grpc_channel_element *elem) {
channel_data *chand = elem->channel_data;
grpc_channel_element *parent_elem;
gpr_mu_lock(&chand->mu_state);
parent_elem = grpc_channel_stack_last_element(grpc_channel_get_channel_stack(
grpc_subchannel_get_master(chand->subchannel)));
gpr_mu_unlock(&chand->mu_state);
return grpc_client_channel_get_connecting_pollset_set(parent_elem);
}
void grpc_client_uchannel_add_interested_party(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_pollset *pollset) {
grpc_pollset_set *master_pollset_set =
grpc_client_uchannel_get_connecting_pollset_set(elem);
grpc_pollset_set_add_pollset(exec_ctx, master_pollset_set, pollset);
}
void grpc_client_uchannel_del_interested_party(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_pollset *pollset) {
grpc_pollset_set *master_pollset_set =
grpc_client_uchannel_get_connecting_pollset_set(elem);
grpc_pollset_set_del_pollset(exec_ctx, master_pollset_set, pollset);
}
grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel, grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
grpc_channel_args *args) { grpc_channel_args *args) {
grpc_channel *channel = NULL; grpc_channel *channel = NULL;
#define MAX_FILTERS 3 #define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS]; const grpc_channel_filter *filters[MAX_FILTERS];
grpc_channel *master = grpc_subchannel_get_master(subchannel);
char *target = grpc_channel_get_target(master);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
size_t n = 0; size_t n = 0;
@ -261,19 +225,19 @@ grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
GPR_ASSERT(n <= MAX_FILTERS); GPR_ASSERT(n <= MAX_FILTERS);
channel = channel =
grpc_channel_create_from_filters(&exec_ctx, target, filters, n, args, 1); grpc_channel_create_from_filters(&exec_ctx, NULL, filters, n, args, 1);
gpr_free(target);
return channel; return channel;
} }
void grpc_client_uchannel_set_subchannel(grpc_channel *uchannel, void grpc_client_uchannel_set_connected_subchannel(
grpc_subchannel *subchannel) { grpc_channel *uchannel, grpc_connected_subchannel *connected_subchannel) {
grpc_channel_element *elem = grpc_channel_element *elem =
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(uchannel)); grpc_channel_stack_last_element(grpc_channel_get_channel_stack(uchannel));
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter); GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter);
gpr_mu_lock(&chand->mu_state); gpr_mu_lock(&chand->mu_state);
chand->subchannel = subchannel; chand->connected_subchannel = connected_subchannel;
GRPC_CONNECTED_SUBCHANNEL_REF(connected_subchannel, "uchannel");
gpr_mu_unlock(&chand->mu_state); gpr_mu_unlock(&chand->mu_state);
} }

@ -48,23 +48,13 @@ grpc_connectivity_state grpc_client_uchannel_check_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
void grpc_client_uchannel_watch_connectivity_state( void grpc_client_uchannel_watch_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
grpc_connectivity_state *state, grpc_closure *on_complete); grpc_connectivity_state *state, grpc_closure *on_complete);
grpc_pollset_set *grpc_client_uchannel_get_connecting_pollset_set(
grpc_channel_element *elem);
void grpc_client_uchannel_add_interested_party(grpc_exec_ctx *exec_ctx,
grpc_channel_element *channel,
grpc_pollset *pollset);
void grpc_client_uchannel_del_interested_party(grpc_exec_ctx *exec_ctx,
grpc_channel_element *channel,
grpc_pollset *pollset);
grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel, grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
grpc_channel_args *args); grpc_channel_args *args);
void grpc_client_uchannel_set_subchannel(grpc_channel *uchannel, void grpc_client_uchannel_set_connected_subchannel(
grpc_subchannel *subchannel); grpc_channel *uchannel, grpc_connected_subchannel *connected_subchannel);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_MICROCHANNEL_H */ #endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_MICROCHANNEL_H */

@ -288,8 +288,7 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for channel data */ /* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) { grpc_channel_element *elem) {}
}
const grpc_channel_filter grpc_compress_filter = { const grpc_channel_filter grpc_compress_filter = {
compress_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data), compress_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data),

@ -89,9 +89,9 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
int r; int r;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter); GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
r = grpc_transport_init_stream(exec_ctx, chand->transport, r = grpc_transport_init_stream(
TRANSPORT_STREAM_FROM_CALL_DATA(calld), exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld),
args->refcount, args->server_transport_data); &args->call_stack->refcount, args->server_transport_data);
GPR_ASSERT(r == 0); GPR_ASSERT(r == 0);
} }

@ -224,8 +224,7 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for channel data */ /* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) { grpc_channel_element *elem) {}
}
const grpc_channel_filter grpc_http_server_filter = { const grpc_channel_filter grpc_http_server_filter = {
hs_start_transport_op, grpc_channel_next_op, sizeof(call_data), hs_start_transport_op, grpc_channel_next_op, sizeof(call_data),

@ -44,7 +44,6 @@
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder, static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder,
int success); int success);
static void call_ready(grpc_exec_ctx *exec_ctx, void *holder, int success);
static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args, static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args,
int success); int success);
@ -58,16 +57,17 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
void grpc_subchannel_call_holder_init( void grpc_subchannel_call_holder_init(
grpc_subchannel_call_holder *holder, grpc_subchannel_call_holder *holder,
grpc_subchannel_call_holder_pick_subchannel pick_subchannel, grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
void *pick_subchannel_arg) { void *pick_subchannel_arg, grpc_call_stack *owning_call) {
gpr_atm_rel_store(&holder->subchannel_call, 0); gpr_atm_rel_store(&holder->subchannel_call, 0);
holder->pick_subchannel = pick_subchannel; holder->pick_subchannel = pick_subchannel;
holder->pick_subchannel_arg = pick_subchannel_arg; holder->pick_subchannel_arg = pick_subchannel_arg;
gpr_mu_init(&holder->mu); gpr_mu_init(&holder->mu);
holder->subchannel = NULL; holder->connected_subchannel = NULL;
holder->waiting_ops = NULL; holder->waiting_ops = NULL;
holder->waiting_ops_count = 0; holder->waiting_ops_count = 0;
holder->waiting_ops_capacity = 0; holder->waiting_ops_capacity = 0;
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
holder->owning_call = owning_call;
} }
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
@ -125,13 +125,9 @@ retry:
case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING: case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
fail_locked(exec_ctx, holder); fail_locked(exec_ctx, holder);
break; break;
case GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL:
grpc_subchannel_cancel_create_call(exec_ctx, holder->subchannel,
&holder->subchannel_call);
break;
case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL: case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL, holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL,
&holder->subchannel, NULL); &holder->connected_subchannel, NULL);
break; break;
} }
gpr_mu_unlock(&holder->mu); gpr_mu_unlock(&holder->mu);
@ -142,29 +138,28 @@ retry:
} }
/* if we don't have a subchannel, try to get one */ /* if we don't have a subchannel, try to get one */
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
holder->subchannel == NULL && op->send_initial_metadata != NULL) { holder->connected_subchannel == NULL &&
op->send_initial_metadata != NULL) {
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL; holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
grpc_closure_init(&holder->next_step, subchannel_ready, holder); grpc_closure_init(&holder->next_step, subchannel_ready, holder);
if (holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, GRPC_CALL_STACK_REF(holder->owning_call, "pick_subchannel");
op->send_initial_metadata, &holder->subchannel, if (holder->pick_subchannel(
&holder->next_step)) { exec_ctx, holder->pick_subchannel_arg, op->send_initial_metadata,
&holder->connected_subchannel, &holder->next_step)) {
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
} }
} }
/* if we've got a subchannel, then let's ask it to create a call */ /* if we've got a subchannel, then let's ask it to create a call */
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING && if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
holder->subchannel != NULL) { holder->connected_subchannel != NULL) {
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL; gpr_atm_rel_store(
grpc_closure_init(&holder->next_step, call_ready, holder); &holder->subchannel_call,
if (grpc_subchannel_create_call(exec_ctx, holder->subchannel, (gpr_atm)(gpr_uintptr)grpc_connected_subchannel_create_call(
holder->pollset, &holder->subchannel_call, exec_ctx, holder->connected_subchannel, holder->pollset));
&holder->next_step)) {
/* got one immediately - continue the op (and any waiting ops) */
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
retry_waiting_locked(exec_ctx, holder); retry_waiting_locked(exec_ctx, holder);
goto retry; goto retry;
} }
}
/* nothing to be done but wait */ /* nothing to be done but wait */
add_waiting_locked(holder, op); add_waiting_locked(holder, op);
gpr_mu_unlock(&holder->mu); gpr_mu_unlock(&holder->mu);
@ -179,36 +174,18 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) {
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL); GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL);
call = GET_CALL(holder); call = GET_CALL(holder);
GPR_ASSERT(call == NULL || call == CANCELLED_CALL); GPR_ASSERT(call == NULL || call == CANCELLED_CALL);
if (holder->subchannel == NULL) {
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
if (holder->connected_subchannel == NULL) {
fail_locked(exec_ctx, holder); fail_locked(exec_ctx, holder);
} else { } else {
grpc_closure_init(&holder->next_step, call_ready, holder); gpr_atm_rel_store(
if (grpc_subchannel_create_call(exec_ctx, holder->subchannel, &holder->subchannel_call,
holder->pollset, &holder->subchannel_call, (gpr_atm)(gpr_uintptr)grpc_connected_subchannel_create_call(
&holder->next_step)) { exec_ctx, holder->connected_subchannel, holder->pollset));
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
/* got one immediately - continue the op (and any waiting ops) */
retry_waiting_locked(exec_ctx, holder); retry_waiting_locked(exec_ctx, holder);
} }
}
gpr_mu_unlock(&holder->mu); gpr_mu_unlock(&holder->mu);
} GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
static void call_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) {
grpc_subchannel_call_holder *holder = arg;
GPR_TIMER_BEGIN("call_ready", 0);
gpr_mu_lock(&holder->mu);
GPR_ASSERT(holder->creation_phase ==
GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL);
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
if (GET_CALL(holder) != NULL) {
retry_waiting_locked(exec_ctx, holder);
} else {
fail_locked(exec_ctx, holder);
}
gpr_mu_unlock(&holder->mu);
GPR_TIMER_END("call_ready", 0);
} }
typedef struct { typedef struct {
@ -270,14 +247,13 @@ static void fail_locked(grpc_exec_ctx *exec_ctx,
holder->waiting_ops_count = 0; holder->waiting_ops_count = 0;
} }
char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx, char *grpc_subchannel_call_holder_get_peer(
grpc_subchannel_call_holder *holder, grpc_exec_ctx *exec_ctx, grpc_subchannel_call_holder *holder) {
grpc_channel *master) {
grpc_subchannel_call *subchannel_call = GET_CALL(holder); grpc_subchannel_call *subchannel_call = GET_CALL(holder);
if (subchannel_call) { if (subchannel_call) {
return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call); return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call);
} else { } else {
return grpc_channel_get_target(master); return NULL;
} }
} }

@ -42,12 +42,11 @@
called when the subchannel is available) */ called when the subchannel is available) */
typedef int (*grpc_subchannel_call_holder_pick_subchannel)( typedef int (*grpc_subchannel_call_holder_pick_subchannel)(
grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata, grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata,
grpc_subchannel **subchannel, grpc_closure *on_ready); grpc_connected_subchannel **connected_subchannel, grpc_closure *on_ready);
typedef enum { typedef enum {
GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING, GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING,
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL, GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL
GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL
} grpc_subchannel_call_holder_creation_phase; } grpc_subchannel_call_holder_creation_phase;
/** Wrapper for holding a pointer to grpc_subchannel_call, and the /** Wrapper for holding a pointer to grpc_subchannel_call, and the
@ -71,7 +70,7 @@ typedef struct grpc_subchannel_call_holder {
gpr_mu mu; gpr_mu mu;
grpc_subchannel_call_holder_creation_phase creation_phase; grpc_subchannel_call_holder_creation_phase creation_phase;
grpc_subchannel *subchannel; grpc_connected_subchannel *connected_subchannel;
grpc_pollset *pollset; grpc_pollset *pollset;
grpc_transport_stream_op *waiting_ops; grpc_transport_stream_op *waiting_ops;
@ -79,12 +78,14 @@ typedef struct grpc_subchannel_call_holder {
size_t waiting_ops_capacity; size_t waiting_ops_capacity;
grpc_closure next_step; grpc_closure next_step;
grpc_call_stack *owning_call;
} grpc_subchannel_call_holder; } grpc_subchannel_call_holder;
void grpc_subchannel_call_holder_init( void grpc_subchannel_call_holder_init(
grpc_subchannel_call_holder *holder, grpc_subchannel_call_holder *holder,
grpc_subchannel_call_holder_pick_subchannel pick_subchannel, grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
void *pick_subchannel_arg); void *pick_subchannel_arg, grpc_call_stack *owning_call);
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx, void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call_holder *holder); grpc_subchannel_call_holder *holder);
@ -92,7 +93,6 @@ void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call_holder *holder, grpc_subchannel_call_holder *holder,
grpc_transport_stream_op *op); grpc_transport_stream_op *op);
char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx, char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call_holder *holder, grpc_subchannel_call_holder *holder);
grpc_channel *master);
#endif #endif

@ -42,7 +42,7 @@
typedef struct pending_pick { typedef struct pending_pick {
struct pending_pick *next; struct pending_pick *next;
grpc_pollset *pollset; grpc_pollset *pollset;
grpc_subchannel **target; grpc_connected_subchannel **target;
grpc_closure *on_complete; grpc_closure *on_complete;
} pending_pick; } pending_pick;
@ -60,7 +60,7 @@ typedef struct {
/** the selected channel /** the selected channel
TODO(ctiller): this should be atomically set so we don't TODO(ctiller): this should be atomically set so we don't
need to take a mutex in the common case */ need to take a mutex in the common case */
grpc_subchannel *selected; grpc_connected_subchannel *selected;
/** have we started picking? */ /** have we started picking? */
int started_picking; int started_picking;
/** are we shut down? */ /** are we shut down? */
@ -76,24 +76,6 @@ typedef struct {
grpc_connectivity_state_tracker state_tracker; grpc_connectivity_state_tracker state_tracker;
} pick_first_lb_policy; } pick_first_lb_policy;
static void del_interested_parties_locked(grpc_exec_ctx *exec_ctx,
pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_del_interested_party(
exec_ctx, p->subchannels[p->checking_subchannel], pp->pollset);
}
}
static void add_interested_parties_locked(grpc_exec_ctx *exec_ctx,
pick_first_lb_policy *p) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_add_interested_party(
exec_ctx, p->subchannels[p->checking_subchannel], pp->pollset);
}
}
void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
size_t i; size_t i;
@ -102,7 +84,7 @@ void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first"); GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first");
} }
if (p->selected) { if (p->selected) {
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->selected, "picked_first"); GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected, "picked_first");
} }
grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
gpr_free(p->subchannels); gpr_free(p->subchannels);
@ -114,16 +96,26 @@ void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp; pending_pick *pp;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
del_interested_parties_locked(exec_ctx, p);
p->shutdown = 1; p->shutdown = 1;
pp = p->pending_picks; pp = p->pending_picks;
p->pending_picks = NULL; p->pending_picks = NULL;
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE, "shutdown"); GRPC_CHANNEL_FATAL_FAILURE, "shutdown");
/* cancel subscription */
if (p->selected != NULL) {
grpc_connected_subchannel_notify_on_state_change(
exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed);
} else {
grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
&p->connectivity_changed);
}
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
while (pp != NULL) { while (pp != NULL) {
pending_pick *next = pp->next; pending_pick *next = pp->next;
*pp->target = NULL; *pp->target = NULL;
grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
pp->pollset);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
gpr_free(pp); gpr_free(pp);
pp = next; pp = next;
@ -131,7 +123,7 @@ void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
} }
static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_subchannel **target) { grpc_connected_subchannel **target) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp; pending_pick *pp;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
@ -140,8 +132,8 @@ static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
while (pp != NULL) { while (pp != NULL) {
pending_pick *next = pp->next; pending_pick *next = pp->next;
if (pp->target == target) { if (pp->target == target) {
grpc_subchannel_del_interested_party( grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
exec_ctx, p->subchannels[p->checking_subchannel], pp->pollset); pp->pollset);
*target = NULL; *target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0);
gpr_free(pp); gpr_free(pp);
@ -158,10 +150,11 @@ static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) {
p->started_picking = 1; p->started_picking = 1;
p->checking_subchannel = 0; p->checking_subchannel = 0;
p->checking_connectivity = GRPC_CHANNEL_IDLE; p->checking_connectivity = GRPC_CHANNEL_IDLE;
GRPC_LB_POLICY_REF(&p->base, "pick_first_connectivity"); GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity");
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel], exec_ctx, p->subchannels[p->checking_subchannel],
&p->checking_connectivity, &p->connectivity_changed); &p->base.interested_parties, &p->checking_connectivity,
&p->connectivity_changed);
} }
void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
@ -174,8 +167,8 @@ void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
} }
int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset, int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata, grpc_subchannel **target, grpc_metadata_batch *initial_metadata,
grpc_closure *on_complete) { grpc_connected_subchannel **target, grpc_closure *on_complete) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp; pending_pick *pp;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
@ -187,8 +180,8 @@ int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
if (!p->started_picking) { if (!p->started_picking) {
start_picking(exec_ctx, p); start_picking(exec_ctx, p);
} }
grpc_subchannel_add_interested_party( grpc_pollset_set_add_pollset(exec_ctx, &p->base.interested_parties,
exec_ctx, p->subchannels[p->checking_subchannel], pollset); pollset);
pp = gpr_malloc(sizeof(*pp)); pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks; pp->next = p->pending_picks;
pp->pollset = pollset; pp->pollset = pollset;
@ -204,25 +197,17 @@ static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) { int iomgr_success) {
pick_first_lb_policy *p = arg; pick_first_lb_policy *p = arg;
size_t i; size_t i;
grpc_transport_op op;
size_t num_subchannels = p->num_subchannels; size_t num_subchannels = p->num_subchannels;
grpc_subchannel **subchannels; grpc_subchannel **subchannels;
grpc_subchannel *exclude_subchannel;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
subchannels = p->subchannels; subchannels = p->subchannels;
p->num_subchannels = 0; p->num_subchannels = 0;
p->subchannels = NULL; p->subchannels = NULL;
exclude_subchannel = p->selected;
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "destroy_subchannels"); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels");
for (i = 0; i < num_subchannels; i++) { for (i = 0; i < num_subchannels; i++) {
if (subchannels[i] != exclude_subchannel) {
memset(&op, 0, sizeof(op));
op.disconnect = 1;
grpc_subchannel_process_transport_op(exec_ctx, subchannels[i], &op);
}
GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first"); GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first");
} }
@ -232,23 +217,28 @@ static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) { int iomgr_success) {
pick_first_lb_policy *p = arg; pick_first_lb_policy *p = arg;
grpc_subchannel *selected_subchannel;
pending_pick *pp; pending_pick *pp;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
if (p->shutdown) { if (p->shutdown) {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
return; return;
} else if (p->selected != NULL) { } else if (p->selected != NULL) {
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
/* if the selected channel goes bad, we're done */
p->checking_connectivity = GRPC_CHANNEL_FATAL_FAILURE;
}
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
p->checking_connectivity, "selected_changed"); p->checking_connectivity, "selected_changed");
if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) { if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) {
grpc_subchannel_notify_on_state_change(exec_ctx, p->selected, grpc_connected_subchannel_notify_on_state_change(
&p->checking_connectivity, exec_ctx, p->selected, &p->base.interested_parties,
&p->connectivity_changed); &p->checking_connectivity, &p->connectivity_changed);
} else { } else {
GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
} }
} else { } else {
loop: loop:
@ -256,39 +246,41 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
case GRPC_CHANNEL_READY: case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_READY, "connecting_ready"); GRPC_CHANNEL_READY, "connecting_ready");
p->selected = p->subchannels[p->checking_subchannel]; selected_subchannel = p->subchannels[p->checking_subchannel];
GRPC_SUBCHANNEL_REF(p->selected, "picked_first"); p->selected =
grpc_subchannel_get_connected_subchannel(selected_subchannel);
GPR_ASSERT(p->selected);
GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked_first");
/* drop the pick list: we are connected now */ /* drop the pick list: we are connected now */
GRPC_LB_POLICY_REF(&p->base, "destroy_subchannels"); GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
grpc_exec_ctx_enqueue(exec_ctx, grpc_exec_ctx_enqueue(exec_ctx,
grpc_closure_create(destroy_subchannels, p), 1); grpc_closure_create(destroy_subchannels, p), 1);
/* update any calls that were waiting for a pick */ /* update any calls that were waiting for a pick */
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = p->selected; *pp->target = p->selected;
grpc_subchannel_del_interested_party(exec_ctx, p->selected, grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
pp->pollset); pp->pollset);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
gpr_free(pp); gpr_free(pp);
} }
grpc_subchannel_notify_on_state_change(exec_ctx, p->selected, grpc_connected_subchannel_notify_on_state_change(
&p->checking_connectivity, exec_ctx, p->selected, &p->base.interested_parties,
&p->connectivity_changed); &p->checking_connectivity, &p->connectivity_changed);
break; break;
case GRPC_CHANNEL_TRANSIENT_FAILURE: case GRPC_CHANNEL_TRANSIENT_FAILURE:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_CHANNEL_TRANSIENT_FAILURE,
"connecting_transient_failure"); "connecting_transient_failure");
del_interested_parties_locked(exec_ctx, p);
p->checking_subchannel = p->checking_subchannel =
(p->checking_subchannel + 1) % p->num_subchannels; (p->checking_subchannel + 1) % p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity( p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]); p->subchannels[p->checking_subchannel]);
add_interested_parties_locked(exec_ctx, p);
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel], exec_ctx, p->subchannels[p->checking_subchannel],
&p->checking_connectivity, &p->connectivity_changed); &p->base.interested_parties, &p->checking_connectivity,
&p->connectivity_changed);
} else { } else {
goto loop; goto loop;
} }
@ -300,13 +292,13 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
"connecting_changed"); "connecting_changed");
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel], exec_ctx, p->subchannels[p->checking_subchannel],
&p->checking_connectivity, &p->connectivity_changed); &p->base.interested_parties, &p->checking_connectivity,
&p->connectivity_changed);
break; break;
case GRPC_CHANNEL_FATAL_FAILURE: case GRPC_CHANNEL_FATAL_FAILURE:
del_interested_parties_locked(exec_ctx, p);
GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
p->subchannels[p->num_subchannels - 1]);
p->num_subchannels--; p->num_subchannels--;
GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
p->subchannels[p->num_subchannels]);
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels], GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
"pick_first"); "pick_first");
if (p->num_subchannels == 0) { if (p->num_subchannels == 0) {
@ -319,7 +311,8 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
gpr_free(pp); gpr_free(pp);
} }
GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
"pick_first_connectivity");
} else { } else {
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_CHANNEL_TRANSIENT_FAILURE,
@ -327,7 +320,6 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
p->checking_subchannel %= p->num_subchannels; p->checking_subchannel %= p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity( p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]); p->subchannels[p->checking_subchannel]);
add_interested_parties_locked(exec_ctx, p);
goto loop; goto loop;
} }
} }
@ -336,39 +328,6 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
} }
static void pf_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_transport_op *op) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
size_t i;
size_t n;
grpc_subchannel **subchannels;
grpc_subchannel *selected;
gpr_mu_lock(&p->mu);
n = p->num_subchannels;
subchannels = gpr_malloc(n * sizeof(*subchannels));
selected = p->selected;
if (selected) {
GRPC_SUBCHANNEL_REF(selected, "pf_broadcast_to_selected");
}
for (i = 0; i < n; i++) {
subchannels[i] = p->subchannels[i];
GRPC_SUBCHANNEL_REF(subchannels[i], "pf_broadcast");
}
gpr_mu_unlock(&p->mu);
for (i = 0; i < n; i++) {
if (selected == subchannels[i]) continue;
grpc_subchannel_process_transport_op(exec_ctx, subchannels[i], op);
GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pf_broadcast");
}
if (p->selected) {
grpc_subchannel_process_transport_op(exec_ctx, selected, op);
GRPC_SUBCHANNEL_UNREF(exec_ctx, selected, "pf_broadcast_to_selected");
}
gpr_free(subchannels);
}
static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx, static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *pol) { grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
@ -391,7 +350,7 @@ void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = { static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
pf_destroy, pf_shutdown, pf_pick, pf_cancel_pick, pf_exit_idle, pf_destroy, pf_shutdown, pf_pick, pf_cancel_pick, pf_exit_idle,
pf_broadcast, pf_check_connectivity, pf_notify_on_state_change}; pf_check_connectivity, pf_notify_on_state_change};
static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {} static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {}

@ -38,6 +38,8 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include "src/core/transport/connectivity_state.h" #include "src/core/transport/connectivity_state.h"
typedef struct round_robin_lb_policy round_robin_lb_policy;
int grpc_lb_round_robin_trace = 0; int grpc_lb_round_robin_trace = 0;
/** List of entities waiting for a pick. /** List of entities waiting for a pick.
@ -46,7 +48,7 @@ int grpc_lb_round_robin_trace = 0;
typedef struct pending_pick { typedef struct pending_pick {
struct pending_pick *next; struct pending_pick *next;
grpc_pollset *pollset; grpc_pollset *pollset;
grpc_subchannel **target; grpc_connected_subchannel **target;
grpc_closure *on_complete; grpc_closure *on_complete;
} pending_pick; } pending_pick;
@ -58,22 +60,27 @@ typedef struct ready_list {
} ready_list; } ready_list;
typedef struct { typedef struct {
size_t subchannel_idx; /**< Index over p->subchannels */ /** index within policy->subchannels */
void *p; /**< round_robin_lb_policy instance */ size_t index;
} connectivity_changed_cb_arg; /** backpointer to owning policy */
round_robin_lb_policy *policy;
typedef struct { /** subchannel itself */
grpc_subchannel *subchannel;
/** notification that connectivity has changed on subchannel */
grpc_closure connectivity_changed_closure;
/** this subchannels current position in subchannel->ready_list */
ready_list *ready_list_node;
/** last observed connectivity */
grpc_connectivity_state connectivity_state;
} subchannel_data;
struct round_robin_lb_policy {
/** base policy: must be first */ /** base policy: must be first */
grpc_lb_policy base; grpc_lb_policy base;
/** all our subchannels */ /** all our subchannels */
grpc_subchannel **subchannels;
size_t num_subchannels; size_t num_subchannels;
subchannel_data **subchannels;
/** Callbacks, one per subchannel being watched, to be called when their
* respective connectivity changes */
grpc_closure *connectivity_changed_cbs;
connectivity_changed_cb_arg *cb_args;
/** mutex protecting remaining members */ /** mutex protecting remaining members */
gpr_mu mu; gpr_mu mu;
@ -81,8 +88,6 @@ typedef struct {
int started_picking; int started_picking;
/** are we shutting down? */ /** are we shutting down? */
int shutdown; int shutdown;
/** Connectivity state of the subchannels being watched */
grpc_connectivity_state *subchannel_connectivity;
/** List of picks that are waiting on connectivity */ /** List of picks that are waiting on connectivity */
pending_pick *pending_picks; pending_pick *pending_picks;
@ -93,13 +98,7 @@ typedef struct {
ready_list ready_list; ready_list ready_list;
/** Last pick from the ready list. */ /** Last pick from the ready list. */
ready_list *ready_list_last_pick; ready_list *ready_list_last_pick;
};
/** Subchannel index to ready_list node.
*
* Kept in order to remove nodes from the ready list associated with a
* subchannel */
ready_list **subchannel_index_to_readylist_node;
} round_robin_lb_policy;
/** Returns the next subchannel from the connected list or NULL if the list is /** Returns the next subchannel from the connected list or NULL if the list is
* empty. * empty.
@ -144,9 +143,9 @@ static void advance_last_picked_locked(round_robin_lb_policy *p) {
/** Prepends (relative to the root at p->ready_list) the connected subchannel \a /** Prepends (relative to the root at p->ready_list) the connected subchannel \a
* csc to the list of ready subchannels. */ * csc to the list of ready subchannels. */
static ready_list *add_connected_sc_locked(round_robin_lb_policy *p, static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
grpc_subchannel *csc) { grpc_subchannel *sc) {
ready_list *new_elem = gpr_malloc(sizeof(ready_list)); ready_list *new_elem = gpr_malloc(sizeof(ready_list));
new_elem->subchannel = csc; new_elem->subchannel = sc;
if (p->ready_list.prev == NULL) { if (p->ready_list.prev == NULL) {
/* first element */ /* first element */
new_elem->next = &p->ready_list; new_elem->next = &p->ready_list;
@ -160,7 +159,7 @@ static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
p->ready_list.prev = new_elem; p->ready_list.prev = new_elem;
} }
if (grpc_lb_round_robin_trace) { if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, csc); gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, sc);
} }
return new_elem; return new_elem;
} }
@ -200,28 +199,15 @@ static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
gpr_free(node); gpr_free(node);
} }
static void del_interested_parties_locked(grpc_exec_ctx *exec_ctx,
round_robin_lb_policy *p,
const size_t subchannel_idx) {
pending_pick *pp;
for (pp = p->pending_picks; pp; pp = pp->next) {
grpc_subchannel_del_interested_party(
exec_ctx, p->subchannels[subchannel_idx], pp->pollset);
}
}
void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol; round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
size_t i; size_t i;
ready_list *elem; ready_list *elem;
for (i = 0; i < p->num_subchannels; i++) { for (i = 0; i < p->num_subchannels; i++) {
del_interested_parties_locked(exec_ctx, p, i); subchannel_data *sd = p->subchannels[i];
GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
gpr_free(sd);
} }
for (i = 0; i < p->num_subchannels; i++) {
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "round_robin");
}
gpr_free(p->connectivity_changed_cbs);
gpr_free(p->subchannel_connectivity);
grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
gpr_free(p->subchannels); gpr_free(p->subchannels);
@ -237,20 +223,15 @@ void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
gpr_free(elem); gpr_free(elem);
elem = tmp; elem = tmp;
} }
gpr_free(p->subchannel_index_to_readylist_node);
gpr_free(p->cb_args);
gpr_free(p); gpr_free(p);
} }
void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
size_t i;
round_robin_lb_policy *p = (round_robin_lb_policy *)pol; round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
pending_pick *pp; pending_pick *pp;
gpr_mu_lock(&p->mu); size_t i;
for (i = 0; i < p->num_subchannels; i++) { gpr_mu_lock(&p->mu);
del_interested_parties_locked(exec_ctx, p, i);
}
p->shutdown = 1; p->shutdown = 1;
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
@ -261,24 +242,26 @@ void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
} }
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE, "shutdown"); GRPC_CHANNEL_FATAL_FAILURE, "shutdown");
for (i = 0; i < p->num_subchannels; i++) {
subchannel_data *sd = p->subchannels[i];
grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL,
&sd->connectivity_changed_closure);
}
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
} }
static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_subchannel **target) { grpc_connected_subchannel **target) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol; round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
pending_pick *pp; pending_pick *pp;
size_t i;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
pp = p->pending_picks; pp = p->pending_picks;
p->pending_picks = NULL; p->pending_picks = NULL;
while (pp != NULL) { while (pp != NULL) {
pending_pick *next = pp->next; pending_pick *next = pp->next;
if (pp->target == target) { if (pp->target == target) {
for (i = 0; i < p->num_subchannels; i++) { grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
grpc_subchannel_add_interested_party(exec_ctx, p->subchannels[i],
pp->pollset); pp->pollset);
}
*target = NULL; *target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0);
gpr_free(pp); gpr_free(pp);
@ -295,12 +278,16 @@ static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
size_t i; size_t i;
p->started_picking = 1; p->started_picking = 1;
gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p,
p->num_subchannels);
for (i = 0; i < p->num_subchannels; i++) { for (i = 0; i < p->num_subchannels; i++) {
p->subchannel_connectivity[i] = GRPC_CHANNEL_IDLE; subchannel_data *sd = p->subchannels[i];
grpc_subchannel_notify_on_state_change(exec_ctx, p->subchannels[i], sd->connectivity_state = GRPC_CHANNEL_IDLE;
&p->subchannel_connectivity[i], grpc_subchannel_notify_on_state_change(
&p->connectivity_changed_cbs[i]); exec_ctx, sd->subchannel, &p->base.interested_parties,
GRPC_LB_POLICY_REF(&p->base, "round_robin_connectivity"); &sd->connectivity_state, &sd->connectivity_changed_closure);
GRPC_LB_POLICY_WEAK_REF(&p->base, "round_robin_connectivity");
} }
} }
@ -314,18 +301,18 @@ void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
} }
int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset, int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata, grpc_subchannel **target, grpc_metadata_batch *initial_metadata,
grpc_closure *on_complete) { grpc_connected_subchannel **target, grpc_closure *on_complete) {
size_t i;
round_robin_lb_policy *p = (round_robin_lb_policy *)pol; round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
pending_pick *pp; pending_pick *pp;
ready_list *selected; ready_list *selected;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
if ((selected = peek_next_connected_locked(p))) { if ((selected = peek_next_connected_locked(p))) {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
*target = selected->subchannel; *target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
if (grpc_lb_round_robin_trace) { if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG, "[RR PICK] TARGET <-- SUBCHANNEL %p (NODE %p)", gpr_log(GPR_DEBUG,
"[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)",
selected->subchannel, selected); selected->subchannel, selected);
} }
/* only advance the last picked pointer if the selection was used */ /* only advance the last picked pointer if the selection was used */
@ -335,10 +322,8 @@ int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
if (!p->started_picking) { if (!p->started_picking) {
start_picking(exec_ctx, p); start_picking(exec_ctx, p);
} }
for (i = 0; i < p->num_subchannels; i++) { grpc_pollset_set_add_pollset(exec_ctx, &p->base.interested_parties,
grpc_subchannel_add_interested_party(exec_ctx, p->subchannels[i],
pollset); pollset);
}
pp = gpr_malloc(sizeof(*pp)); pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks; pp->next = p->pending_picks;
pp->pollset = pollset; pp->pollset = pollset;
@ -352,33 +337,25 @@ int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) { int iomgr_success) {
connectivity_changed_cb_arg *cb_arg = arg; subchannel_data *sd = arg;
round_robin_lb_policy *p = cb_arg->p; round_robin_lb_policy *p = sd->policy;
/* index over p->subchannels of this cb's subchannel */
const size_t this_idx = cb_arg->subchannel_idx;
pending_pick *pp; pending_pick *pp;
ready_list *selected; ready_list *selected;
int unref = 0; int unref = 0;
/* connectivity state of this cb's subchannel */
grpc_connectivity_state *this_connectivity;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
this_connectivity = &p->subchannel_connectivity[this_idx];
if (p->shutdown) { if (p->shutdown) {
unref = 1; unref = 1;
} else { } else {
switch (*this_connectivity) { switch (sd->connectivity_state) {
case GRPC_CHANNEL_READY: case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_READY, "connecting_ready"); GRPC_CHANNEL_READY, "connecting_ready");
/* add the newly connected subchannel to the list of connected ones. /* add the newly connected subchannel to the list of connected ones.
* Note that it goes to the "end of the line". */ * Note that it goes to the "end of the line". */
p->subchannel_index_to_readylist_node[this_idx] = sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel);
add_connected_sc_locked(p, p->subchannels[this_idx]);
/* at this point we know there's at least one suitable subchannel. Go /* at this point we know there's at least one suitable subchannel. Go
* ahead and pick one and notify the pending suitors in * ahead and pick one and notify the pending suitors in
* p->pending_picks. This preemtively replicates rr_pick()'s actions. */ * p->pending_picks. This preemtively replicates rr_pick()'s actions. */
@ -390,60 +367,60 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
} }
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = selected->subchannel; *pp->target =
grpc_subchannel_get_connected_subchannel(selected->subchannel);
if (grpc_lb_round_robin_trace) { if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)", "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
selected->subchannel, selected); selected->subchannel, selected);
} }
grpc_subchannel_del_interested_party(exec_ctx, selected->subchannel, grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
pp->pollset); pp->pollset);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
gpr_free(pp); gpr_free(pp);
} }
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[this_idx], this_connectivity, exec_ctx, sd->subchannel, &p->base.interested_parties,
&p->connectivity_changed_cbs[this_idx]); &sd->connectivity_state, &sd->connectivity_changed_closure);
break; break;
case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE: case GRPC_CHANNEL_IDLE:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
*this_connectivity, "connecting_changed"); sd->connectivity_state,
"connecting_changed");
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[this_idx], this_connectivity, exec_ctx, sd->subchannel, &p->base.interested_parties,
&p->connectivity_changed_cbs[this_idx]); &sd->connectivity_state, &sd->connectivity_changed_closure);
break; break;
case GRPC_CHANNEL_TRANSIENT_FAILURE: case GRPC_CHANNEL_TRANSIENT_FAILURE:
del_interested_parties_locked(exec_ctx, p, this_idx);
/* renew state notification */ /* renew state notification */
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[this_idx], this_connectivity, exec_ctx, sd->subchannel, &p->base.interested_parties,
&p->connectivity_changed_cbs[this_idx]); &sd->connectivity_state, &sd->connectivity_changed_closure);
/* remove from ready list if still present */ /* remove from ready list if still present */
if (p->subchannel_index_to_readylist_node[this_idx] != NULL) { if (sd->ready_list_node != NULL) {
remove_disconnected_sc_locked( remove_disconnected_sc_locked(p, sd->ready_list_node);
p, p->subchannel_index_to_readylist_node[this_idx]); sd->ready_list_node = NULL;
p->subchannel_index_to_readylist_node[this_idx] = NULL;
} }
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_CHANNEL_TRANSIENT_FAILURE,
"connecting_transient_failure"); "connecting_transient_failure");
break; break;
case GRPC_CHANNEL_FATAL_FAILURE: case GRPC_CHANNEL_FATAL_FAILURE:
del_interested_parties_locked(exec_ctx, p, this_idx); if (sd->ready_list_node != NULL) {
if (p->subchannel_index_to_readylist_node[this_idx] != NULL) { remove_disconnected_sc_locked(p, sd->ready_list_node);
remove_disconnected_sc_locked( sd->ready_list_node = NULL;
p, p->subchannel_index_to_readylist_node[this_idx]);
p->subchannel_index_to_readylist_node[this_idx] = NULL;
} }
GPR_SWAP(grpc_subchannel *, p->subchannels[this_idx],
p->subchannels[p->num_subchannels - 1]);
p->num_subchannels--; p->num_subchannels--;
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels], GPR_SWAP(subchannel_data *, p->subchannels[sd->index],
"round_robin"); p->subchannels[p->num_subchannels]);
GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
p->subchannels[sd->index]->index = sd->index;
gpr_free(sd);
unref = 1;
if (p->num_subchannels == 0) { if (p->num_subchannels == 0) {
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE, GRPC_CHANNEL_FATAL_FAILURE,
@ -454,7 +431,6 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
gpr_free(pp); gpr_free(pp);
} }
unref = 1;
} else { } else {
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_CHANNEL_TRANSIENT_FAILURE,
@ -466,33 +442,10 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
if (unref) { if (unref) {
GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "round_robin_connectivity"); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity");
} }
} }
static void rr_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_transport_op *op) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
size_t i;
size_t n;
grpc_subchannel **subchannels;
gpr_mu_lock(&p->mu);
n = p->num_subchannels;
subchannels = gpr_malloc(n * sizeof(*subchannels));
for (i = 0; i < n; i++) {
subchannels[i] = p->subchannels[i];
GRPC_SUBCHANNEL_REF(subchannels[i], "rr_broadcast");
}
gpr_mu_unlock(&p->mu);
for (i = 0; i < n; i++) {
grpc_subchannel_process_transport_op(exec_ctx, subchannels[i], op);
GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "rr_broadcast");
}
gpr_free(subchannels);
}
static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx, static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *pol) { grpc_lb_policy *pol) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol; round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
@ -516,7 +469,7 @@ static void rr_notify_on_state_change(grpc_exec_ctx *exec_ctx,
static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = { static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = {
rr_destroy, rr_shutdown, rr_pick, rr_cancel_pick, rr_exit_idle, rr_destroy, rr_shutdown, rr_pick, rr_cancel_pick, rr_exit_idle,
rr_broadcast, rr_check_connectivity, rr_notify_on_state_change}; rr_check_connectivity, rr_notify_on_state_change};
static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {} static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {}
@ -529,27 +482,22 @@ static grpc_lb_policy *create_round_robin(grpc_lb_policy_factory *factory,
GPR_ASSERT(args->num_subchannels > 0); GPR_ASSERT(args->num_subchannels > 0);
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable); grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
p->subchannels =
gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
p->num_subchannels = args->num_subchannels; p->num_subchannels = args->num_subchannels;
p->subchannels = gpr_malloc(sizeof(*p->subchannels) * p->num_subchannels);
memset(p->subchannels, 0, sizeof(*p->subchannels) * p->num_subchannels);
grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
"round_robin"); "round_robin");
memcpy(p->subchannels, args->subchannels,
sizeof(grpc_subchannel *) * args->num_subchannels);
gpr_mu_init(&p->mu); gpr_mu_init(&p->mu);
p->connectivity_changed_cbs =
gpr_malloc(sizeof(grpc_closure) * args->num_subchannels);
p->subchannel_connectivity =
gpr_malloc(sizeof(grpc_connectivity_state) * args->num_subchannels);
p->cb_args =
gpr_malloc(sizeof(connectivity_changed_cb_arg) * args->num_subchannels);
for (i = 0; i < args->num_subchannels; i++) { for (i = 0; i < args->num_subchannels; i++) {
p->cb_args[i].subchannel_idx = i; subchannel_data *sd = gpr_malloc(sizeof(*sd));
p->cb_args[i].p = p; memset(sd, 0, sizeof(*sd));
grpc_closure_init(&p->connectivity_changed_cbs[i], rr_connectivity_changed, p->subchannels[i] = sd;
&p->cb_args[i]); sd->policy = p;
sd->index = i;
sd->subchannel = args->subchannels[i];
grpc_closure_init(&sd->connectivity_changed_closure,
rr_connectivity_changed, sd);
} }
/* The (dummy node) root of the ready list */ /* The (dummy node) root of the ready list */
@ -558,10 +506,6 @@ static grpc_lb_policy *create_round_robin(grpc_lb_policy_factory *factory,
p->ready_list.next = NULL; p->ready_list.next = NULL;
p->ready_list_last_pick = &p->ready_list; p->ready_list_last_pick = &p->ready_list;
p->subchannel_index_to_readylist_node =
gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
memset(p->subchannel_index_to_readylist_node, 0,
sizeof(grpc_subchannel *) * args->num_subchannels);
return &p->base; return &p->base;
} }

@ -33,59 +33,85 @@
#include "src/core/client_config/lb_policy.h" #include "src/core/client_config/lb_policy.h"
#define WEAK_REF_BITS 16
void grpc_lb_policy_init(grpc_lb_policy *policy, void grpc_lb_policy_init(grpc_lb_policy *policy,
const grpc_lb_policy_vtable *vtable) { const grpc_lb_policy_vtable *vtable) {
policy->vtable = vtable; policy->vtable = vtable;
gpr_ref_init(&policy->refs, 1); gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS);
grpc_pollset_set_init(&policy->interested_parties);
} }
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG #ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line, #define REF_FUNC_EXTRA_ARGS , const char *file, int line, const char *reason
const char *reason) { #define REF_MUTATE_EXTRA_ARGS REF_FUNC_EXTRA_ARGS, const char *purpose
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p ref %d -> %d %s", #define REF_FUNC_PASS_ARGS(new_reason) , file, line, new_reason
policy, (int)policy->refs.count, (int)policy->refs.count + 1, reason); #define REF_MUTATE_PASS_ARGS(purpose) , file, line, reason, purpose
#else #else
void grpc_lb_policy_ref(grpc_lb_policy *policy) { #define REF_FUNC_EXTRA_ARGS
#define REF_MUTATE_EXTRA_ARGS
#define REF_FUNC_PASS_ARGS(new_reason)
#define REF_MUTATE_PASS_ARGS(x)
#endif #endif
gpr_ref(&policy->refs);
}
static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta,
int barrier REF_MUTATE_EXTRA_ARGS) {
gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
: gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG #ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
void grpc_lb_policy_unref(grpc_lb_policy *policy, gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
grpc_closure_list *closure_list, const char *file, "LB_POLICY: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val,
int line, const char *reason) { old_val + delta, reason);
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p unref %d -> %d %s",
policy, (int)policy->refs.count, (int)policy->refs.count - 1, reason);
#else
void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
#endif #endif
if (gpr_unref(&policy->refs)) { return old_val;
policy->vtable->destroy(exec_ctx, policy);
} }
void grpc_lb_policy_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
ref_mutate(policy, 1 << WEAK_REF_BITS, 0 REF_MUTATE_PASS_ARGS("STRONG_REF"));
} }
void grpc_lb_policy_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) { void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
gpr_atm old_val =
ref_mutate(policy, (gpr_atm)1 - (gpr_atm)(1 << WEAK_REF_BITS),
1 REF_MUTATE_PASS_ARGS("STRONG_UNREF"));
gpr_atm mask = ~(gpr_atm)((1 << WEAK_REF_BITS) - 1);
gpr_atm check = 1 << WEAK_REF_BITS;
if ((old_val & mask) == check) {
policy->vtable->shutdown(exec_ctx, policy); policy->vtable->shutdown(exec_ctx, policy);
} }
grpc_lb_policy_weak_unref(exec_ctx,
policy REF_FUNC_PASS_ARGS("strong-unref"));
}
void grpc_lb_policy_weak_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
ref_mutate(policy, 1, 0 REF_MUTATE_PASS_ARGS("WEAK_REF"));
}
void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
gpr_atm old_val =
ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF"));
if (old_val == 1) {
grpc_pollset_set_destroy(&policy->interested_parties);
policy->vtable->destroy(exec_ctx, policy);
}
}
int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_pollset *pollset, grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata, grpc_metadata_batch *initial_metadata,
grpc_subchannel **target, grpc_closure *on_complete) { grpc_connected_subchannel **target,
grpc_closure *on_complete) {
return policy->vtable->pick(exec_ctx, policy, pollset, initial_metadata, return policy->vtable->pick(exec_ctx, policy, pollset, initial_metadata,
target, on_complete); target, on_complete);
} }
void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_subchannel **target) { grpc_connected_subchannel **target) {
policy->vtable->cancel_pick(exec_ctx, policy, target); policy->vtable->cancel_pick(exec_ctx, policy, target);
} }
void grpc_lb_policy_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_transport_op *op) {
policy->vtable->broadcast(exec_ctx, policy, op);
}
void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) { void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
policy->vtable->exit_idle(exec_ctx, policy); policy->vtable->exit_idle(exec_ctx, policy);
} }

@ -47,7 +47,8 @@ typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel,
struct grpc_lb_policy { struct grpc_lb_policy {
const grpc_lb_policy_vtable *vtable; const grpc_lb_policy_vtable *vtable;
gpr_refcount refs; gpr_atm ref_pair;
grpc_pollset_set interested_parties;
}; };
struct grpc_lb_policy_vtable { struct grpc_lb_policy_vtable {
@ -58,17 +59,13 @@ struct grpc_lb_policy_vtable {
/** implement grpc_lb_policy_pick */ /** implement grpc_lb_policy_pick */
int (*pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, int (*pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_pollset *pollset, grpc_metadata_batch *initial_metadata, grpc_pollset *pollset, grpc_metadata_batch *initial_metadata,
grpc_subchannel **target, grpc_closure *on_complete); grpc_connected_subchannel **target, grpc_closure *on_complete);
void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_subchannel **target); grpc_connected_subchannel **target);
/** try to enter a READY connectivity state */ /** try to enter a READY connectivity state */
void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
/** broadcast a transport op to all subchannels */
void (*broadcast)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_transport_op *op);
/** check the current connectivity of the lb_policy */ /** check the current connectivity of the lb_policy */
grpc_connectivity_state (*check_connectivity)(grpc_exec_ctx *exec_ctx, grpc_connectivity_state (*check_connectivity)(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *policy); grpc_lb_policy *policy);
@ -81,29 +78,39 @@ struct grpc_lb_policy_vtable {
grpc_closure *closure); grpc_closure *closure);
}; };
/*#define GRPC_LB_POLICY_REFCOUNT_DEBUG*/
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG #ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
#define GRPC_LB_POLICY_REF(p, r) \ #define GRPC_LB_POLICY_REF(p, r) \
grpc_lb_policy_ref((p), __FILE__, __LINE__, (r)) grpc_lb_policy_ref((p), __FILE__, __LINE__, (r))
#define GRPC_LB_POLICY_UNREF(exec_ctx, p, r) \ #define GRPC_LB_POLICY_UNREF(exec_ctx, p, r) \
grpc_lb_policy_unref((exec_ctx), (p), __FILE__, __LINE__, (r)) grpc_lb_policy_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
#define GRPC_LB_POLICY_WEAK_REF(p, r) \
grpc_lb_policy_weak_ref((p), __FILE__, __LINE__, (r))
#define GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, p, r) \
grpc_lb_policy_weak_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line, void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line,
const char *reason); const char *reason);
void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
const char *file, int line, const char *reason); const char *file, int line, const char *reason);
void grpc_lb_policy_weak_ref(grpc_lb_policy *policy, const char *file, int line,
const char *reason);
void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
const char *file, int line, const char *reason);
#else #else
#define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p)) #define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p))
#define GRPC_LB_POLICY_UNREF(cl, p, r) grpc_lb_policy_unref((cl), (p)) #define GRPC_LB_POLICY_UNREF(cl, p, r) grpc_lb_policy_unref((cl), (p))
#define GRPC_LB_POLICY_WEAK_REF(p, r) grpc_lb_policy_weak_ref((p))
#define GRPC_LB_POLICY_WEAK_UNREF(cl, p, r) grpc_lb_policy_weak_unref((cl), (p))
void grpc_lb_policy_ref(grpc_lb_policy *policy); void grpc_lb_policy_ref(grpc_lb_policy *policy);
void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
void grpc_lb_policy_weak_ref(grpc_lb_policy *policy);
void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
#endif #endif
/** called by concrete implementations to initialize the base struct */ /** called by concrete implementations to initialize the base struct */
void grpc_lb_policy_init(grpc_lb_policy *policy, void grpc_lb_policy_init(grpc_lb_policy *policy,
const grpc_lb_policy_vtable *vtable); const grpc_lb_policy_vtable *vtable);
/** Start shutting down (fail any pending picks) */
void grpc_lb_policy_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
/** Given initial metadata in \a initial_metadata, find an appropriate /** Given initial metadata in \a initial_metadata, find an appropriate
target for this rpc, and 'return' it by calling \a on_complete after setting target for this rpc, and 'return' it by calling \a on_complete after setting
\a target. \a target.
@ -111,13 +118,11 @@ void grpc_lb_policy_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_pollset *pollset, grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata, grpc_metadata_batch *initial_metadata,
grpc_subchannel **target, grpc_closure *on_complete); grpc_connected_subchannel **target,
grpc_closure *on_complete);
void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_subchannel **target); grpc_connected_subchannel **target);
void grpc_lb_policy_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_transport_op *op);
void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);

@ -71,11 +71,8 @@ void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
} }
void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx, void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver, grpc_resolver *resolver) {
struct sockaddr *failing_address, resolver->vtable->channel_saw_error(exec_ctx, resolver);
int failing_address_len) {
resolver->vtable->channel_saw_error(exec_ctx, resolver, failing_address,
failing_address_len);
} }
void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,

@ -35,8 +35,8 @@
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H #define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H
#include "src/core/client_config/client_config.h" #include "src/core/client_config/client_config.h"
#include "src/core/client_config/subchannel.h"
#include "src/core/iomgr/iomgr.h" #include "src/core/iomgr/iomgr.h"
#include "src/core/iomgr/sockaddr.h"
typedef struct grpc_resolver grpc_resolver; typedef struct grpc_resolver grpc_resolver;
typedef struct grpc_resolver_vtable grpc_resolver_vtable; typedef struct grpc_resolver_vtable grpc_resolver_vtable;
@ -51,9 +51,7 @@ struct grpc_resolver {
struct grpc_resolver_vtable { struct grpc_resolver_vtable {
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver); void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
struct sockaddr *failing_address,
int failing_address_len);
void (*next)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, void (*next)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
grpc_client_config **target_config, grpc_closure *on_complete); grpc_client_config **target_config, grpc_closure *on_complete);
}; };
@ -81,9 +79,7 @@ void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
/** Notification that the channel has seen an error on some address. /** Notification that the channel has seen an error on some address.
Can be used as a hint that re-resolution is desirable soon. */ Can be used as a hint that re-resolution is desirable soon. */
void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx, void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver, grpc_resolver *resolver);
struct sockaddr *failing_address,
int failing_address_len);
/** Get the next client config. Called by the channel to fetch a new /** Get the next client config. Called by the channel to fetch a new
configuration. Expected to set *target_config with a new configuration, configuration. Expected to set *target_config with a new configuration,

@ -80,9 +80,7 @@ static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
dns_resolver *r); dns_resolver *r);
static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r, static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
struct sockaddr *failing_address,
int failing_address_len);
static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
grpc_client_config **target_config, grpc_client_config **target_config,
grpc_closure *on_complete); grpc_closure *on_complete);
@ -102,8 +100,7 @@ static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
} }
static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver, struct sockaddr *sa, grpc_resolver *resolver) {
int len) {
dns_resolver *r = (dns_resolver *)resolver; dns_resolver *r = (dns_resolver *)resolver;
gpr_mu_lock(&r->mu); gpr_mu_lock(&r->mu);
if (!r->resolving) { if (!r->resolving) {

@ -83,9 +83,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx, static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *r, grpc_resolver *r);
struct sockaddr *failing_address,
int failing_address_len);
static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
grpc_client_config **target_config, grpc_client_config **target_config,
grpc_closure *on_complete); grpc_closure *on_complete);
@ -107,8 +105,13 @@ static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx,
} }
static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx, static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver, grpc_resolver *resolver) {
struct sockaddr *sa, int len) {} sockaddr_resolver *r = (sockaddr_resolver *)resolver;
gpr_mu_lock(&r->mu);
r->published = 0;
sockaddr_maybe_finish_next_locked(exec_ctx, r);
gpr_mu_unlock(&r->mu);
}
static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver, static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
grpc_client_config **target_config, grpc_client_config **target_config,

@ -96,9 +96,7 @@ static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r); static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx, static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *r, grpc_resolver *r);
struct sockaddr *failing_address,
int failing_address_len);
static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r, static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
grpc_client_config **target_config, grpc_client_config **target_config,
grpc_closure *on_complete); grpc_closure *on_complete);
@ -125,8 +123,7 @@ static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx,
} }
static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx, static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver, grpc_resolver *resolver) {
struct sockaddr *sa, int len) {
zookeeper_resolver *r = (zookeeper_resolver *)resolver; zookeeper_resolver *r = (zookeeper_resolver *)resolver;
gpr_mu_lock(&r->mu); gpr_mu_lock(&r->mu);
if (r->resolving == 0) { if (r->resolving == 0) {

@ -47,39 +47,44 @@
#include "src/core/transport/connectivity_state.h" #include "src/core/transport/connectivity_state.h"
#include "src/core/transport/connectivity_state.h" #include "src/core/transport/connectivity_state.h"
#define INTERNAL_REF_BITS 16
#define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1))
#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20 #define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20
#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1 #define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1
#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6 #define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120 #define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2 #define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
typedef struct { #define GET_CONNECTED_SUBCHANNEL(subchannel, barrier) \
/* all fields protected by subchannel->mu */ ((grpc_connected_subchannel *)(gpr_atm_##barrier##_load( \
/** refcount */ &(subchannel)->connected_subchannel)))
int refs;
/** parent subchannel */
grpc_subchannel *subchannel;
} connection;
typedef struct { typedef struct {
grpc_closure closure; grpc_closure closure;
size_t version;
grpc_subchannel *subchannel; grpc_subchannel *subchannel;
grpc_connectivity_state connectivity_state; grpc_connectivity_state connectivity_state;
} state_watcher; } state_watcher;
typedef struct waiting_for_connect { typedef struct external_state_watcher {
struct waiting_for_connect *next;
grpc_closure *notify;
grpc_pollset *pollset;
gpr_atm *target;
grpc_subchannel *subchannel; grpc_subchannel *subchannel;
grpc_closure continuation; grpc_pollset_set *pollset_set;
} waiting_for_connect; grpc_closure *notify;
grpc_closure closure;
struct external_state_watcher *next;
struct external_state_watcher *prev;
} external_state_watcher;
struct grpc_subchannel { struct grpc_subchannel {
grpc_connector *connector; grpc_connector *connector;
/** refcount
- lower INTERNAL_REF_BITS bits are for internal references:
these do not keep the subchannel open.
- upper remaining bits are for public references: these do
keep the subchannel open */
gpr_atm ref_pair;
/** non-transport related channel filters */ /** non-transport related channel filters */
const grpc_channel_filter **filters; const grpc_channel_filter **filters;
size_t num_filters; size_t num_filters;
@ -88,15 +93,9 @@ struct grpc_subchannel {
/** address to connect to */ /** address to connect to */
struct sockaddr *addr; struct sockaddr *addr;
size_t addr_len; size_t addr_len;
/** initial string to send to peer */ /** initial string to send to peer */
gpr_slice initial_connect_string; gpr_slice initial_connect_string;
/** master channel - the grpc_channel instance that ultimately owns
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
to keep ourselves alive through an asynchronous operation. */
grpc_channel *master;
/** have we seen a disconnection? */
int disconnected;
/** set during connection */ /** set during connection */
grpc_connect_out_args connecting_result; grpc_connect_out_args connecting_result;
@ -105,27 +104,24 @@ struct grpc_subchannel {
grpc_closure connected; grpc_closure connected;
/** pollset_set tracking who's interested in a connection /** pollset_set tracking who's interested in a connection
being setup - owned by the master channel (in particular the being setup */
client_channel grpc_pollset_set pollset_set;
filter there-in) */
grpc_pollset_set *pollset_set; /** active connection, or null; of type grpc_connected_subchannel */
gpr_atm connected_subchannel;
/** mutex protecting remaining elements */ /** mutex protecting remaining elements */
gpr_mu mu; gpr_mu mu;
/** active connection */ /** have we seen a disconnection? */
connection *active; int disconnected;
/** version number for the active connection */
size_t active_version;
/** refcount */
int refs;
/** are we connecting */ /** are we connecting */
int connecting; int connecting;
/** things waiting for a connection */
waiting_for_connect *waiting;
/** connectivity state tracking */ /** connectivity state tracking */
grpc_connectivity_state_tracker state_tracker; grpc_connectivity_state_tracker state_tracker;
external_state_watcher root_external_state_watcher;
/** next connect attempt time */ /** next connect attempt time */
gpr_timespec next_attempt; gpr_timespec next_attempt;
/** amount to backoff each failure */ /** amount to backoff each failure */
@ -139,151 +135,141 @@ struct grpc_subchannel {
}; };
struct grpc_subchannel_call { struct grpc_subchannel_call {
connection *connection; grpc_connected_subchannel *connection;
}; };
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1)) #define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1))
#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)((con) + 1)) #define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)(con))
#define CALLSTACK_TO_SUBCHANNEL_CALL(callstack) \ #define CALLSTACK_TO_SUBCHANNEL_CALL(callstack) \
(((grpc_subchannel_call *)(callstack)) - 1) (((grpc_subchannel_call *)(callstack)) - 1)
static grpc_subchannel_call *create_call(grpc_exec_ctx *exec_ctx,
connection *con,
grpc_pollset *pollset);
static void connectivity_state_changed_locked(grpc_exec_ctx *exec_ctx,
grpc_subchannel *c,
const char *reason);
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c);
static gpr_timespec compute_connect_deadline(grpc_subchannel *c); static gpr_timespec compute_connect_deadline(grpc_subchannel *c);
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel, static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel,
int iomgr_success); int iomgr_success);
static void subchannel_ref_locked(grpc_subchannel *c
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
static int subchannel_unref_locked(
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT;
static void connection_ref_locked(connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
static grpc_subchannel *connection_unref_locked(
grpc_exec_ctx *exec_ctx,
connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT;
static void subchannel_destroy(grpc_exec_ctx *exec_ctx, grpc_subchannel *c);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG
#define SUBCHANNEL_REF_LOCKED(p, r) \ #define REF_REASON reason
subchannel_ref_locked((p), __FILE__, __LINE__, (r))
#define SUBCHANNEL_UNREF_LOCKED(p, r) \
subchannel_unref_locked((p), __FILE__, __LINE__, (r))
#define CONNECTION_REF_LOCKED(p, r) \
connection_ref_locked((p), __FILE__, __LINE__, (r))
#define CONNECTION_UNREF_LOCKED(cl, p, r) \
connection_unref_locked((cl), (p), __FILE__, __LINE__, (r))
#define REF_PASS_ARGS , file, line, reason
#define REF_PASS_REASON , reason
#define REF_LOG(name, p) \ #define REF_LOG(name, p) \
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \
(name), (p), (p)->refs, (p)->refs + 1, reason) (name), (p), (p)->refs.count, (p)->refs.count + 1, reason)
#define UNREF_LOG(name, p) \ #define UNREF_LOG(name, p) \
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \
(name), (p), (p)->refs, (p)->refs - 1, reason) (name), (p), (p)->refs.count, (p)->refs.count - 1, reason)
#define REF_MUTATE_EXTRA_ARGS \
GRPC_SUBCHANNEL_REF_EXTRA_ARGS, const char *purpose
#define REF_MUTATE_PURPOSE(x) , file, line, reason, x
#else #else
#define SUBCHANNEL_REF_LOCKED(p, r) subchannel_ref_locked((p)) #define REF_REASON ""
#define SUBCHANNEL_UNREF_LOCKED(p, r) subchannel_unref_locked((p))
#define CONNECTION_REF_LOCKED(p, r) connection_ref_locked((p))
#define CONNECTION_UNREF_LOCKED(cl, p, r) connection_unref_locked((cl), (p))
#define REF_PASS_ARGS
#define REF_PASS_REASON
#define REF_LOG(name, p) \ #define REF_LOG(name, p) \
do { \ do { \
} while (0) } while (0)
#define UNREF_LOG(name, p) \ #define UNREF_LOG(name, p) \
do { \ do { \
} while (0) } while (0)
#define REF_MUTATE_EXTRA_ARGS
#define REF_MUTATE_PURPOSE(x)
#endif #endif
/* /*
* connection implementation * connection implementation
*/ */
static void connection_destroy(grpc_exec_ctx *exec_ctx, connection *c) { static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
GPR_ASSERT(c->refs == 0); int success) {
grpc_connected_subchannel *c = arg;
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c)); grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c));
gpr_free(c); gpr_free(c);
} }
static void connection_ref_locked(connection *c void grpc_connected_subchannel_ref(grpc_connected_subchannel *c
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
REF_LOG("CONNECTION", c); GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON);
subchannel_ref_locked(c->subchannel REF_PASS_ARGS);
++c->refs;
} }
static grpc_subchannel *connection_unref_locked( void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx *exec_ctx, connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { grpc_connected_subchannel *c
grpc_subchannel *destroy = NULL; GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
UNREF_LOG("CONNECTION", c); GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c),
if (subchannel_unref_locked(c->subchannel REF_PASS_ARGS)) { REF_REASON);
destroy = c->subchannel;
}
if (--c->refs == 0 && c->subchannel->active != c) {
connection_destroy(exec_ctx, c);
}
return destroy;
} }
/* /*
* grpc_subchannel implementation * grpc_subchannel implementation
*/ */
static void subchannel_ref_locked(grpc_subchannel *c static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { int success) {
REF_LOG("SUBCHANNEL", c); grpc_subchannel *c = arg;
++c->refs; gpr_free((void *)c->filters);
grpc_channel_args_destroy(c->args);
gpr_free(c->addr);
gpr_slice_unref(c->initial_connect_string);
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
grpc_connector_unref(exec_ctx, c->connector);
grpc_pollset_set_destroy(&c->pollset_set);
gpr_free(c);
} }
static int subchannel_unref_locked(grpc_subchannel *c static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta,
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { int barrier REF_MUTATE_EXTRA_ARGS) {
UNREF_LOG("SUBCHANNEL", c); gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
return --c->refs == 0; : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"SUBCHANNEL: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val,
old_val + delta, reason);
#endif
return old_val;
} }
void grpc_subchannel_ref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { void grpc_subchannel_ref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
gpr_mu_lock(&c->mu); gpr_atm old_refs;
subchannel_ref_locked(c REF_PASS_ARGS); old_refs = ref_mutate(c, (1 << INTERNAL_REF_BITS),
gpr_mu_unlock(&c->mu); 0 REF_MUTATE_PURPOSE("STRONG_REF"));
GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0);
} }
void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, void grpc_subchannel_weak_ref(grpc_subchannel *c
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
int destroy; gpr_atm old_refs;
old_refs = ref_mutate(c, 1, 0 REF_MUTATE_PURPOSE("WEAK_REF"));
GPR_ASSERT(old_refs != 0);
}
static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
grpc_connected_subchannel *con;
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
destroy = subchannel_unref_locked(c REF_PASS_ARGS); GPR_ASSERT(!c->disconnected);
c->disconnected = 1;
grpc_connector_shutdown(exec_ctx, c->connector);
con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
if (con != NULL) {
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection");
gpr_atm_no_barrier_store(&c->connected_subchannel, 0xdeadbeef);
}
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
if (destroy) subchannel_destroy(exec_ctx, c);
} }
static void subchannel_destroy(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx,
if (c->active != NULL) { grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
connection_destroy(exec_ctx, c->active); gpr_atm old_refs;
old_refs = ref_mutate(c, (gpr_atm)1 - (gpr_atm)(1 << INTERNAL_REF_BITS),
1 REF_MUTATE_PURPOSE("STRONG_UNREF"));
if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) {
disconnect(exec_ctx, c);
} }
gpr_free((void *)c->filters); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "strong-unref");
grpc_channel_args_destroy(c->args);
gpr_free(c->addr);
gpr_slice_unref(c->initial_connect_string);
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
grpc_connector_unref(exec_ctx, c->connector);
gpr_free(c);
} }
void grpc_subchannel_add_interested_party(grpc_exec_ctx *exec_ctx, void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel *c, grpc_subchannel *c
grpc_pollset *pollset) { GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
grpc_pollset_set_add_pollset(exec_ctx, c->pollset_set, pollset); gpr_atm old_refs;
old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF"));
if (old_refs == 1) {
grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(subchannel_destroy, c),
1);
} }
void grpc_subchannel_del_interested_party(grpc_exec_ctx *exec_ctx,
grpc_subchannel *c,
grpc_pollset *pollset) {
grpc_pollset_set_del_pollset(exec_ctx, c->pollset_set, pollset);
} }
static gpr_uint32 random_seed() { static gpr_uint32 random_seed() {
@ -293,10 +279,8 @@ static gpr_uint32 random_seed() {
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args) { grpc_subchannel_args *args) {
grpc_subchannel *c = gpr_malloc(sizeof(*c)); grpc_subchannel *c = gpr_malloc(sizeof(*c));
grpc_channel_element *parent_elem = grpc_channel_stack_last_element(
grpc_channel_get_channel_stack(args->master));
memset(c, 0, sizeof(*c)); memset(c, 0, sizeof(*c));
c->refs = 1; gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS);
c->connector = connector; c->connector = connector;
grpc_connector_ref(c->connector); grpc_connector_ref(c->connector);
c->num_filters = args->filter_count; c->num_filters = args->filter_count;
@ -305,13 +289,14 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
sizeof(grpc_channel_filter *) * c->num_filters); sizeof(grpc_channel_filter *) * c->num_filters);
c->addr = gpr_malloc(args->addr_len); c->addr = gpr_malloc(args->addr_len);
memcpy(c->addr, args->addr, args->addr_len); memcpy(c->addr, args->addr, args->addr_len);
grpc_pollset_set_init(&c->pollset_set);
c->addr_len = args->addr_len; c->addr_len = args->addr_len;
grpc_set_initial_connect_string(&c->addr, &c->addr_len, grpc_set_initial_connect_string(&c->addr, &c->addr_len,
&c->initial_connect_string); &c->initial_connect_string);
c->args = grpc_channel_args_copy(args->args); c->args = grpc_channel_args_copy(args->args);
c->master = args->master;
c->pollset_set = grpc_client_channel_get_connecting_pollset_set(parent_elem);
c->random = random_seed(); c->random = random_seed();
c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
&c->root_external_state_watcher;
grpc_closure_init(&c->connected, subchannel_connected, c); grpc_closure_init(&c->connected, subchannel_connected, c);
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE, grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
"subchannel"); "subchannel");
@ -319,70 +304,18 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
return c; return c;
} }
static void cancel_waiting_calls(grpc_exec_ctx *exec_ctx,
grpc_subchannel *subchannel,
int iomgr_success) {
waiting_for_connect *w4c;
gpr_mu_lock(&subchannel->mu);
w4c = subchannel->waiting;
subchannel->waiting = NULL;
gpr_mu_unlock(&subchannel->mu);
while (w4c != NULL) {
waiting_for_connect *next = w4c->next;
grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel,
w4c->pollset);
if (w4c->notify) {
w4c->notify->cb(exec_ctx, w4c->notify->cb_arg, iomgr_success);
}
GRPC_SUBCHANNEL_UNREF(exec_ctx, w4c->subchannel, "waiting_for_connect");
gpr_free(w4c);
w4c = next;
}
}
void grpc_subchannel_cancel_create_call(grpc_exec_ctx *exec_ctx,
grpc_subchannel *subchannel,
gpr_atm *target) {
waiting_for_connect *w4c;
int unref_count = 0;
gpr_mu_lock(&subchannel->mu);
w4c = subchannel->waiting;
subchannel->waiting = NULL;
while (w4c != NULL) {
waiting_for_connect *next = w4c->next;
if (w4c->target == target) {
grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel,
w4c->pollset);
grpc_exec_ctx_enqueue(exec_ctx, w4c->notify, 0);
unref_count++;
gpr_free(w4c);
} else {
w4c->next = subchannel->waiting;
subchannel->waiting = w4c;
}
w4c = next;
}
gpr_mu_unlock(&subchannel->mu);
while (unref_count-- > 0) {
GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannel, "waiting_for_connect");
}
}
static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
grpc_connect_in_args args; grpc_connect_in_args args;
args.interested_parties = c->pollset_set; args.interested_parties = &c->pollset_set;
args.addr = c->addr; args.addr = c->addr;
args.addr_len = c->addr_len; args.addr_len = c->addr_len;
args.deadline = compute_connect_deadline(c); args.deadline = compute_connect_deadline(c);
args.channel_args = c->args; args.channel_args = c->args;
args.initial_connect_string = c->initial_connect_string; args.initial_connect_string = c->initial_connect_string;
grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
GRPC_CHANNEL_CONNECTING, "state_change");
grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result, grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result,
&c->connected); &c->connected);
} }
@ -395,66 +328,6 @@ static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
continue_connect(exec_ctx, c); continue_connect(exec_ctx, c);
} }
static void continue_creating_call(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
int call_creation_finished_ok;
waiting_for_connect *w4c = arg;
grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel, w4c->pollset);
call_creation_finished_ok = grpc_subchannel_create_call(
exec_ctx, w4c->subchannel, w4c->pollset, w4c->target, w4c->notify);
GPR_ASSERT(call_creation_finished_ok == 1);
w4c->notify->cb(exec_ctx, w4c->notify->cb_arg, iomgr_success);
GRPC_SUBCHANNEL_UNREF(exec_ctx, w4c->subchannel, "waiting_for_connect");
gpr_free(w4c);
}
int grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
grpc_pollset *pollset, gpr_atm *target,
grpc_closure *notify) {
connection *con;
grpc_subchannel_call *call;
GPR_TIMER_BEGIN("grpc_subchannel_create_call", 0);
gpr_mu_lock(&c->mu);
if (c->active != NULL) {
con = c->active;
CONNECTION_REF_LOCKED(con, "call");
gpr_mu_unlock(&c->mu);
call = create_call(exec_ctx, con, pollset);
if (!gpr_atm_rel_cas(target, 0, (gpr_atm)(gpr_uintptr)call)) {
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "failed to set");
}
GPR_TIMER_END("grpc_subchannel_create_call", 0);
return 1;
} else {
waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c));
w4c->next = c->waiting;
w4c->notify = notify;
w4c->pollset = pollset;
w4c->target = target;
w4c->subchannel = c;
/* released when clearing w4c */
SUBCHANNEL_REF_LOCKED(c, "waiting_for_connect");
grpc_closure_init(&w4c->continuation, continue_creating_call, w4c);
c->waiting = w4c;
grpc_subchannel_add_interested_party(exec_ctx, c, pollset);
if (!c->connecting) {
c->connecting = 1;
connectivity_state_changed_locked(exec_ctx, c, "create_call");
/* released by connection */
SUBCHANNEL_REF_LOCKED(c, "connecting");
GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting");
gpr_mu_unlock(&c->mu);
start_connect(exec_ctx, c);
} else {
gpr_mu_unlock(&c->mu);
}
GPR_TIMER_END("grpc_subchannel_create_call", 0);
return 0;
}
}
grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) { grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) {
grpc_connectivity_state state; grpc_connectivity_state state;
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
@ -463,153 +336,138 @@ grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) {
return state; return state;
} }
void grpc_subchannel_notify_on_state_change(grpc_exec_ctx *exec_ctx, static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_subchannel *c, int success) {
grpc_connectivity_state *state, external_state_watcher *w = arg;
grpc_closure *follow_up = w->notify;
if (w->pollset_set != NULL) {
grpc_pollset_set_del_pollset_set(exec_ctx, &w->subchannel->pollset_set,
w->pollset_set);
}
gpr_mu_lock(&w->subchannel->mu);
w->next->prev = w->prev;
w->prev->next = w->next;
gpr_mu_unlock(&w->subchannel->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher");
gpr_free(w);
follow_up->cb(exec_ctx, follow_up->cb_arg, success);
}
void grpc_subchannel_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
grpc_closure *notify) { grpc_closure *notify) {
int do_connect = 0; int do_connect = 0;
external_state_watcher *w;
if (state == NULL) {
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
for (w = c->root_external_state_watcher.next;
w != &c->root_external_state_watcher; w = w->next) {
if (w->notify == notify) {
grpc_connectivity_state_notify_on_state_change(
exec_ctx, &c->state_tracker, NULL, &w->closure);
}
}
gpr_mu_unlock(&c->mu);
} else {
w = gpr_malloc(sizeof(*w));
w->subchannel = c;
w->pollset_set = interested_parties;
w->notify = notify;
grpc_closure_init(&w->closure, on_external_state_watcher_done, w);
if (interested_parties != NULL) {
grpc_pollset_set_add_pollset_set(exec_ctx, &c->pollset_set,
interested_parties);
}
GRPC_SUBCHANNEL_WEAK_REF(c, "external_state_watcher");
gpr_mu_lock(&c->mu);
w->next = &c->root_external_state_watcher;
w->prev = w->next->prev;
w->next->prev = w->prev->next = w;
if (grpc_connectivity_state_notify_on_state_change( if (grpc_connectivity_state_notify_on_state_change(
exec_ctx, &c->state_tracker, state, notify)) { exec_ctx, &c->state_tracker, state, &w->closure)) {
do_connect = 1; do_connect = 1;
c->connecting = 1; c->connecting = 1;
/* released by connection */ /* released by connection */
SUBCHANNEL_REF_LOCKED(c, "connecting"); GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting");
connectivity_state_changed_locked(exec_ctx, c, "state_change");
} }
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
}
if (do_connect) { if (do_connect) {
start_connect(exec_ctx, c); start_connect(exec_ctx, c);
} }
} }
int grpc_subchannel_state_change_unsubscribe(grpc_exec_ctx *exec_ctx, void grpc_connected_subchannel_process_transport_op(
grpc_subchannel *c, grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
grpc_closure *subscribed_notify) {
int success;
gpr_mu_lock(&c->mu);
success = grpc_connectivity_state_change_unsubscribe(
exec_ctx, &c->state_tracker, subscribed_notify);
gpr_mu_unlock(&c->mu);
return success;
}
void grpc_subchannel_process_transport_op(grpc_exec_ctx *exec_ctx,
grpc_subchannel *c,
grpc_transport_op *op) { grpc_transport_op *op) {
connection *con = NULL;
grpc_subchannel *destroy;
int cancel_alarm = 0;
gpr_mu_lock(&c->mu);
if (c->active != NULL) {
con = c->active;
CONNECTION_REF_LOCKED(con, "transport-op");
}
if (op->disconnect) {
c->disconnected = 1;
connectivity_state_changed_locked(exec_ctx, c, "disconnect");
if (c->have_alarm) {
cancel_alarm = 1;
}
}
gpr_mu_unlock(&c->mu);
if (con != NULL) {
grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con); grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con);
grpc_channel_element *top_elem = grpc_channel_element *top_elem = grpc_channel_stack_element(channel_stack, 0);
grpc_channel_stack_element(channel_stack, 0);
top_elem->filter->start_transport_op(exec_ctx, top_elem, op); top_elem->filter->start_transport_op(exec_ctx, top_elem, op);
gpr_mu_lock(&c->mu);
destroy = CONNECTION_UNREF_LOCKED(exec_ctx, con, "transport-op");
gpr_mu_unlock(&c->mu);
if (destroy) {
subchannel_destroy(exec_ctx, destroy);
}
} }
if (cancel_alarm) { static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
grpc_timer_cancel(exec_ctx, &c->alarm);
}
if (op->disconnect) {
grpc_connector_shutdown(exec_ctx, c->connector);
}
}
static void on_state_changed(grpc_exec_ctx *exec_ctx, void *p,
int iomgr_success) { int iomgr_success) {
state_watcher *sw = p; state_watcher *sw = p;
grpc_subchannel *c = sw->subchannel; grpc_subchannel *c = sw->subchannel;
gpr_mu *mu = &c->mu; gpr_mu *mu = &c->mu;
int destroy;
grpc_transport_op op;
grpc_channel_element *elem;
connection *destroy_connection = NULL;
gpr_mu_lock(mu); gpr_mu_lock(mu);
/* if we failed or there is a version number mismatch, just leave /* if we failed just leave this closure */
this closure */ if (iomgr_success) {
if (!iomgr_success || sw->subchannel->active_version != sw->version) { if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
goto done; /* any errors on a subchannel ==> we're done, create a new one */
} sw->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE;
switch (sw->connectivity_state) {
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_READY:
case GRPC_CHANNEL_IDLE:
/* all is still good: keep watching */
memset(&op, 0, sizeof(op));
op.connectivity_state = &sw->connectivity_state;
op.on_connectivity_state_change = &sw->closure;
elem = grpc_channel_stack_element(
CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
elem->filter->start_transport_op(exec_ctx, elem, &op);
/* early out */
gpr_mu_unlock(mu);
return;
case GRPC_CHANNEL_FATAL_FAILURE:
case GRPC_CHANNEL_TRANSIENT_FAILURE:
/* things have gone wrong, deactivate and enter idle */
if (sw->subchannel->active->refs == 0) {
destroy_connection = sw->subchannel->active;
} }
sw->subchannel->active = NULL;
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
c->disconnected sw->connectivity_state, "reflect_child");
? GRPC_CHANNEL_FATAL_FAILURE if (sw->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) {
: GRPC_CHANNEL_TRANSIENT_FAILURE, grpc_connected_subchannel_notify_on_state_change(
"connection_failed"); exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL,
break; &sw->connectivity_state, &sw->closure);
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
sw = NULL;
}
} }
done:
connectivity_state_changed_locked(exec_ctx, c, "transport_state_changed");
destroy = SUBCHANNEL_UNREF_LOCKED(c, "state_watcher");
gpr_free(sw);
gpr_mu_unlock(mu); gpr_mu_unlock(mu);
if (destroy) { GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "state_watcher");
subchannel_destroy(exec_ctx, c); gpr_free(sw);
} }
if (destroy_connection != NULL) {
connection_destroy(exec_ctx, destroy_connection); static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx,
grpc_connected_subchannel *con,
grpc_pollset_set *interested_parties,
grpc_connectivity_state *state,
grpc_closure *closure) {
grpc_transport_op op;
grpc_channel_element *elem;
memset(&op, 0, sizeof(op));
op.connectivity_state = state;
op.on_connectivity_state_change = closure;
op.bind_pollset_set = interested_parties;
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
elem->filter->start_transport_op(exec_ctx, elem, &op);
} }
void grpc_connected_subchannel_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
grpc_closure *closure) {
connected_subchannel_state_op(exec_ctx, con, interested_parties, state,
closure);
} }
static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
size_t channel_stack_size; size_t channel_stack_size;
connection *con; grpc_connected_subchannel *con;
grpc_channel_stack *stk; grpc_channel_stack *stk;
size_t num_filters; size_t num_filters;
const grpc_channel_filter **filters; const grpc_channel_filter **filters;
waiting_for_connect *w4c; state_watcher *sw_subchannel;
grpc_transport_op op;
state_watcher *sw;
connection *destroy_connection = NULL;
grpc_channel_element *elem;
/* build final filter list */ /* build final filter list */
num_filters = c->num_filters + c->connecting_result.num_filters + 1; num_filters = c->num_filters + c->connecting_result.num_filters + 1;
@ -621,74 +479,52 @@ static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
/* construct channel stack */ /* construct channel stack */
channel_stack_size = grpc_channel_stack_size(filters, num_filters); channel_stack_size = grpc_channel_stack_size(filters, num_filters);
con = gpr_malloc(sizeof(connection) + channel_stack_size); con = gpr_malloc(channel_stack_size);
stk = (grpc_channel_stack *)(con + 1); stk = CHANNEL_STACK_FROM_CONNECTION(con);
con->refs = 0; grpc_channel_stack_init(exec_ctx, 1, connection_destroy, con, filters,
con->subchannel = c; num_filters, c->args, "CONNECTED_SUBCHANNEL", stk);
grpc_channel_stack_init(exec_ctx, filters, num_filters, c->master, c->args,
stk);
grpc_connected_channel_bind_transport(stk, c->connecting_result.transport); grpc_connected_channel_bind_transport(stk, c->connecting_result.transport);
gpr_free((void *)c->connecting_result.filters); gpr_free((void *)c->connecting_result.filters);
memset(&c->connecting_result, 0, sizeof(c->connecting_result)); memset(&c->connecting_result, 0, sizeof(c->connecting_result));
/* initialize state watcher */ /* initialize state watcher */
sw = gpr_malloc(sizeof(*sw)); sw_subchannel = gpr_malloc(sizeof(*sw_subchannel));
grpc_closure_init(&sw->closure, on_state_changed, sw); sw_subchannel->subchannel = c;
sw->subchannel = c; sw_subchannel->connectivity_state = GRPC_CHANNEL_READY;
sw->connectivity_state = GRPC_CHANNEL_READY; grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed,
sw_subchannel);
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
if (c->disconnected) { if (c->disconnected) {
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
gpr_free(sw); gpr_free(sw_subchannel);
gpr_free((void *)filters); gpr_free((void *)filters);
grpc_channel_stack_destroy(exec_ctx, stk); grpc_channel_stack_destroy(exec_ctx, stk);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->master, "connecting"); gpr_free(con);
GRPC_SUBCHANNEL_UNREF(exec_ctx, c, "connecting"); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
return; return;
} }
/* publish */ /* publish */
if (c->active != NULL && c->active->refs == 0) { GPR_ASSERT(gpr_atm_no_barrier_cas(&c->connected_subchannel, 0, (gpr_atm)con));
destroy_connection = c->active;
}
c->active = con;
c->active_version++;
sw->version = c->active_version;
c->connecting = 0; c->connecting = 0;
/* watch for changes; subchannel ref for connecting is donated /* setup subchannel watching connected subchannel for changes; subchannel ref
for connecting is donated
to the state watcher */ to the state watcher */
memset(&op, 0, sizeof(op)); GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
op.connectivity_state = &sw->connectivity_state; GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
op.on_connectivity_state_change = &sw->closure; grpc_connected_subchannel_notify_on_state_change(
op.bind_pollset_set = c->pollset_set; exec_ctx, con, &c->pollset_set, &sw_subchannel->connectivity_state,
SUBCHANNEL_REF_LOCKED(c, "state_watcher"); &sw_subchannel->closure);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->master, "connecting");
GPR_ASSERT(!SUBCHANNEL_UNREF_LOCKED(c, "connecting"));
elem =
grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
elem->filter->start_transport_op(exec_ctx, elem, &op);
/* signal completion */ /* signal completion */
connectivity_state_changed_locked(exec_ctx, c, "connected"); grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY,
w4c = c->waiting; "connected");
c->waiting = NULL;
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
while (w4c != NULL) {
waiting_for_connect *next = w4c->next;
grpc_exec_ctx_enqueue(exec_ctx, &w4c->continuation, 1);
w4c = next;
}
gpr_free((void *)filters); gpr_free((void *)filters);
if (destroy_connection != NULL) {
connection_destroy(exec_ctx, destroy_connection);
}
} }
/* Generate a random number between 0 and 1. */ /* Generate a random number between 0 and 1. */
@ -742,29 +578,31 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, int iomgr_success) {
if (c->disconnected) { if (c->disconnected) {
iomgr_success = 0; iomgr_success = 0;
} }
connectivity_state_changed_locked(exec_ctx, c, "alarm");
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
if (iomgr_success) { if (iomgr_success) {
update_reconnect_parameters(c); update_reconnect_parameters(c);
continue_connect(exec_ctx, c); continue_connect(exec_ctx, c);
} else { } else {
cancel_waiting_calls(exec_ctx, c, iomgr_success); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->master, "connecting");
GRPC_SUBCHANNEL_UNREF(exec_ctx, c, "connecting");
} }
} }
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) { int iomgr_success) {
grpc_subchannel *c = arg; grpc_subchannel *c = arg;
if (c->connecting_result.transport != NULL) { if (c->connecting_result.transport != NULL) {
publish_transport(exec_ctx, c); publish_transport(exec_ctx, c);
} else if (c->disconnected) {
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
} else { } else {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
GPR_ASSERT(!c->have_alarm); GPR_ASSERT(!c->have_alarm);
c->have_alarm = 1; c->have_alarm = 1;
connectivity_state_changed_locked(exec_ctx, c, "connect_failed"); grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"connect_failed");
grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now); grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
} }
@ -781,29 +619,6 @@ static gpr_timespec compute_connect_deadline(grpc_subchannel *c) {
: min_deadline; : min_deadline;
} }
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) {
if (c->disconnected) {
return GRPC_CHANNEL_FATAL_FAILURE;
}
if (c->connecting) {
if (c->have_alarm) {
return GRPC_CHANNEL_TRANSIENT_FAILURE;
}
return GRPC_CHANNEL_CONNECTING;
}
if (c->active) {
return GRPC_CHANNEL_READY;
}
return GRPC_CHANNEL_IDLE;
}
static void connectivity_state_changed_locked(grpc_exec_ctx *exec_ctx,
grpc_subchannel *c,
const char *reason) {
grpc_connectivity_state current = compute_connectivity_locked(c);
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, current, reason);
}
/* /*
* grpc_subchannel_call implementation * grpc_subchannel_call implementation
*/ */
@ -811,37 +626,22 @@ static void connectivity_state_changed_locked(grpc_exec_ctx *exec_ctx,
static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call, static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
int success) { int success) {
grpc_subchannel_call *c = call; grpc_subchannel_call *c = call;
gpr_mu *mu = &c->connection->subchannel->mu;
grpc_subchannel *destroy;
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0); GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c)); grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
gpr_mu_lock(mu); GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call");
destroy = CONNECTION_UNREF_LOCKED(exec_ctx, c->connection, "call");
gpr_mu_unlock(mu);
gpr_free(c); gpr_free(c);
if (destroy != NULL) {
subchannel_destroy(exec_ctx, destroy);
}
GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0); GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
} }
void grpc_subchannel_call_ref(grpc_subchannel_call *c void grpc_subchannel_call_ref(grpc_subchannel_call *c
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
#ifdef GRPC_STREAM_REFCOUNT_DEBUG GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
grpc_call_stack_ref(SUBCHANNEL_CALL_TO_CALL_STACK(c), reason);
#else
grpc_call_stack_ref(SUBCHANNEL_CALL_TO_CALL_STACK(c));
#endif
} }
void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *c grpc_subchannel_call *c
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
#ifdef GRPC_STREAM_REFCOUNT_DEBUG GRPC_CALL_STACK_UNREF(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
grpc_call_stack_unref(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), reason);
#else
grpc_call_stack_unref(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
#endif
} }
char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx, char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx,
@ -859,24 +659,26 @@ void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
top_elem->filter->start_transport_stream_op(exec_ctx, top_elem, op); top_elem->filter->start_transport_stream_op(exec_ctx, top_elem, op);
} }
static grpc_subchannel_call *create_call(grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
connection *con, grpc_subchannel *c) {
return GET_CONNECTED_SUBCHANNEL(c, acq);
}
grpc_subchannel_call *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
grpc_pollset *pollset) { grpc_pollset *pollset) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
grpc_subchannel_call *call = grpc_subchannel_call *call =
gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call); grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call);
call->connection = con; call->connection = con;
GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, call, grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, call,
NULL, NULL, callstk); NULL, NULL, callstk);
grpc_call_stack_set_pollset(exec_ctx, callstk, pollset); grpc_call_stack_set_pollset(exec_ctx, callstk, pollset);
return call; return call;
} }
grpc_channel *grpc_subchannel_get_master(grpc_subchannel *subchannel) {
return subchannel->master;
}
grpc_call_stack *grpc_subchannel_call_get_call_stack( grpc_call_stack *grpc_subchannel_call_get_call_stack(
grpc_subchannel_call *subchannel_call) { grpc_subchannel_call *subchannel_call) {
return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call); return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call);

@ -41,6 +41,7 @@
/** A (sub-)channel that knows how to connect to exactly one target /** A (sub-)channel that knows how to connect to exactly one target
address. Provides a target for load balancing. */ address. Provides a target for load balancing. */
typedef struct grpc_subchannel grpc_subchannel; typedef struct grpc_subchannel grpc_subchannel;
typedef struct grpc_connected_subchannel grpc_connected_subchannel;
typedef struct grpc_subchannel_call grpc_subchannel_call; typedef struct grpc_subchannel_call grpc_subchannel_call;
typedef struct grpc_subchannel_args grpc_subchannel_args; typedef struct grpc_subchannel_args grpc_subchannel_args;
@ -49,6 +50,14 @@ typedef struct grpc_subchannel_args grpc_subchannel_args;
grpc_subchannel_ref((p), __FILE__, __LINE__, (r)) grpc_subchannel_ref((p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_UNREF(cl, p, r) \ #define GRPC_SUBCHANNEL_UNREF(cl, p, r) \
grpc_subchannel_unref((cl), (p), __FILE__, __LINE__, (r)) grpc_subchannel_unref((cl), (p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_WEAK_REF(p, r) \
grpc_subchannel_weak_ref((p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \
grpc_subchannel_weak_unref((cl), (p), __FILE__, __LINE__, (r))
#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) \
grpc_connected_subchannel_ref((p), __FILE__, __LINE__, (r))
#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \
grpc_connected_subchannel_unref((cl), (p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_CALL_REF(p, r) \ #define GRPC_SUBCHANNEL_CALL_REF(p, r) \
grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r)) grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \ #define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \
@ -58,6 +67,12 @@ typedef struct grpc_subchannel_args grpc_subchannel_args;
#else #else
#define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p)) #define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p))
#define GRPC_SUBCHANNEL_UNREF(cl, p, r) grpc_subchannel_unref((cl), (p)) #define GRPC_SUBCHANNEL_UNREF(cl, p, r) grpc_subchannel_unref((cl), (p))
#define GRPC_SUBCHANNEL_WEAK_REF(p, r) grpc_subchannel_weak_ref((p))
#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \
grpc_subchannel_weak_unref((cl), (p))
#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) grpc_connected_subchannel_ref((p))
#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \
grpc_connected_subchannel_unref((cl), (p))
#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p)) #define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p))
#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \ #define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \
grpc_subchannel_call_unref((cl), (p)) grpc_subchannel_call_unref((cl), (p))
@ -69,32 +84,30 @@ void grpc_subchannel_ref(grpc_subchannel *channel
void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel *channel grpc_subchannel *channel
GRPC_SUBCHANNEL_REF_EXTRA_ARGS); GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_weak_ref(grpc_subchannel *channel
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel *channel
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_connected_subchannel_ref(grpc_connected_subchannel *channel
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
grpc_connected_subchannel *channel
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_call_ref(grpc_subchannel_call *call void grpc_subchannel_call_ref(grpc_subchannel_call *call
GRPC_SUBCHANNEL_REF_EXTRA_ARGS); GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *call grpc_subchannel_call *call
GRPC_SUBCHANNEL_REF_EXTRA_ARGS); GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
/** construct a subchannel call (possibly asynchronously). /** construct a subchannel call */
* grpc_subchannel_call *grpc_connected_subchannel_create_call(
* If the returned status is 1, the call will return immediately and \a target grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
* will point to a connected \a subchannel_call instance. Note that \a notify grpc_pollset *pollset);
* will \em not be invoked in this case.
* Otherwise, if the returned status is 0, the subchannel call will be created
* asynchronously, invoking the \a notify callback upon completion. */
int grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx,
grpc_subchannel *subchannel,
grpc_pollset *pollset, gpr_atm *target,
grpc_closure *notify);
/** cancel \a call in the waiting state. */
void grpc_subchannel_cancel_create_call(grpc_exec_ctx *exec_ctx,
grpc_subchannel *subchannel,
gpr_atm *target);
/** process a transport level op */ /** process a transport level op */
void grpc_subchannel_process_transport_op(grpc_exec_ctx *exec_ctx, void grpc_connected_subchannel_process_transport_op(
grpc_subchannel *subchannel, grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *subchannel,
grpc_transport_op *op); grpc_transport_op *op);
/** poll the current connectivity state of a channel */ /** poll the current connectivity state of a channel */
@ -103,26 +116,19 @@ grpc_connectivity_state grpc_subchannel_check_connectivity(
/** call notify when the connectivity state of a channel changes from *state. /** call notify when the connectivity state of a channel changes from *state.
Updates *state with the new state of the channel */ Updates *state with the new state of the channel */
void grpc_subchannel_notify_on_state_change(grpc_exec_ctx *exec_ctx, void grpc_subchannel_notify_on_state_change(
grpc_subchannel *channel, grpc_exec_ctx *exec_ctx, grpc_subchannel *channel,
grpc_connectivity_state *state, grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
grpc_closure *notify);
void grpc_connected_subchannel_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *channel,
grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
grpc_closure *notify); grpc_closure *notify);
/** Remove \a subscribed_notify from the list of closures to be called on a /** retrieve the grpc_connected_subchannel - or NULL if called before
* state change if present, returning 1. Otherwise, nothing is done and return the subchannel becomes connected */
* 0. */ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
int grpc_subchannel_state_change_unsubscribe(grpc_exec_ctx *exec_ctx, grpc_subchannel *subchannel);
grpc_subchannel *channel,
grpc_closure *subscribed_notify);
/** express interest in \a channel's activities through \a pollset. */
void grpc_subchannel_add_interested_party(grpc_exec_ctx *exec_ctx,
grpc_subchannel *channel,
grpc_pollset *pollset);
/** stop following \a channel's activity through \a pollset. */
void grpc_subchannel_del_interested_party(grpc_exec_ctx *exec_ctx,
grpc_subchannel *channel,
grpc_pollset *pollset);
/** continue processing a transport op */ /** continue processing a transport op */
void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx, void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
@ -147,15 +153,10 @@ struct grpc_subchannel_args {
/** Address to connect to */ /** Address to connect to */
struct sockaddr *addr; struct sockaddr *addr;
size_t addr_len; size_t addr_len;
/** master channel */
grpc_channel *master;
}; };
/** create a subchannel given a connector */ /** create a subchannel given a connector */
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args); grpc_subchannel_args *args);
/** Return the master channel associated with the subchannel */
grpc_channel *grpc_subchannel_get_master(grpc_subchannel *subchannel);
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H */ #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H */

@ -53,6 +53,7 @@ typedef struct {
size_t next_address; size_t next_address;
grpc_endpoint *ep; grpc_endpoint *ep;
char *host; char *host;
char *ssl_host_override;
gpr_timespec deadline; gpr_timespec deadline;
int have_read_byte; int have_read_byte;
const grpc_httpcli_handshaker *handshaker; const grpc_httpcli_handshaker *handshaker;
@ -106,6 +107,7 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
} }
gpr_slice_unref(req->request_text); gpr_slice_unref(req->request_text);
gpr_free(req->host); gpr_free(req->host);
gpr_free(req->ssl_host_override);
grpc_iomgr_unregister_object(&req->iomgr_obj); grpc_iomgr_unregister_object(&req->iomgr_obj);
gpr_slice_buffer_destroy(&req->incoming); gpr_slice_buffer_destroy(&req->incoming);
gpr_slice_buffer_destroy(&req->outgoing); gpr_slice_buffer_destroy(&req->outgoing);
@ -180,7 +182,9 @@ static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
next_address(exec_ctx, req); next_address(exec_ctx, req);
return; return;
} }
req->handshaker->handshake(exec_ctx, req, req->ep, req->host, req->handshaker->handshake(
exec_ctx, req, req->ep,
req->ssl_host_override ? req->ssl_host_override : req->host,
on_handshake_done); on_handshake_done);
} }
@ -231,6 +235,7 @@ static void internal_request_begin(
gpr_slice_buffer_init(&req->outgoing); gpr_slice_buffer_init(&req->outgoing);
grpc_iomgr_register_object(&req->iomgr_obj, name); grpc_iomgr_register_object(&req->iomgr_obj, name);
req->host = gpr_strdup(request->host); req->host = gpr_strdup(request->host);
req->ssl_host_override = gpr_strdup(request->ssl_host_override);
grpc_pollset_set_add_pollset(exec_ctx, &req->context->pollset_set, grpc_pollset_set_add_pollset(exec_ctx, &req->context->pollset_set,
req->pollset); req->pollset);

@ -74,6 +74,8 @@ extern const grpc_httpcli_handshaker grpc_httpcli_ssl;
typedef struct grpc_httpcli_request { typedef struct grpc_httpcli_request {
/* The host name to connect to */ /* The host name to connect to */
char *host; char *host;
/* The host to verify in the SSL handshake (or NULL) */
char *ssl_host_override;
/* The path of the resource to fetch */ /* The path of the resource to fetch */
char *path; char *path;
/* Additional headers: count and key/values; the following are supplied /* Additional headers: count and key/values; the following are supplied

@ -43,6 +43,7 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#define CLOSURE_NOT_READY ((grpc_closure *)0) #define CLOSURE_NOT_READY ((grpc_closure *)0)
@ -158,7 +159,10 @@ void grpc_fd_global_shutdown(void) {
grpc_fd *grpc_fd_create(int fd, const char *name) { grpc_fd *grpc_fd_create(int fd, const char *name) {
grpc_fd *r = alloc_fd(fd); grpc_fd *r = alloc_fd(fd);
grpc_iomgr_register_object(&r->iomgr_object, name); char *name2;
gpr_asprintf(&name2, "%s fd=%d", name, fd);
grpc_iomgr_register_object(&r->iomgr_object, name2);
gpr_free(name2);
#ifdef GRPC_FD_REF_COUNT_DEBUG #ifdef GRPC_FD_REF_COUNT_DEBUG
gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, r, name); gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, r, name);
#endif #endif

@ -170,6 +170,7 @@ void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd); void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
/* Reference counting for fds */ /* Reference counting for fds */
/*#define GRPC_FD_REF_COUNT_DEBUG*/
#ifdef GRPC_FD_REF_COUNT_DEBUG #ifdef GRPC_FD_REF_COUNT_DEBUG
void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line); void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line);
void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, int line); void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, int line);

@ -57,5 +57,11 @@ void grpc_pollset_set_add_pollset(grpc_exec_ctx* exec_ctx,
void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx, void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *pollset_set, grpc_pollset_set *pollset_set,
grpc_pollset *pollset); grpc_pollset *pollset);
void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *bag,
grpc_pollset_set *item);
void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *bag,
grpc_pollset_set *item);
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */ #endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */

@ -52,9 +52,10 @@ void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {
size_t i; size_t i;
gpr_mu_destroy(&pollset_set->mu); gpr_mu_destroy(&pollset_set->mu);
for (i = 0; i < pollset_set->fd_count; i++) { for (i = 0; i < pollset_set->fd_count; i++) {
GRPC_FD_UNREF(pollset_set->fds[i], "pollset"); GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
} }
gpr_free(pollset_set->pollsets); gpr_free(pollset_set->pollsets);
gpr_free(pollset_set->pollset_sets);
gpr_free(pollset_set->fds); gpr_free(pollset_set->fds);
} }
@ -73,7 +74,7 @@ void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
pollset_set->pollsets[pollset_set->pollset_count++] = pollset; pollset_set->pollsets[pollset_set->pollset_count++] = pollset;
for (i = 0, j = 0; i < pollset_set->fd_count; i++) { for (i = 0, j = 0; i < pollset_set->fd_count; i++) {
if (grpc_fd_is_orphaned(pollset_set->fds[i])) { if (grpc_fd_is_orphaned(pollset_set->fds[i])) {
GRPC_FD_UNREF(pollset_set->fds[i], "pollset"); GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
} else { } else {
grpc_pollset_add_fd(exec_ctx, pollset, pollset_set->fds[i]); grpc_pollset_add_fd(exec_ctx, pollset, pollset_set->fds[i]);
pollset_set->fds[j++] = pollset_set->fds[i]; pollset_set->fds[j++] = pollset_set->fds[i];
@ -99,6 +100,46 @@ void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
gpr_mu_unlock(&pollset_set->mu); gpr_mu_unlock(&pollset_set->mu);
} }
void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *bag,
grpc_pollset_set *item) {
size_t i, j;
gpr_mu_lock(&bag->mu);
if (bag->pollset_set_count == bag->pollset_set_capacity) {
bag->pollset_set_capacity = GPR_MAX(8, 2 * bag->pollset_set_capacity);
bag->pollset_sets =
gpr_realloc(bag->pollset_sets,
bag->pollset_set_capacity * sizeof(*bag->pollset_sets));
}
bag->pollset_sets[bag->pollset_set_count++] = item;
for (i = 0, j = 0; i < bag->fd_count; i++) {
if (grpc_fd_is_orphaned(bag->fds[i])) {
GRPC_FD_UNREF(bag->fds[i], "pollset_set");
} else {
grpc_pollset_set_add_fd(exec_ctx, item, bag->fds[i]);
bag->fds[j++] = bag->fds[i];
}
}
bag->fd_count = j;
gpr_mu_unlock(&bag->mu);
}
void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *bag,
grpc_pollset_set *item) {
size_t i;
gpr_mu_lock(&bag->mu);
for (i = 0; i < bag->pollset_set_count; i++) {
if (bag->pollset_sets[i] == item) {
bag->pollset_set_count--;
GPR_SWAP(grpc_pollset_set *, bag->pollset_sets[i],
bag->pollset_sets[bag->pollset_set_count]);
break;
}
}
gpr_mu_unlock(&bag->mu);
}
void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx, void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *pollset_set, grpc_fd *fd) { grpc_pollset_set *pollset_set, grpc_fd *fd) {
size_t i; size_t i;
@ -113,6 +154,9 @@ void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
for (i = 0; i < pollset_set->pollset_count; i++) { for (i = 0; i < pollset_set->pollset_count; i++) {
grpc_pollset_add_fd(exec_ctx, pollset_set->pollsets[i], fd); grpc_pollset_add_fd(exec_ctx, pollset_set->pollsets[i], fd);
} }
for (i = 0; i < pollset_set->pollset_set_count; i++) {
grpc_pollset_set_add_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
}
gpr_mu_unlock(&pollset_set->mu); gpr_mu_unlock(&pollset_set->mu);
} }
@ -129,6 +173,9 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
break; break;
} }
} }
for (i = 0; i < pollset_set->pollset_set_count; i++) {
grpc_pollset_set_del_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
}
gpr_mu_unlock(&pollset_set->mu); gpr_mu_unlock(&pollset_set->mu);
} }

@ -44,6 +44,10 @@ typedef struct grpc_pollset_set {
size_t pollset_capacity; size_t pollset_capacity;
grpc_pollset **pollsets; grpc_pollset **pollsets;
size_t pollset_set_count;
size_t pollset_set_capacity;
struct grpc_pollset_set **pollset_sets;
size_t fd_count; size_t fd_count;
size_t fd_capacity; size_t fd_capacity;
grpc_fd **fds; grpc_fd **fds;

@ -49,4 +49,12 @@ void grpc_pollset_set_del_pollset(grpc_exec_ctx* exec_ctx,
grpc_pollset_set* pollset_set, grpc_pollset_set* pollset_set,
grpc_pollset* pollset) {} grpc_pollset* pollset) {}
void grpc_pollset_set_add_pollset_set(grpc_exec_ctx* exec_ctx,
grpc_pollset_set* bag,
grpc_pollset_set* item) {}
void grpc_pollset_set_del_pollset_set(grpc_exec_ctx* exec_ctx,
grpc_pollset_set* bag,
grpc_pollset_set* item) {}
#endif /* GPR_WINSOCK_SOCKET */ #endif /* GPR_WINSOCK_SOCKET */

@ -39,7 +39,7 @@
#include "src/core/channel/channel_args.h" #include "src/core/channel/channel_args.h"
#include "src/core/channel/http_client_filter.h" #include "src/core/channel/http_client_filter.h"
#include "src/core/httpcli/httpcli.h" #include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/iomgr.h" #include "src/core/iomgr/executor.h"
#include "src/core/json/json.h" #include "src/core/json/json.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include "src/core/surface/api_trace.h" #include "src/core/surface/api_trace.h"
@ -48,7 +48,6 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
/* -- Common. -- */ /* -- Common. -- */
@ -792,15 +791,14 @@ static void md_only_test_destruct(grpc_call_credentials *creds) {
grpc_credentials_md_store_unref(c->md_store); grpc_credentials_md_store_unref(c->md_store);
} }
static void on_simulated_token_fetch_done(void *user_data) { static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx,
void *user_data, int success) {
grpc_credentials_metadata_request *r = grpc_credentials_metadata_request *r =
(grpc_credentials_metadata_request *)user_data; (grpc_credentials_metadata_request *)user_data;
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds; grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; r->cb(exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries,
r->cb(&exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries,
GRPC_CREDENTIALS_OK); GRPC_CREDENTIALS_OK);
grpc_credentials_metadata_request_destroy(r); grpc_credentials_metadata_request_destroy(r);
grpc_exec_ctx_finish(&exec_ctx);
} }
static void md_only_test_get_request_metadata( static void md_only_test_get_request_metadata(
@ -810,10 +808,10 @@ static void md_only_test_get_request_metadata(
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
if (c->is_async) { if (c->is_async) {
gpr_thd_id thd_id;
grpc_credentials_metadata_request *cb_arg = grpc_credentials_metadata_request *cb_arg =
grpc_credentials_metadata_request_create(creds, cb, user_data); grpc_credentials_metadata_request_create(creds, cb, user_data);
gpr_thd_new(&thd_id, on_simulated_token_fetch_done, cb_arg, NULL); grpc_executor_enqueue(
grpc_closure_create(on_simulated_token_fetch_done, cb_arg), 1);
} else { } else {
cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK); cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK);
} }

@ -62,11 +62,13 @@ struct gpr_cmdline {
void (*extra_arg)(void *user_data, const char *arg); void (*extra_arg)(void *user_data, const char *arg);
void *extra_arg_user_data; void *extra_arg_user_data;
void (*state)(gpr_cmdline *cl, char *arg); int (*state)(gpr_cmdline *cl, char *arg);
arg *cur_arg; arg *cur_arg;
int survive_failure;
}; };
static void normal_state(gpr_cmdline *cl, char *arg); static int normal_state(gpr_cmdline *cl, char *arg);
gpr_cmdline *gpr_cmdline_create(const char *description) { gpr_cmdline *gpr_cmdline_create(const char *description) {
gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline)); gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline));
@ -78,6 +80,10 @@ gpr_cmdline *gpr_cmdline_create(const char *description) {
return cl; return cl;
} }
void gpr_cmdline_set_survive_failure(gpr_cmdline *cl) {
cl->survive_failure = 1;
}
void gpr_cmdline_destroy(gpr_cmdline *cl) { void gpr_cmdline_destroy(gpr_cmdline *cl) {
while (cl->args) { while (cl->args) {
arg *a = cl->args; arg *a = cl->args;
@ -185,16 +191,22 @@ char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0) {
return tmp; return tmp;
} }
static void print_usage_and_die(gpr_cmdline *cl) { static int print_usage_and_die(gpr_cmdline *cl) {
char *usage = gpr_cmdline_usage_string(cl, cl->argv0); char *usage = gpr_cmdline_usage_string(cl, cl->argv0);
fprintf(stderr, "%s", usage); fprintf(stderr, "%s", usage);
gpr_free(usage); gpr_free(usage);
if (!cl->survive_failure) {
exit(1); exit(1);
} }
return 0;
}
static void extra_state(gpr_cmdline *cl, char *str) { static int extra_state(gpr_cmdline *cl, char *str) {
if (!cl->extra_arg) print_usage_and_die(cl); if (!cl->extra_arg) {
return print_usage_and_die(cl);
}
cl->extra_arg(cl->extra_arg_user_data, str); cl->extra_arg(cl->extra_arg_user_data, str);
return 1;
} }
static arg *find_arg(gpr_cmdline *cl, char *name) { static arg *find_arg(gpr_cmdline *cl, char *name) {
@ -208,13 +220,13 @@ static arg *find_arg(gpr_cmdline *cl, char *name) {
if (!a) { if (!a) {
fprintf(stderr, "Unknown argument: %s\n", name); fprintf(stderr, "Unknown argument: %s\n", name);
print_usage_and_die(cl); return NULL;
} }
return a; return a;
} }
static void value_state(gpr_cmdline *cl, char *str) { static int value_state(gpr_cmdline *cl, char *str) {
long intval; long intval;
char *end; char *end;
@ -226,7 +238,7 @@ static void value_state(gpr_cmdline *cl, char *str) {
if (*end || intval < INT_MIN || intval > INT_MAX) { if (*end || intval < INT_MIN || intval > INT_MAX) {
fprintf(stderr, "expected integer, got '%s' for %s\n", str, fprintf(stderr, "expected integer, got '%s' for %s\n", str,
cl->cur_arg->name); cl->cur_arg->name);
print_usage_and_die(cl); return print_usage_and_die(cl);
} }
*(int *)cl->cur_arg->value = (int)intval; *(int *)cl->cur_arg->value = (int)intval;
break; break;
@ -238,7 +250,7 @@ static void value_state(gpr_cmdline *cl, char *str) {
} else { } else {
fprintf(stderr, "expected boolean, got '%s' for %s\n", str, fprintf(stderr, "expected boolean, got '%s' for %s\n", str,
cl->cur_arg->name); cl->cur_arg->name);
print_usage_and_die(cl); return print_usage_and_die(cl);
} }
break; break;
case ARGTYPE_STRING: case ARGTYPE_STRING:
@ -247,16 +259,18 @@ static void value_state(gpr_cmdline *cl, char *str) {
} }
cl->state = normal_state; cl->state = normal_state;
return 1;
} }
static void normal_state(gpr_cmdline *cl, char *str) { static int normal_state(gpr_cmdline *cl, char *str) {
char *eq = NULL; char *eq = NULL;
char *tmp = NULL; char *tmp = NULL;
char *arg_name = NULL; char *arg_name = NULL;
int r = 1;
if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") || if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") ||
0 == strcmp(str, "-h")) { 0 == strcmp(str, "-h")) {
print_usage_and_die(cl); return print_usage_and_die(cl);
} }
cl->cur_arg = NULL; cl->cur_arg = NULL;
@ -266,7 +280,7 @@ static void normal_state(gpr_cmdline *cl, char *str) {
if (str[2] == 0) { if (str[2] == 0) {
/* handle '--' to move to just extra args */ /* handle '--' to move to just extra args */
cl->state = extra_state; cl->state = extra_state;
return; return 1;
} }
str += 2; str += 2;
} else { } else {
@ -277,12 +291,15 @@ static void normal_state(gpr_cmdline *cl, char *str) {
/* str is of the form '--no-foo' - it's a flag disable */ /* str is of the form '--no-foo' - it's a flag disable */
str += 3; str += 3;
cl->cur_arg = find_arg(cl, str); cl->cur_arg = find_arg(cl, str);
if (cl->cur_arg == NULL) {
return print_usage_and_die(cl);
}
if (cl->cur_arg->type != ARGTYPE_BOOL) { if (cl->cur_arg->type != ARGTYPE_BOOL) {
fprintf(stderr, "%s is not a flag argument\n", str); fprintf(stderr, "%s is not a flag argument\n", str);
print_usage_and_die(cl); return print_usage_and_die(cl);
} }
*(int *)cl->cur_arg->value = 0; *(int *)cl->cur_arg->value = 0;
return; /* early out */ return 1; /* early out */
} }
eq = strchr(str, '='); eq = strchr(str, '=');
if (eq != NULL) { if (eq != NULL) {
@ -294,9 +311,12 @@ static void normal_state(gpr_cmdline *cl, char *str) {
arg_name = str; arg_name = str;
} }
cl->cur_arg = find_arg(cl, arg_name); cl->cur_arg = find_arg(cl, arg_name);
if (cl->cur_arg == NULL) {
return print_usage_and_die(cl);
}
if (eq != NULL) { if (eq != NULL) {
/* str was of the type --foo=value, parse the value */ /* str was of the type --foo=value, parse the value */
value_state(cl, eq + 1); r = value_state(cl, eq + 1);
} else if (cl->cur_arg->type != ARGTYPE_BOOL) { } else if (cl->cur_arg->type != ARGTYPE_BOOL) {
/* flag types don't have a '--foo value' variant, other types do */ /* flag types don't have a '--foo value' variant, other types do */
cl->state = value_state; cl->state = value_state;
@ -305,19 +325,23 @@ static void normal_state(gpr_cmdline *cl, char *str) {
*(int *)cl->cur_arg->value = 1; *(int *)cl->cur_arg->value = 1;
} }
} else { } else {
extra_state(cl, str); r = extra_state(cl, str);
} }
gpr_free(tmp); gpr_free(tmp);
return r;
} }
void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) { int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) {
int i; int i;
GPR_ASSERT(argc >= 1); GPR_ASSERT(argc >= 1);
cl->argv0 = argv[0]; cl->argv0 = argv[0];
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
cl->state(cl, argv[i]); if (!cl->state(cl, argv[i])) {
return 0;
}
} }
return 1;
} }

@ -341,21 +341,18 @@ grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) {
} }
#ifdef GRPC_STREAM_REFCOUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_call_internal_ref(grpc_call *c, const char *reason) { #define REF_REASON reason
grpc_call_stack_ref(CALL_STACK_FROM_CALL(c), reason); #define REF_ARG , const char *reason
}
void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c,
const char *reason) {
grpc_call_stack_unref(exec_ctx, CALL_STACK_FROM_CALL(c), reason);
}
#else #else
void grpc_call_internal_ref(grpc_call *c) { #define REF_REASON ""
grpc_call_stack_ref(CALL_STACK_FROM_CALL(c)); #define REF_ARG
#endif
void grpc_call_internal_ref(grpc_call *c REF_ARG) {
GRPC_CALL_STACK_REF(CALL_STACK_FROM_CALL(c), REF_REASON);
} }
void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c) { void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) {
grpc_call_stack_unref(exec_ctx, CALL_STACK_FROM_CALL(c)); GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
} }
#endif
static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, int success) { static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, int success) {
size_t i; size_t i;
@ -742,8 +739,15 @@ static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
char *grpc_call_get_peer(grpc_call *call) { char *grpc_call_get_peer(grpc_call *call) {
grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0); grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
char *result = elem->filter->get_peer(&exec_ctx, elem); char *result;
GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call)); GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
result = elem->filter->get_peer(&exec_ctx, elem);
if (result == NULL) {
result = grpc_channel_get_target(call->channel);
}
if (result == NULL) {
result = gpr_strdup("unknown");
}
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
return result; return result;
} }

@ -63,7 +63,6 @@ typedef struct registered_call {
struct grpc_channel { struct grpc_channel {
int is_client; int is_client;
gpr_refcount refs;
gpr_uint32 max_message_length; gpr_uint32 max_message_length;
grpc_mdelem *default_authority; grpc_mdelem *default_authority;
@ -81,6 +80,8 @@ struct grpc_channel {
/* the protobuf library will (by default) start warning at 100megs */ /* the protobuf library will (by default) start warning at 100megs */
#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024) #define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024)
static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, int success);
grpc_channel *grpc_channel_create_from_filters( grpc_channel *grpc_channel_create_from_filters(
grpc_exec_ctx *exec_ctx, const char *target, grpc_exec_ctx *exec_ctx, const char *target,
const grpc_channel_filter **filters, size_t num_filters, const grpc_channel_filter **filters, size_t num_filters,
@ -93,8 +94,6 @@ grpc_channel *grpc_channel_create_from_filters(
channel->target = gpr_strdup(target); channel->target = gpr_strdup(target);
GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
channel->is_client = is_client; channel->is_client = is_client;
/* decremented by grpc_channel_destroy */
gpr_ref_init(&channel->refs, 1);
gpr_mu_init(&channel->registered_call_mu); gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = NULL; channel->registered_calls = NULL;
@ -153,7 +152,9 @@ grpc_channel *grpc_channel_create_from_filters(
gpr_free(default_authority); gpr_free(default_authority);
} }
grpc_channel_stack_init(exec_ctx, filters, num_filters, channel, args, grpc_channel_stack_init(exec_ctx, 1, destroy_channel, channel, filters,
num_filters, args,
is_client ? "CLIENT_CHANNEL" : "SERVER_CHANNEL",
CHANNEL_STACK_FROM_CHANNEL(channel)); CHANNEL_STACK_FROM_CHANNEL(channel));
return channel; return channel;
@ -250,17 +251,25 @@ grpc_call *grpc_channel_create_registered_call(
rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline); rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
} }
#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_channel_internal_ref(grpc_channel *c, const char *reason) { #define REF_REASON reason
gpr_log(GPR_DEBUG, "CHANNEL: ref %p %d -> %d [%s]", c, c->refs.count, #define REF_ARG , const char *reason
c->refs.count + 1, reason);
#else #else
void grpc_channel_internal_ref(grpc_channel *c) { #define REF_REASON ""
#define REF_ARG
#endif #endif
gpr_ref(&c->refs); void grpc_channel_internal_ref(grpc_channel *c REF_ARG) {
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
} }
static void destroy_channel(grpc_exec_ctx *exec_ctx, grpc_channel *channel) { void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
grpc_channel *c REF_ARG) {
GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
}
static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
grpc_channel *channel = arg;
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel)); grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel));
while (channel->registered_calls) { while (channel->registered_calls) {
registered_call *rc = channel->registered_calls; registered_call *rc = channel->registered_calls;
@ -279,20 +288,6 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, grpc_channel *channel) {
gpr_free(channel); gpr_free(channel);
} }
#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
const char *reason) {
gpr_log(GPR_DEBUG, "CHANNEL: unref %p %d -> %d [%s]", channel,
channel->refs.count, channel->refs.count - 1, reason);
#else
void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
grpc_channel *channel) {
#endif
if (gpr_unref(&channel->refs)) {
destroy_channel(exec_ctx, channel);
}
}
void grpc_channel_destroy(grpc_channel *channel) { void grpc_channel_destroy(grpc_channel *channel) {
grpc_transport_op op; grpc_transport_op op;
grpc_channel_element *elem; grpc_channel_element *elem;

@ -53,7 +53,7 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
int status_code); int status_code);
gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel); gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);
#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_channel_internal_ref(grpc_channel *channel, const char *reason); void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel, void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
const char *reason); const char *reason);

@ -83,7 +83,6 @@ typedef struct {
gpr_mu mu; gpr_mu mu;
callback_phase phase; callback_phase phase;
int success; int success;
int removed;
grpc_closure on_complete; grpc_closure on_complete;
grpc_timer alarm; grpc_timer alarm;
grpc_connectivity_state state; grpc_connectivity_state state;
@ -135,30 +134,15 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
int due_to_completion) { int due_to_completion) {
int delete = 0; int delete = 0;
grpc_channel_element *client_channel_elem = NULL;
gpr_mu_lock(&w->mu);
if (w->removed == 0) {
w->removed = 1;
client_channel_elem = grpc_channel_stack_last_element(
grpc_channel_get_channel_stack(w->channel));
if (client_channel_elem->filter == &grpc_client_channel_filter) {
grpc_client_channel_del_interested_party(exec_ctx, client_channel_elem,
grpc_cq_pollset(w->cq));
} else {
grpc_client_uchannel_del_interested_party(exec_ctx, client_channel_elem,
grpc_cq_pollset(w->cq));
}
}
gpr_mu_unlock(&w->mu);
if (due_to_completion) { if (due_to_completion) {
gpr_mu_lock(&w->mu);
w->success = 1;
gpr_mu_unlock(&w->mu);
grpc_timer_cancel(exec_ctx, &w->alarm); grpc_timer_cancel(exec_ctx, &w->alarm);
} }
gpr_mu_lock(&w->mu); gpr_mu_lock(&w->mu);
if (due_to_completion) {
w->success = 1;
}
switch (w->phase) { switch (w->phase) {
case WAITING: case WAITING:
w->phase = CALLING_BACK; w->phase = CALLING_BACK;
@ -212,7 +196,6 @@ void grpc_channel_watch_connectivity_state(
w->phase = WAITING; w->phase = WAITING;
w->state = last_observed_state; w->state = last_observed_state;
w->success = 0; w->success = 0;
w->removed = 0;
w->cq = cq; w->cq = cq;
w->tag = tag; w->tag = tag;
w->channel = channel; w->channel = channel;
@ -223,16 +206,14 @@ void grpc_channel_watch_connectivity_state(
if (client_channel_elem->filter == &grpc_client_channel_filter) { if (client_channel_elem->filter == &grpc_client_channel_filter) {
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity"); GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
grpc_client_channel_add_interested_party(&exec_ctx, client_channel_elem,
grpc_cq_pollset(cq));
grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem, grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem,
&w->state, &w->on_complete); grpc_cq_pollset(cq), &w->state,
&w->on_complete);
} else if (client_channel_elem->filter == &grpc_client_uchannel_filter) { } else if (client_channel_elem->filter == &grpc_client_uchannel_filter) {
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_uchannel_connectivity"); GRPC_CHANNEL_INTERNAL_REF(channel, "watch_uchannel_connectivity");
grpc_client_uchannel_add_interested_party(&exec_ctx, client_channel_elem,
grpc_cq_pollset(cq));
grpc_client_uchannel_watch_connectivity_state( grpc_client_uchannel_watch_connectivity_state(
&exec_ctx, client_channel_elem, &w->state, &w->on_complete); &exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state,
&w->on_complete);
} }
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);

@ -171,7 +171,6 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
c->base.vtable = &connector_vtable; c->base.vtable = &connector_vtable;
gpr_ref_init(&c->refs, 1); gpr_ref_init(&c->refs, 1);
args->args = final_args; args->args = final_args;
args->master = f->master;
s = grpc_subchannel_create(&c->base, args); s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(exec_ctx, &c->base); grpc_connector_unref(exec_ctx, &c->base);
grpc_channel_args_destroy(final_args); grpc_channel_args_destroy(final_args);

@ -49,7 +49,6 @@ typedef struct {
} call_data; } call_data;
typedef struct { typedef struct {
grpc_channel *master;
grpc_status_code error_code; grpc_status_code error_code;
const char *error_message; const char *error_message;
} channel_data; } channel_data;
@ -84,8 +83,7 @@ static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
} }
static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
channel_data *chand = elem->channel_data; return NULL;
return grpc_channel_get_target(chand->master);
} }
static void lame_start_transport_op(grpc_exec_ctx *exec_ctx, static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
@ -111,10 +109,8 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
static void init_channel_elem(grpc_exec_ctx *exec_ctx, static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem, grpc_channel_element *elem,
grpc_channel_element_args *args) { grpc_channel_element_args *args) {
channel_data *chand = elem->channel_data;
GPR_ASSERT(args->is_first); GPR_ASSERT(args->is_first);
GPR_ASSERT(args->is_last); GPR_ASSERT(args->is_last);
chand->master = args->master;
} }
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,

@ -228,7 +228,6 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
gpr_mu_init(&c->mu); gpr_mu_init(&c->mu);
gpr_ref_init(&c->refs, 1); gpr_ref_init(&c->refs, 1);
args->args = final_args; args->args = final_args;
args->master = f->master;
s = grpc_subchannel_create(&c->base, args); s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(exec_ctx, &c->base); grpc_connector_unref(exec_ctx, &c->base);
grpc_channel_args_destroy(final_args); grpc_channel_args_destroy(final_args);

@ -101,9 +101,7 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
} }
tcp = grpc_tcp_server_create(); tcp = grpc_tcp_server_create();
if (!tcp) { GPR_ASSERT(tcp);
goto error;
}
for (i = 0; i < resolved->naddrs; i++) { for (i = 0; i < resolved->naddrs; i++) {
grpc_tcp_listener *listener; grpc_tcp_listener *listener;

@ -910,7 +910,7 @@ static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1); grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1);
if (op->on_connectivity_state_change) { if (op->on_connectivity_state_change != NULL) {
grpc_connectivity_state_notify_on_state_change( grpc_connectivity_state_notify_on_state_change(
exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state, exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state,
op->on_connectivity_state_change); op->on_connectivity_state_change);

@ -87,7 +87,7 @@ void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx,
grpc_connectivity_state grpc_connectivity_state_check( grpc_connectivity_state grpc_connectivity_state_check(
grpc_connectivity_state_tracker *tracker) { grpc_connectivity_state_tracker *tracker) {
if (grpc_connectivity_state_trace) { if (grpc_connectivity_state_trace) {
gpr_log(GPR_DEBUG, "CONWATCH: %s: get %s", tracker->name, gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
grpc_connectivity_state_name(tracker->current_state)); grpc_connectivity_state_name(tracker->current_state));
} }
return tracker->current_state; return tracker->current_state;
@ -97,42 +97,47 @@ int grpc_connectivity_state_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state *current, grpc_closure *notify) { grpc_connectivity_state *current, grpc_closure *notify) {
if (grpc_connectivity_state_trace) { if (grpc_connectivity_state_trace) {
gpr_log(GPR_DEBUG, "CONWATCH: %s: from %s [cur=%s] notify=%p", if (current == NULL) {
gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
tracker->name, notify);
} else {
gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker,
tracker->name, grpc_connectivity_state_name(*current), tracker->name, grpc_connectivity_state_name(*current),
grpc_connectivity_state_name(tracker->current_state), notify); grpc_connectivity_state_name(tracker->current_state), notify);
} }
if (tracker->current_state != *current) {
*current = tracker->current_state;
grpc_exec_ctx_enqueue(exec_ctx, notify, 1);
} else {
grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
w->current = current;
w->notify = notify;
w->next = tracker->watchers;
tracker->watchers = w;
}
return tracker->current_state == GRPC_CHANNEL_IDLE;
} }
if (current == NULL) {
int grpc_connectivity_state_change_unsubscribe(
grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
grpc_closure *subscribed_notify) {
grpc_connectivity_state_watcher *w = tracker->watchers; grpc_connectivity_state_watcher *w = tracker->watchers;
if (w != NULL && w->notify == subscribed_notify) { if (w != NULL && w->notify == notify) {
grpc_exec_ctx_enqueue(exec_ctx, notify, 0);
tracker->watchers = w->next; tracker->watchers = w->next;
gpr_free(w); gpr_free(w);
return 1; return 0;
} }
while (w != NULL) { while (w != NULL) {
grpc_connectivity_state_watcher *rm_candidate = w->next; grpc_connectivity_state_watcher *rm_candidate = w->next;
if (rm_candidate != NULL && rm_candidate->notify == subscribed_notify) { if (rm_candidate != NULL && rm_candidate->notify == notify) {
grpc_exec_ctx_enqueue(exec_ctx, notify, 0);
w->next = w->next->next; w->next = w->next->next;
gpr_free(rm_candidate); gpr_free(rm_candidate);
return 1; return 0;
} }
w = w->next; w = w->next;
} }
return 0; return 0;
} else {
if (tracker->current_state != *current) {
*current = tracker->current_state;
grpc_exec_ctx_enqueue(exec_ctx, notify, 1);
} else {
grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
w->current = current;
w->notify = notify;
w->next = tracker->watchers;
tracker->watchers = w;
}
return tracker->current_state == GRPC_CHANNEL_IDLE;
}
} }
void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
@ -141,7 +146,7 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
const char *reason) { const char *reason) {
grpc_connectivity_state_watcher *w; grpc_connectivity_state_watcher *w;
if (grpc_connectivity_state_trace) { if (grpc_connectivity_state_trace) {
gpr_log(GPR_DEBUG, "SET: %s: %s --> %s [%s]", tracker->name, gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s]", tracker, tracker->name,
grpc_connectivity_state_name(tracker->current_state), grpc_connectivity_state_name(tracker->current_state),
grpc_connectivity_state_name(state), reason); grpc_connectivity_state_name(state), reason);
} }

@ -75,16 +75,11 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
grpc_connectivity_state grpc_connectivity_state_check( grpc_connectivity_state grpc_connectivity_state_check(
grpc_connectivity_state_tracker *tracker); grpc_connectivity_state_tracker *tracker);
/** Return 1 if the channel should start connecting, 0 otherwise */ /** Return 1 if the channel should start connecting, 0 otherwise.
If current==NULL cancel notify if it is already queued (success==0 in that
case) */
int grpc_connectivity_state_notify_on_state_change( int grpc_connectivity_state_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker, grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state *current, grpc_closure *notify); grpc_connectivity_state *current, grpc_closure *notify);
/** Remove \a subscribed_notify from the list of closures to be called on a
* state change if present, returning 1. Otherwise, nothing is done and return
* 0. */
int grpc_connectivity_state_change_unsubscribe(
grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
grpc_closure *subscribed_notify);
#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H */ #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H */

@ -711,7 +711,7 @@ int grpc_mdstr_is_legal_header(grpc_mdstr *s) {
int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s) { int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s) {
static const gpr_uint8 legal_header_bits[256 / 8] = { static const gpr_uint8 legal_header_bits[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
return conforms_to(s, legal_header_bits); return conforms_to(s, legal_header_bits);

@ -65,92 +65,23 @@ const gpr_uint8
80, 81, 82, 33, 83, 33, 84, 33, 85, 33, 86, 33}; 80, 81, 82, 33, 83, 33, 84, 33, 85, 33, 86, 33};
const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = { const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
"0", "0", "1", "2", "200", "204", "206", "304", "400", "404", "500", "accept",
"1", "accept-charset", "accept-encoding", "accept-language", "accept-ranges",
"2", "access-control-allow-origin", "age", "allow", "application/grpc",
"200", ":authority", "authorization", "cache-control", "content-disposition",
"204", "content-encoding", "content-language", "content-length",
"206", "content-location", "content-range", "content-type", "cookie", "date",
"304", "deflate", "deflate,gzip", "", "etag", "expect", "expires", "from", "GET",
"400", "grpc", "grpc-accept-encoding", "grpc-encoding",
"404", "grpc-internal-encoding-request", "grpc-message", "grpc-status",
"500", "grpc-timeout", "gzip", "gzip, deflate", "host", "http", "https",
"accept", "identity", "identity,deflate", "identity,deflate,gzip", "identity,gzip",
"accept-charset", "if-match", "if-modified-since", "if-none-match", "if-range",
"accept-encoding", "if-unmodified-since", "last-modified", "link", "location", "max-forwards",
"accept-language", ":method", ":path", "POST", "proxy-authenticate", "proxy-authorization",
"accept-ranges", "range", "referer", "refresh", "retry-after", ":scheme", "server",
"access-control-allow-origin", "set-cookie", "/", "/index.html", ":status", "strict-transport-security",
"age", "te", "trailers", "transfer-encoding", "user-agent", "vary", "via",
"allow",
"application/grpc",
":authority",
"authorization",
"cache-control",
"content-disposition",
"content-encoding",
"content-language",
"content-length",
"content-location",
"content-range",
"content-type",
"cookie",
"date",
"deflate",
"deflate,gzip",
"",
"etag",
"expect",
"expires",
"from",
"GET",
"grpc",
"grpc-accept-encoding",
"grpc-encoding",
"grpc-internal-encoding-request",
"grpc-message",
"grpc-status",
"grpc-timeout",
"gzip",
"gzip, deflate",
"host",
"http",
"https",
"identity",
"identity,deflate",
"identity,deflate,gzip",
"identity,gzip",
"if-match",
"if-modified-since",
"if-none-match",
"if-range",
"if-unmodified-since",
"last-modified",
"link",
"location",
"max-forwards",
":method",
":path",
"POST",
"proxy-authenticate",
"proxy-authorization",
"range",
"referer",
"refresh",
"retry-after",
":scheme",
"server",
"set-cookie",
"/",
"/index.html",
":status",
"strict-transport-security",
"te",
"trailers",
"transfer-encoding",
"user-agent",
"vary",
"via",
"www-authenticate"}; "www-authenticate"};
const gpr_uint8 grpc_static_accept_encoding_metadata[8] = {0, 29, 26, 30, const gpr_uint8 grpc_static_accept_encoding_metadata[8] = {0, 29, 26, 30,

@ -40,8 +40,8 @@
#ifdef GRPC_STREAM_REFCOUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) { void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) {
gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
gpr_log(GPR_DEBUG, "STREAM %p:%p REF %d->%d %s", refcount, gpr_log(GPR_DEBUG, "%s %p:%p REF %d->%d %s", refcount->object_type,
refcount->destroy.cb_arg, val, val + 1, reason); refcount, refcount->destroy.cb_arg, val, val + 1, reason);
#else #else
void grpc_stream_ref(grpc_stream_refcount *refcount) { void grpc_stream_ref(grpc_stream_refcount *refcount) {
#endif #endif
@ -52,8 +52,8 @@ void grpc_stream_ref(grpc_stream_refcount *refcount) {
void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount, void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount,
const char *reason) { const char *reason) {
gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count); gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
gpr_log(GPR_DEBUG, "STREAM %p:%p UNREF %d->%d %s", refcount, gpr_log(GPR_DEBUG, "%s %p:%p UNREF %d->%d %s", refcount->object_type,
refcount->destroy.cb_arg, val, val - 1, reason); refcount, refcount->destroy.cb_arg, val, val - 1, reason);
#else #else
void grpc_stream_unref(grpc_exec_ctx *exec_ctx, void grpc_stream_unref(grpc_exec_ctx *exec_ctx,
grpc_stream_refcount *refcount) { grpc_stream_refcount *refcount) {
@ -63,6 +63,19 @@ void grpc_stream_unref(grpc_exec_ctx *exec_ctx,
} }
} }
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
grpc_iomgr_cb_func cb, void *cb_arg,
const char *object_type) {
refcount->object_type = object_type;
#else
void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
grpc_iomgr_cb_func cb, void *cb_arg) {
#endif
gpr_ref_init(&refcount->refs, initial_refs);
grpc_closure_init(&refcount->destroy, cb, cb_arg);
}
size_t grpc_transport_stream_size(grpc_transport *transport) { size_t grpc_transport_stream_size(grpc_transport *transport) {
return transport->vtable->sizeof_stream; return transport->vtable->sizeof_stream;
} }

@ -50,19 +50,32 @@ typedef struct grpc_transport grpc_transport;
for a stream. */ for a stream. */
typedef struct grpc_stream grpc_stream; typedef struct grpc_stream grpc_stream;
/*#define GRPC_STREAM_REFCOUNT_DEBUG*/
typedef struct grpc_stream_refcount { typedef struct grpc_stream_refcount {
gpr_refcount refs; gpr_refcount refs;
grpc_closure destroy; grpc_closure destroy;
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
const char *object_type;
#endif
} grpc_stream_refcount; } grpc_stream_refcount;
/*#define GRPC_STREAM_REFCOUNT_DEBUG*/
#ifdef GRPC_STREAM_REFCOUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
grpc_iomgr_cb_func cb, void *cb_arg,
const char *object_type);
void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason); void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason);
void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount, void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount,
const char *reason); const char *reason);
#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \
grpc_stream_ref_init(rc, ir, cb, cb_arg, objtype)
#else #else
void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
grpc_iomgr_cb_func cb, void *cb_arg);
void grpc_stream_ref(grpc_stream_refcount *refcount); void grpc_stream_ref(grpc_stream_refcount *refcount);
void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount); void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount);
#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \
grpc_stream_ref_init(rc, ir, cb, cb_arg)
#endif #endif
/* Transport stream op: a set of operations to perform on a transport /* Transport stream op: a set of operations to perform on a transport
@ -96,7 +109,7 @@ typedef struct grpc_transport_stream_op {
typedef struct grpc_transport_op { typedef struct grpc_transport_op {
/** called when processing of this op is done */ /** called when processing of this op is done */
grpc_closure *on_consumed; grpc_closure *on_consumed;
/** connectivity monitoring */ /** connectivity monitoring - set connectivity_state to NULL to unsubscribe */
grpc_closure *on_connectivity_state_change; grpc_closure *on_connectivity_state_change;
grpc_connectivity_state *connectivity_state; grpc_connectivity_state *connectivity_state;
/** should the transport be disconnected */ /** should the transport be disconnected */

@ -30,7 +30,7 @@
# Loads the local shared library, and runs all of the test cases in tests/ # Loads the local shared library, and runs all of the test cases in tests/
# against it # against it
set -e set -ex
cd $(dirname $0)/../../.. cd $(dirname $0)/../../..
root=$(pwd) root=$(pwd)
cd src/php/bin cd src/php/bin

@ -81,6 +81,16 @@ static char *get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
return gpr_strdup("peer"); return gpr_strdup("peer");
} }
static void free_channel(grpc_exec_ctx *exec_ctx, void *arg, int success) {
grpc_channel_stack_destroy(exec_ctx, arg);
gpr_free(arg);
}
static void free_call(grpc_exec_ctx *exec_ctx, void *arg, int success) {
grpc_call_stack_destroy(exec_ctx, arg);
gpr_free(arg);
}
static void test_create_channel_stack(void) { static void test_create_channel_stack(void) {
const grpc_channel_filter filter = { const grpc_channel_filter filter = {
call_func, channel_func, sizeof(int), call_init_func, call_func, channel_func, sizeof(int), call_init_func,
@ -105,16 +115,16 @@ static void test_create_channel_stack(void) {
chan_args.args = &arg; chan_args.args = &arg;
channel_stack = gpr_malloc(grpc_channel_stack_size(&filters, 1)); channel_stack = gpr_malloc(grpc_channel_stack_size(&filters, 1));
grpc_channel_stack_init(&exec_ctx, &filters, 1, NULL, &chan_args, grpc_channel_stack_init(&exec_ctx, 1, free_channel, channel_stack, &filters,
channel_stack); 1, &chan_args, "test", channel_stack);
GPR_ASSERT(channel_stack->count == 1); GPR_ASSERT(channel_stack->count == 1);
channel_elem = grpc_channel_stack_element(channel_stack, 0); channel_elem = grpc_channel_stack_element(channel_stack, 0);
channel_data = (int *)channel_elem->channel_data; channel_data = (int *)channel_elem->channel_data;
GPR_ASSERT(*channel_data == 0); GPR_ASSERT(*channel_data == 0);
call_stack = gpr_malloc(channel_stack->call_stack_size); call_stack = gpr_malloc(channel_stack->call_stack_size);
grpc_call_stack_init(&exec_ctx, channel_stack, 0, NULL, NULL, NULL, NULL, grpc_call_stack_init(&exec_ctx, channel_stack, 1, free_call, call_stack, NULL,
call_stack); NULL, call_stack);
GPR_ASSERT(call_stack->count == 1); GPR_ASSERT(call_stack->count == 1);
call_elem = grpc_call_stack_element(call_stack, 0); call_elem = grpc_call_stack_element(call_stack, 0);
GPR_ASSERT(call_elem->filter == channel_elem->filter); GPR_ASSERT(call_elem->filter == channel_elem->filter);
@ -123,12 +133,11 @@ static void test_create_channel_stack(void) {
GPR_ASSERT(*call_data == 0); GPR_ASSERT(*call_data == 0);
GPR_ASSERT(*channel_data == 1); GPR_ASSERT(*channel_data == 1);
grpc_call_stack_destroy(&exec_ctx, call_stack); GRPC_CALL_STACK_UNREF(&exec_ctx, call_stack, "done");
gpr_free(call_stack); grpc_exec_ctx_flush(&exec_ctx);
GPR_ASSERT(*channel_data == 2); GPR_ASSERT(*channel_data == 2);
grpc_channel_stack_destroy(&exec_ctx, channel_stack); GRPC_CHANNEL_STACK_UNREF(&exec_ctx, channel_stack, "done");
gpr_free(channel_stack);
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
} }

@ -136,9 +136,8 @@ static void kill_server(const servers_fixture *f, size_t i) {
gpr_log(GPR_INFO, "KILLING SERVER %d", i); gpr_log(GPR_INFO, "KILLING SERVER %d", i);
GPR_ASSERT(f->servers[i] != NULL); GPR_ASSERT(f->servers[i] != NULL);
grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000)); grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
GPR_ASSERT( GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(10000), n_millis_time(5000),
grpc_completion_queue_pluck(f->cq, tag(10000), n_millis_time(5000), NULL) NULL).type == GRPC_OP_COMPLETE);
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->servers[i]); grpc_server_destroy(f->servers[i]);
f->servers[i] = NULL; f->servers[i] = NULL;
} }
@ -204,8 +203,8 @@ static void teardown_servers(servers_fixture *f) {
if (f->servers[i] == NULL) continue; if (f->servers[i] == NULL) continue;
grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000)); grpc_server_shutdown_and_notify(f->servers[i], f->cq, tag(10000));
GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(10000), GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(10000),
n_millis_time(5000), NULL) n_millis_time(5000),
.type == GRPC_OP_COMPLETE); NULL).type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->servers[i]); grpc_server_destroy(f->servers[i]);
} }
grpc_completion_queue_shutdown(f->cq); grpc_completion_queue_shutdown(f->cq);
@ -305,8 +304,8 @@ int *perform_request(servers_fixture *f, grpc_channel *client,
s_idx = -1; s_idx = -1;
while ((ev = grpc_completion_queue_next( while ((ev = grpc_completion_queue_next(
f->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), NULL)) f->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), NULL)).type !=
.type != GRPC_QUEUE_TIMEOUT) { GRPC_QUEUE_TIMEOUT) {
GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
read_tag = ((int)(gpr_intptr)ev.tag); read_tag = ((int)(gpr_intptr)ev.tag);
gpr_log(GPR_DEBUG, "EVENT: success:%d, type:%d, tag:%d iter:%d", gpr_log(GPR_DEBUG, "EVENT: success:%d, type:%d, tag:%d iter:%d",

@ -159,11 +159,14 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
c->base.vtable = &connector_vtable; c->base.vtable = &connector_vtable;
gpr_ref_init(&c->refs, 1); gpr_ref_init(&c->refs, 1);
args->args = final_args; args->args = final_args;
args->master = f->master;
s = grpc_subchannel_create(&c->base, args); s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(exec_ctx, &c->base); grpc_connector_unref(exec_ctx, &c->base);
grpc_channel_args_destroy(final_args); grpc_channel_args_destroy(final_args);
if (*f->sniffed_subchannel) {
GRPC_SUBCHANNEL_UNREF(exec_ctx, *f->sniffed_subchannel, "sniffed");
}
*f->sniffed_subchannel = s; *f->sniffed_subchannel = s;
GRPC_SUBCHANNEL_REF(s, "sniffed");
return s; return s;
} }
@ -224,6 +227,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_micro_fullstack(
micro_fullstack_fixture_data *ffd = micro_fullstack_fixture_data *ffd =
gpr_malloc(sizeof(micro_fullstack_fixture_data)); gpr_malloc(sizeof(micro_fullstack_fixture_data));
memset(&f, 0, sizeof(f)); memset(&f, 0, sizeof(f));
memset(ffd, 0, sizeof(*ffd));
gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port); gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port);
@ -233,10 +237,54 @@ static grpc_end2end_test_fixture chttp2_create_fixture_micro_fullstack(
return f; return f;
} }
grpc_connectivity_state g_state = GRPC_CHANNEL_IDLE;
grpc_pollset_set g_interested_parties;
static void state_changed(grpc_exec_ctx *exec_ctx, void *arg, int success) {
if (g_state != GRPC_CHANNEL_READY) {
grpc_subchannel_notify_on_state_change(
exec_ctx, arg, &g_interested_parties, &g_state,
grpc_closure_create(state_changed, arg));
}
}
static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *arg, int success) {
grpc_pollset_destroy(arg);
}
static grpc_connected_subchannel *connect_subchannel(grpc_subchannel *c) {
grpc_pollset pollset;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_pollset_init(&pollset);
grpc_pollset_set_init(&g_interested_parties);
grpc_pollset_set_add_pollset(&exec_ctx, &g_interested_parties, &pollset);
grpc_subchannel_notify_on_state_change(&exec_ctx, c, &g_interested_parties,
&g_state,
grpc_closure_create(state_changed, c));
grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(GRPC_POLLSET_MU(&pollset));
while (g_state != GRPC_CHANNEL_READY) {
grpc_pollset_worker worker;
grpc_pollset_work(&exec_ctx, &pollset, &worker,
gpr_now(GPR_CLOCK_MONOTONIC),
GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
gpr_mu_unlock(GRPC_POLLSET_MU(&pollset));
grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(GRPC_POLLSET_MU(&pollset));
}
grpc_pollset_shutdown(&exec_ctx, &pollset,
grpc_closure_create(destroy_pollset, &pollset));
grpc_pollset_set_destroy(&g_interested_parties);
gpr_mu_unlock(GRPC_POLLSET_MU(&pollset));
grpc_exec_ctx_finish(&exec_ctx);
return grpc_subchannel_get_connected_subchannel(c);
}
static void chttp2_init_client_micro_fullstack(grpc_end2end_test_fixture *f, static void chttp2_init_client_micro_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) { grpc_channel_args *client_args) {
micro_fullstack_fixture_data *ffd = f->fixture_data; micro_fullstack_fixture_data *ffd = f->fixture_data;
grpc_connectivity_state conn_state; grpc_connectivity_state conn_state;
grpc_connected_subchannel *connected;
char *ipv4_localaddr; char *ipv4_localaddr;
gpr_asprintf(&ipv4_localaddr, "ipv4:%s", ffd->localaddr); gpr_asprintf(&ipv4_localaddr, "ipv4:%s", ffd->localaddr);
@ -252,8 +300,10 @@ static void chttp2_init_client_micro_fullstack(grpc_end2end_test_fixture *f,
/* here sniffed_subchannel should be ready to use */ /* here sniffed_subchannel should be ready to use */
GPR_ASSERT(conn_state == GRPC_CHANNEL_IDLE); GPR_ASSERT(conn_state == GRPC_CHANNEL_IDLE);
GPR_ASSERT(ffd->sniffed_subchannel != NULL); GPR_ASSERT(ffd->sniffed_subchannel != NULL);
connected = connect_subchannel(ffd->sniffed_subchannel);
f->client = grpc_client_uchannel_create(ffd->sniffed_subchannel, client_args); f->client = grpc_client_uchannel_create(ffd->sniffed_subchannel, client_args);
grpc_client_uchannel_set_subchannel(f->client, ffd->sniffed_subchannel); grpc_client_uchannel_set_connected_subchannel(f->client, connected);
gpr_log(GPR_INFO, "CHANNEL WRAPPING SUBCHANNEL: %p(%p)", f->client, gpr_log(GPR_INFO, "CHANNEL WRAPPING SUBCHANNEL: %p(%p)", f->client,
ffd->sniffed_subchannel); ffd->sniffed_subchannel);
@ -273,18 +323,22 @@ static void chttp2_init_server_micro_fullstack(grpc_end2end_test_fixture *f,
} }
static void chttp2_tear_down_micro_fullstack(grpc_end2end_test_fixture *f) { static void chttp2_tear_down_micro_fullstack(grpc_end2end_test_fixture *f) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
micro_fullstack_fixture_data *ffd = f->fixture_data; micro_fullstack_fixture_data *ffd = f->fixture_data;
grpc_channel_destroy(ffd->master_channel); grpc_channel_destroy(ffd->master_channel);
ffd->master_channel = NULL; if (ffd->sniffed_subchannel) {
GRPC_SUBCHANNEL_UNREF(&exec_ctx, ffd->sniffed_subchannel, "sniffed");
}
gpr_free(ffd->localaddr); gpr_free(ffd->localaddr);
gpr_free(ffd); gpr_free(ffd);
grpc_exec_ctx_finish(&exec_ctx);
} }
/* All test configurations */ /* All test configurations */
static grpc_end2end_test_config configs[] = { static grpc_end2end_test_config configs[] = {
{"chttp2/micro_fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION, {"chttp2/micro_fullstack", 0, chttp2_create_fixture_micro_fullstack,
chttp2_create_fixture_micro_fullstack, chttp2_init_client_micro_fullstack, chttp2_init_client_micro_fullstack, chttp2_init_server_micro_fullstack,
chttp2_init_server_micro_fullstack, chttp2_tear_down_micro_fullstack}, chttp2_tear_down_micro_fullstack},
}; };
int main(int argc, char **argv) { int main(int argc, char **argv) {

@ -67,7 +67,7 @@ END2END_FIXTURES = {
'h2_ssl+poll': default_secure_fixture_options._replace(platforms=['linux']), 'h2_ssl+poll': default_secure_fixture_options._replace(platforms=['linux']),
'h2_ssl_proxy': default_secure_fixture_options._replace(includes_proxy=True, 'h2_ssl_proxy': default_secure_fixture_options._replace(includes_proxy=True,
ci_mac=False), ci_mac=False),
'h2_uchannel': default_unsecure_fixture_options, 'h2_uchannel': default_unsecure_fixture_options._replace(fullstack=False),
'h2_uds+poll': uds_fixture_options._replace(platforms=['linux']), 'h2_uds+poll': uds_fixture_options._replace(platforms=['linux']),
'h2_uds': uds_fixture_options, 'h2_uds': uds_fixture_options,
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -55,8 +55,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -55,8 +55,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -56,8 +56,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s/%s", test_name, config.name, mode.name); gpr_log(GPR_INFO, "%s/%s/%s", test_name, config.name, mode.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -55,8 +55,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -56,8 +56,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -153,7 +153,7 @@ static void test_connectivity(grpc_end2end_test_config config) {
cq_verify(cqv); cq_verify(cqv);
state = grpc_channel_check_connectivity_state(f.client, 0); state = grpc_channel_check_connectivity_state(f.client, 0);
GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE || GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
state == GRPC_CHANNEL_CONNECTING); state == GRPC_CHANNEL_CONNECTING || state == GRPC_CHANNEL_IDLE);
/* cleanup server */ /* cleanup server */
grpc_server_destroy(f.server); grpc_server_destroy(f.server);

@ -59,8 +59,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -56,8 +56,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -36,13 +36,15 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "src/core/support/string.h"
#include <grpc/byte_buffer.h> #include <grpc/byte_buffer.h>
#include <grpc/grpc.h> #include <grpc/grpc.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/support/string.h"
#include "test/core/end2end/cq_verifier.h" #include "test/core/end2end/cq_verifier.h"
enum { TIMEOUT = 200000 }; enum { TIMEOUT = 200000 };
@ -56,8 +58,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }
@ -208,6 +210,7 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
grpc_arg client_arg; grpc_arg client_arg;
grpc_channel_args client_args; grpc_channel_args client_args;
char *name;
client_arg.type = GRPC_ARG_INTEGER; client_arg.type = GRPC_ARG_INTEGER;
client_arg.key = GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER; client_arg.key = GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER;
@ -216,13 +219,16 @@ static void test_invoke_10_simple_requests(grpc_end2end_test_config config,
client_args.num_args = 1; client_args.num_args = 1;
client_args.args = &client_arg; client_args.args = &client_arg;
f = begin_test(config, "test_invoke_10_simple_requests", &client_args, NULL); gpr_asprintf(&name, "test_invoke_requests first_seqno=%d",
initial_sequence_number);
f = begin_test(config, name, &client_args, NULL);
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
simple_request_body(f); simple_request_body(f);
gpr_log(GPR_INFO, "Passed simple request %d", i); gpr_log(GPR_INFO, "Passed simple request %d", i);
} }
end_test(&f); end_test(&f);
config.tear_down_data(&f); config.tear_down_data(&f);
gpr_free(name);
} }
void grpc_end2end_tests(grpc_end2end_test_config config) { void grpc_end2end_tests(grpc_end2end_test_config config) {

@ -241,8 +241,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }
@ -262,9 +262,9 @@ static void drain_cq(grpc_completion_queue *cq) {
static void shutdown_server(grpc_end2end_test_fixture *f) { static void shutdown_server(grpc_end2end_test_fixture *f) {
if (!f->server) return; if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000)); grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck( GPR_ASSERT(grpc_completion_queue_pluck(f->cq, tag(1000),
f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL) GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
.type == GRPC_OP_COMPLETE); NULL).type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server); grpc_server_destroy(f->server);
f->server = NULL; f->server = NULL;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -56,8 +56,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -56,8 +56,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -55,8 +55,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -56,8 +56,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -56,8 +56,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -54,8 +54,8 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s/%s", test_name, config.name); gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_client(&f, client_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f; return f;
} }

@ -69,13 +69,13 @@ static void on_finish(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset)); gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
} }
static void test_get(int use_ssl, int port) { static void test_get(int port) {
grpc_httpcli_request req; grpc_httpcli_request req;
char *host; char *host;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
g_done = 0; g_done = 0;
gpr_log(GPR_INFO, "running %s with use_ssl=%d.", "test_get", use_ssl); gpr_log(GPR_INFO, "test_get");
gpr_asprintf(&host, "localhost:%d", port); gpr_asprintf(&host, "localhost:%d", port);
gpr_log(GPR_INFO, "requesting from %s", host); gpr_log(GPR_INFO, "requesting from %s", host);
@ -83,7 +83,7 @@ static void test_get(int use_ssl, int port) {
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
req.host = host; req.host = host;
req.path = "/get"; req.path = "/get";
req.handshaker = use_ssl ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; req.handshaker = &grpc_httpcli_plaintext;
grpc_httpcli_get(&exec_ctx, &g_context, &g_pollset, &req, n_seconds_time(15), grpc_httpcli_get(&exec_ctx, &g_context, &g_pollset, &req, n_seconds_time(15),
on_finish, (void *)42); on_finish, (void *)42);
@ -100,13 +100,13 @@ static void test_get(int use_ssl, int port) {
gpr_free(host); gpr_free(host);
} }
static void test_post(int use_ssl, int port) { static void test_post(int port) {
grpc_httpcli_request req; grpc_httpcli_request req;
char *host; char *host;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
g_done = 0; g_done = 0;
gpr_log(GPR_INFO, "running %s with use_ssl=%d.", "test_post", (int)use_ssl); gpr_log(GPR_INFO, "test_post");
gpr_asprintf(&host, "localhost:%d", port); gpr_asprintf(&host, "localhost:%d", port);
gpr_log(GPR_INFO, "posting to %s", host); gpr_log(GPR_INFO, "posting to %s", host);
@ -114,7 +114,7 @@ static void test_post(int use_ssl, int port) {
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
req.host = host; req.host = host;
req.path = "/post"; req.path = "/post";
req.handshaker = use_ssl ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; req.handshaker = &grpc_httpcli_plaintext;
grpc_httpcli_post(&exec_ctx, &g_context, &g_pollset, &req, "hello", 5, grpc_httpcli_post(&exec_ctx, &g_context, &g_pollset, &req, "hello", 5,
n_seconds_time(15), on_finish, (void *)42); n_seconds_time(15), on_finish, (void *)42);
@ -170,8 +170,8 @@ int main(int argc, char **argv) {
grpc_httpcli_context_init(&g_context); grpc_httpcli_context_init(&g_context);
grpc_pollset_init(&g_pollset); grpc_pollset_init(&g_pollset);
test_get(0, port); test_get(port);
test_post(0, port); test_post(port);
grpc_httpcli_context_destroy(&g_context); grpc_httpcli_context_destroy(&g_context);
grpc_closure_init(&destroyed, destroy_pollset, &g_pollset); grpc_closure_init(&destroyed, destroy_pollset, &g_pollset);

@ -0,0 +1,188 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/httpcli/httpcli.h"
#include <string.h>
#include <grpc/grpc.h>
#include "src/core/iomgr/iomgr.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/subprocess.h>
#include <grpc/support/sync.h>
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
static int g_done = 0;
static grpc_httpcli_context g_context;
static grpc_pollset g_pollset;
static gpr_timespec n_seconds_time(int seconds) {
return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(seconds);
}
static void on_finish(grpc_exec_ctx *exec_ctx, void *arg,
const grpc_httpcli_response *response) {
const char *expect =
"<html><head><title>Hello world!</title></head>"
"<body><p>This is a test</p></body></html>";
GPR_ASSERT(arg == (void *)42);
GPR_ASSERT(response);
GPR_ASSERT(response->status == 200);
GPR_ASSERT(response->body_length == strlen(expect));
GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length));
gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
g_done = 1;
grpc_pollset_kick(&g_pollset, NULL);
gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
}
static void test_get(int port) {
grpc_httpcli_request req;
char *host;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
g_done = 0;
gpr_log(GPR_INFO, "test_get");
gpr_asprintf(&host, "localhost:%d", port);
gpr_log(GPR_INFO, "requesting from %s", host);
memset(&req, 0, sizeof(req));
req.host = host;
req.ssl_host_override = "foo.test.google.fr";
req.path = "/get";
req.handshaker = &grpc_httpcli_ssl;
grpc_httpcli_get(&exec_ctx, &g_context, &g_pollset, &req, n_seconds_time(15),
on_finish, (void *)42);
gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
while (!g_done) {
grpc_pollset_worker worker;
grpc_pollset_work(&exec_ctx, &g_pollset, &worker,
gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
grpc_exec_ctx_finish(&exec_ctx);
gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
}
gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
gpr_free(host);
}
static void test_post(int port) {
grpc_httpcli_request req;
char *host;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
g_done = 0;
gpr_log(GPR_INFO, "test_post");
gpr_asprintf(&host, "localhost:%d", port);
gpr_log(GPR_INFO, "posting to %s", host);
memset(&req, 0, sizeof(req));
req.host = host;
req.ssl_host_override = "foo.test.google.fr";
req.path = "/post";
req.handshaker = &grpc_httpcli_ssl;
grpc_httpcli_post(&exec_ctx, &g_context, &g_pollset, &req, "hello", 5,
n_seconds_time(15), on_finish, (void *)42);
gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
while (!g_done) {
grpc_pollset_worker worker;
grpc_pollset_work(&exec_ctx, &g_pollset, &worker,
gpr_now(GPR_CLOCK_MONOTONIC), n_seconds_time(20));
gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
grpc_exec_ctx_finish(&exec_ctx);
gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
}
gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
gpr_free(host);
}
static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
grpc_pollset_destroy(p);
}
int main(int argc, char **argv) {
grpc_closure destroyed;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
gpr_subprocess *server;
char *me = argv[0];
char *lslash = strrchr(me, '/');
char *args[5];
char root[1024];
int port = grpc_pick_unused_port_or_die();
/* figure out where we are */
if (lslash) {
memcpy(root, me, (size_t)(lslash - me));
root[lslash - me] = 0;
} else {
strcpy(root, ".");
}
/* start the server */
gpr_asprintf(&args[0], "%s/../../test/core/httpcli/test_server.py", root);
args[1] = "--port";
gpr_asprintf(&args[2], "%d", port);
args[3] = "--ssl";
server = gpr_subprocess_create(4, (const char **)args);
GPR_ASSERT(server);
gpr_free(args[0]);
gpr_free(args[2]);
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_seconds(5, GPR_TIMESPAN)));
grpc_test_init(argc, argv);
grpc_init();
grpc_httpcli_context_init(&g_context);
grpc_pollset_init(&g_pollset);
test_get(port);
test_post(port);
grpc_httpcli_context_destroy(&g_context);
grpc_closure_init(&destroyed, destroy_pollset, &g_pollset);
grpc_pollset_shutdown(&exec_ctx, &g_pollset, &destroyed);
grpc_exec_ctx_finish(&exec_ctx);
grpc_shutdown();
gpr_subprocess_destroy(server);
return 0;
}

@ -4,9 +4,18 @@
import argparse import argparse
import BaseHTTPServer import BaseHTTPServer
import os
import ssl
import sys
_PEM = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..', 'src/core/tsi/test_creds/server1.pem'))
_KEY = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..', 'src/core/tsi/test_creds/server1.key'))
print _PEM
open(_PEM).close()
argp = argparse.ArgumentParser(description='Server for httpcli_test') argp = argparse.ArgumentParser(description='Server for httpcli_test')
argp.add_argument('-p', '--port', default=10080, type=int) argp.add_argument('-p', '--port', default=10080, type=int)
argp.add_argument('-s', '--ssl', default=False, action='store_true')
args = argp.parse_args() args = argp.parse_args()
print 'server running on port %d' % args.port print 'server running on port %d' % args.port
@ -28,4 +37,7 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
if self.path == '/post' and content == 'hello': if self.path == '/post' and content == 'hello':
self.good() self.good()
BaseHTTPServer.HTTPServer(('', args.port), Handler).serve_forever() httpd = BaseHTTPServer.HTTPServer(('localhost', args.port), Handler)
if args.ssl:
httpd.socket = ssl.wrap_socket(httpd.socket, certfile=_PEM, keyfile=_KEY, server_side=True)
httpd.serve_forever()

@ -1096,6 +1096,7 @@ static void test_get_well_known_google_credentials_file_path(void) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
grpc_init();
test_empty_md_store(); test_empty_md_store();
test_ref_unref_empty_md_store(); test_ref_unref_empty_md_store();
test_add_to_empty_md_store(); test_add_to_empty_md_store();
@ -1126,5 +1127,6 @@ int main(int argc, char **argv) {
test_metadata_plugin_success(); test_metadata_plugin_success();
test_metadata_plugin_failure(); test_metadata_plugin_failure();
test_get_well_known_google_credentials_file_path(); test_get_well_known_google_credentials_file_path();
grpc_shutdown();
return 0; return 0;
} }

@ -40,7 +40,7 @@
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FILE__) #define LOG_TEST() gpr_log(GPR_INFO, "test at %s:%d", __FILE__, __LINE__)
static void test_simple_int(void) { static void test_simple_int(void) {
int x = 1; int x = 1;
@ -273,6 +273,44 @@ static void test_many(void) {
gpr_cmdline_destroy(cl); gpr_cmdline_destroy(cl);
} }
static void extra_arg_cb(void *user_data, const char *arg) {
int *count = user_data;
GPR_ASSERT(arg != NULL);
GPR_ASSERT(strlen(arg) == 1);
GPR_ASSERT(arg[0] == 'a' + *count);
++*count;
}
static void test_extra(void) {
gpr_cmdline *cl;
int count = 0;
char *args[] = {(char *)__FILE__, "a", "b", "c"};
LOG_TEST();
cl = gpr_cmdline_create(NULL);
gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
&count);
gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
GPR_ASSERT(count == 3);
gpr_cmdline_destroy(cl);
}
static void test_extra_dashdash(void) {
gpr_cmdline *cl;
int count = 0;
char *args[] = {(char *)__FILE__, "--", "a", "b", "c"};
LOG_TEST();
cl = gpr_cmdline_create(NULL);
gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
&count);
gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
GPR_ASSERT(count == 3);
gpr_cmdline_destroy(cl);
}
static void test_usage(void) { static void test_usage(void) {
gpr_cmdline *cl; gpr_cmdline *cl;
char *usage; char *usage;
@ -281,20 +319,154 @@ static void test_usage(void) {
int x = 0; int x = 0;
int flag = 2; int flag = 2;
LOG_TEST();
cl = gpr_cmdline_create(NULL); cl = gpr_cmdline_create(NULL);
gpr_cmdline_add_string(cl, "str", NULL, &str); gpr_cmdline_add_string(cl, "str", NULL, &str);
gpr_cmdline_add_int(cl, "x", NULL, &x); gpr_cmdline_add_int(cl, "x", NULL, &x);
gpr_cmdline_add_flag(cl, "flag", NULL, &flag); gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
NULL);
usage = gpr_cmdline_usage_string(cl, "test"); usage = gpr_cmdline_usage_string(cl, "test");
GPR_ASSERT( GPR_ASSERT(0 == strcmp(usage,
0 == strcmp(usage, "Usage: test [--str=string] [--x=int] "
"Usage: test [--str=string] [--x=int] [--flag|--no-flag]\n")); "[--flag|--no-flag] [file...]\n"));
gpr_free(usage);
usage = gpr_cmdline_usage_string(cl, "/foo/test");
GPR_ASSERT(0 == strcmp(usage,
"Usage: test [--str=string] [--x=int] "
"[--flag|--no-flag] [file...]\n"));
gpr_free(usage); gpr_free(usage);
gpr_cmdline_destroy(cl); gpr_cmdline_destroy(cl);
} }
static void test_help(void) {
gpr_cmdline *cl;
char *str = NULL;
int x = 0;
int flag = 2;
char *help[] = {(char *)__FILE__, "-h"};
LOG_TEST();
cl = gpr_cmdline_create(NULL);
gpr_cmdline_set_survive_failure(cl);
gpr_cmdline_add_string(cl, "str", NULL, &str);
gpr_cmdline_add_int(cl, "x", NULL, &x);
gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
NULL);
GPR_ASSERT(0 == gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(help), help));
gpr_cmdline_destroy(cl);
}
static void test_badargs1(void) {
gpr_cmdline *cl;
char *str = NULL;
int x = 0;
int flag = 2;
char *bad_arg_name[] = {(char *)__FILE__, "--y"};
LOG_TEST();
cl = gpr_cmdline_create(NULL);
gpr_cmdline_set_survive_failure(cl);
gpr_cmdline_add_string(cl, "str", NULL, &str);
gpr_cmdline_add_int(cl, "x", NULL, &x);
gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
NULL);
GPR_ASSERT(0 ==
gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(bad_arg_name), bad_arg_name));
gpr_cmdline_destroy(cl);
}
static void test_badargs2(void) {
gpr_cmdline *cl;
char *str = NULL;
int x = 0;
int flag = 2;
char *bad_int_value[] = {(char *)__FILE__, "--x", "henry"};
LOG_TEST();
cl = gpr_cmdline_create(NULL);
gpr_cmdline_set_survive_failure(cl);
gpr_cmdline_add_string(cl, "str", NULL, &str);
gpr_cmdline_add_int(cl, "x", NULL, &x);
gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
NULL);
GPR_ASSERT(
0 == gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(bad_int_value), bad_int_value));
gpr_cmdline_destroy(cl);
}
static void test_badargs3(void) {
gpr_cmdline *cl;
char *str = NULL;
int x = 0;
int flag = 2;
char *bad_bool_value[] = {(char *)__FILE__, "--flag=henry"};
LOG_TEST();
cl = gpr_cmdline_create(NULL);
gpr_cmdline_set_survive_failure(cl);
gpr_cmdline_add_string(cl, "str", NULL, &str);
gpr_cmdline_add_int(cl, "x", NULL, &x);
gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
NULL);
GPR_ASSERT(0 == gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(bad_bool_value),
bad_bool_value));
gpr_cmdline_destroy(cl);
}
static void test_badargs4(void) {
gpr_cmdline *cl;
char *str = NULL;
int x = 0;
int flag = 2;
char *bad_bool_value[] = {(char *)__FILE__, "--no-str"};
LOG_TEST();
cl = gpr_cmdline_create(NULL);
gpr_cmdline_set_survive_failure(cl);
gpr_cmdline_add_string(cl, "str", NULL, &str);
gpr_cmdline_add_int(cl, "x", NULL, &x);
gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
NULL);
GPR_ASSERT(0 == gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(bad_bool_value),
bad_bool_value));
gpr_cmdline_destroy(cl);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
test_simple_int(); test_simple_int();
@ -312,6 +484,13 @@ int main(int argc, char **argv) {
test_flag_val_true(); test_flag_val_true();
test_flag_val_false(); test_flag_val_false();
test_many(); test_many();
test_extra();
test_extra_dashdash();
test_usage(); test_usage();
test_help();
test_badargs1();
test_badargs2();
test_badargs3();
test_badargs4();
return 0; return 0;
} }

@ -31,12 +31,13 @@
* *
*/ */
#include <grpc/grpc.h> #include <string.h>
#include "test/core/end2end/cq_verifier.h" #include <grpc/grpc.h>
#include "test/core/util/test_config.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "test/core/end2end/cq_verifier.h"
#include "test/core/util/test_config.h"
static void *tag(gpr_intptr x) { return (void *)x; } static void *tag(gpr_intptr x) { return (void *)x; }
@ -47,21 +48,25 @@ int main(int argc, char **argv) {
cq_verifier *cqv; cq_verifier *cqv;
grpc_op ops[6]; grpc_op ops[6];
grpc_op *op; grpc_op *op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv; grpc_metadata_array trailing_metadata_recv;
grpc_status_code status; grpc_status_code status;
grpc_call_error error; grpc_call_error error;
char *details = NULL; char *details = NULL;
size_t details_capacity = 0; size_t details_capacity = 0;
char *peer;
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
grpc_init(); grpc_init();
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv); grpc_metadata_array_init(&trailing_metadata_recv);
chan = grpc_lame_client_channel_create( chan = grpc_lame_client_channel_create(
"lampoon:national", GRPC_STATUS_UNKNOWN, "Rpc sent on a lame channel."); "lampoon:national", GRPC_STATUS_UNKNOWN, "Rpc sent on a lame channel.");
GPR_ASSERT(chan); GPR_ASSERT(chan);
cq = grpc_completion_queue_create(NULL); cq = grpc_completion_queue_create(NULL);
call = grpc_channel_create_call(chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq, call = grpc_channel_create_call(chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
"/Foo", "anywhere", "/Foo", "anywhere",
GRPC_TIMEOUT_SECONDS_TO_DEADLINE(100), NULL); GRPC_TIMEOUT_SECONDS_TO_DEADLINE(100), NULL);
@ -74,6 +79,19 @@ int main(int argc, char **argv) {
op->flags = 0; op->flags = 0;
op->reserved = NULL; op->reserved = NULL;
op++; op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata = &initial_metadata_recv;
op->flags = 0;
op->reserved = NULL;
op++;
error = grpc_call_start_batch(call, ops, (size_t)(op - ops), tag(1), NULL);
GPR_ASSERT(GRPC_CALL_OK == error);
/* the call should immediately fail */
cq_expect_completion(cqv, tag(1), 0);
cq_verify(cqv);
op = ops;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status; op->data.recv_status_on_client.status = &status;
@ -82,18 +100,23 @@ int main(int argc, char **argv) {
op->flags = 0; op->flags = 0;
op->reserved = NULL; op->reserved = NULL;
op++; op++;
error = grpc_call_start_batch(call, ops, (size_t)(op - ops), tag(1), NULL); error = grpc_call_start_batch(call, ops, (size_t)(op - ops), tag(2), NULL);
GPR_ASSERT(GRPC_CALL_OK == error); GPR_ASSERT(GRPC_CALL_OK == error);
/* the call should immediately fail */ /* the call should immediately fail */
cq_expect_completion(cqv, tag(1), 1); cq_expect_completion(cqv, tag(2), 1);
cq_verify(cqv); cq_verify(cqv);
peer = grpc_call_get_peer(call);
GPR_ASSERT(strcmp(peer, "lampoon:national") == 0);
gpr_free(peer);
grpc_call_destroy(call); grpc_call_destroy(call);
grpc_channel_destroy(chan); grpc_channel_destroy(chan);
cq_verifier_destroy(cqv); cq_verifier_destroy(cqv);
grpc_completion_queue_destroy(cq); grpc_completion_queue_destroy(cq);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv); grpc_metadata_array_destroy(&trailing_metadata_recv);
gpr_free(details); gpr_free(details);

@ -0,0 +1,49 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include "test/core/util/test_config.h"
void test_unparsable_target(void) {
int port = grpc_server_add_insecure_http2_port(NULL, "[");
GPR_ASSERT(port == 0);
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
test_unparsable_target();
grpc_shutdown();
return 0;
}

@ -72,7 +72,6 @@ int main(void) {
clear(); clear();
for (i = 32; i <= 126; i++) { for (i = 32; i <= 126; i++) {
if (i == ',') continue;
legal(i); legal(i);
} }
dump(); dump();

@ -40,6 +40,26 @@
% endif % endif
</%def> </%def>
<%def name="fill_one_http2_test_result(shortname, resultset)">
## keep this mostly in sync with the template above
% if shortname in resultset:
## Because interop tests does not have runs_per_test flag, each test is
## run once. So there should only be one element for each result.
<% result = resultset[shortname][0] %>
<td bgcolor="white">
<div style="width:95%; border: 1px solid black; position: relative; padding: 3px;">
<span style="position: absolute; left: 45%;">${int(result.http2results['percent'] * 100)}&#37;</span>
<div style="height: 20px;
background-color: hsl(${result.http2results['percent'] * 120}, 100%, 50%);
width: ${result.http2results['percent'] * 100}%;"
title="${result.http2results['failed_cases'] | h}"></div>
</div>
</td>
% else:
<td bgcolor="magenta">Not implemented</td>
% endif
</%def>
% if num_failures > 1: % if num_failures > 1:
<p><h2><font color="red">${num_failures} tests failed!</font></h2></p> <p><h2><font color="red">${num_failures} tests failed!</font></h2></p>
% elif num_failures: % elif num_failures:
@ -95,11 +115,11 @@
shortname = 'cloud_to_cloud:http2:%s_server:%s' % ( shortname = 'cloud_to_cloud:http2:%s_server:%s' % (
server_lang, test_case) server_lang, test_case)
%> %>
${fill_one_test_result(shortname, resultset)} ${fill_one_http2_test_result(shortname, resultset)}
% endfor % endfor
% if cloud_to_prod: % if cloud_to_prod:
<% shortname = 'cloud_to_prod:http2:%s' % test_case %> <% shortname = 'cloud_to_prod:http2:%s' % test_case %>
${fill_one_test_result(shortname, resultset)} ${fill_one_http2_test_result(shortname, resultset)}
% endif % endif
</tr> </tr>
% endfor % endfor

@ -317,6 +317,10 @@ class Jobset(object):
self._hashes = {} self._hashes = {}
self._add_env = add_env self._add_env = add_env
self.resultset = {} self.resultset = {}
self._remaining = None
def set_remaining(self, remaining):
self._remaining = remaining
def get_num_failures(self): def get_num_failures(self):
return self._failures return self._failures
@ -372,8 +376,9 @@ class Jobset(object):
self._running.remove(job) self._running.remove(job)
if dead: return if dead: return
if (not self._travis): if (not self._travis):
message('WAITING', '%d jobs running, %d complete, %d failed' % ( rstr = '' if self._remaining is None else '%d queued, ' % self._remaining
len(self._running), self._completed, self._failures)) message('WAITING', '%s%d jobs running, %d complete, %d failed' % (
rstr, len(self._running), self._completed, self._failures))
if platform_string() == 'windows': if platform_string() == 'windows':
time.sleep(0.1) time.sleep(0.1)
else: else:
@ -412,6 +417,17 @@ class NoCache(object):
pass pass
def tag_remaining(xs):
staging = []
for x in xs:
staging.append(x)
if len(staging) > 1000:
yield (staging.pop(0), None)
n = len(staging)
for i, x in enumerate(staging):
yield (x, n - i - 1)
def run(cmdlines, def run(cmdlines,
check_cancelled=_never_cancelled, check_cancelled=_never_cancelled,
maxjobs=None, maxjobs=None,
@ -425,8 +441,11 @@ def run(cmdlines,
maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS, maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS,
newline_on_success, travis, stop_on_failure, add_env, newline_on_success, travis, stop_on_failure, add_env,
cache if cache is not None else NoCache()) cache if cache is not None else NoCache())
for cmdline in cmdlines: for cmdline, remaining in tag_remaining(cmdlines):
if not js.start(cmdline): if not js.start(cmdline):
break break
if remaining is not None:
js.set_remaining(remaining)
js.finish() js.finish()
return js.get_num_failures(), js.resultset return js.get_num_failures(), js.resultset

@ -32,6 +32,7 @@
try: try:
from mako.runtime import Context from mako.runtime import Context
from mako.template import Template from mako.template import Template
from mako import exceptions
except (ImportError): except (ImportError):
pass # Mako not installed but it is ok. pass # Mako not installed but it is ok.
import os import os
@ -103,9 +104,15 @@ def render_interop_html_report(
'num_failures': num_failures, 'num_failures': num_failures,
'cloud_to_prod': cloud_to_prod, 'cloud_to_prod': cloud_to_prod,
'http2_interop': http2_interop} 'http2_interop': http2_interop}
html_report_out_dir = 'reports' html_report_out_dir = 'reports'
if not os.path.exists(html_report_out_dir): if not os.path.exists(html_report_out_dir):
os.mkdir(html_report_out_dir) os.mkdir(html_report_out_dir)
html_file_path = os.path.join(html_report_out_dir, 'index.html') html_file_path = os.path.join(html_report_out_dir, 'index.html')
try:
with open(html_file_path, 'w') as output_file: with open(html_file_path, 'w') as output_file:
mytemplate.render_context(Context(output_file, **args)) mytemplate.render_context(Context(output_file, **args))
except:
print(exceptions.text_error_template().render())
raise

@ -31,17 +31,24 @@
"""Run interop (cross-language) tests in parallel.""" """Run interop (cross-language) tests in parallel."""
import argparse import argparse
import atexit
import dockerjob import dockerjob
import itertools import itertools
import jobset import jobset
import json
import multiprocessing import multiprocessing
import os import os
import re
import report_utils import report_utils
import subprocess
import sys import sys
import tempfile import tempfile
import time import time
import uuid import uuid
# Docker doesn't clean up after itself, so we do it on exit.
atexit.register(lambda: subprocess.call(['stty', 'echo']))
ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..')) ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
os.chdir(ROOT) os.chdir(ROOT)
@ -549,6 +556,33 @@ def build_interop_image_jobspec(language, tag=None):
return build_job return build_job
def aggregate_http2_results(stdout):
match = re.search(r'\{"cases[^\]]*\]\}', stdout)
if not match:
return None
results = json.loads(match.group(0))
skipped = 0
passed = 0
failed = 0
failed_cases = []
for case in results['cases']:
if case.get('skipped', False):
skipped += 1
else:
if case.get('passed', False):
passed += 1
else:
failed += 1
failed_cases.append(case.get('name', "NONAME"))
return {
'passed': passed,
'failed': failed,
'skipped': skipped,
'failed_cases': ', '.join(failed_cases),
'percent': 1.0 * passed / (passed + failed)
}
argp = argparse.ArgumentParser(description='Run interop tests.') argp = argparse.ArgumentParser(description='Run interop tests.')
argp.add_argument('-l', '--language', argp.add_argument('-l', '--language',
choices=['all'] + sorted(_LANGUAGES), choices=['all'] + sorted(_LANGUAGES),
@ -676,9 +710,7 @@ try:
docker_image=docker_images.get(str(language))) docker_image=docker_images.get(str(language)))
jobs.append(test_job) jobs.append(test_job)
# TODO(carl-mastrangelo): Currently prod TLS terminators aren't spec compliant. Reenable if args.http2_interop:
# this once a better solution is in place.
if args.http2_interop and False:
for test_case in _HTTP2_TEST_CASES: for test_case in _HTTP2_TEST_CASES:
test_job = cloud_to_prod_jobspec(http2Interop, test_case, test_job = cloud_to_prod_jobspec(http2Interop, test_case,
docker_image=docker_images.get(str(http2Interop))) docker_image=docker_images.get(str(http2Interop)))
@ -745,6 +777,10 @@ try:
report_utils.render_junit_xml_report(resultset, 'report.xml') report_utils.render_junit_xml_report(resultset, 'report.xml')
for name, job in resultset.iteritems():
if "http2" in name:
job[0].http2results = aggregate_http2_results(job[0].message)
report_utils.render_interop_html_report( report_utils.render_interop_html_report(
set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES, set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
_HTTP2_TEST_CASES, resultset, num_failures, _HTTP2_TEST_CASES, resultset, num_failures,

@ -152,7 +152,10 @@ class CLanguage(object):
else: else:
binary = 'bins/%s/%s' % (config.build_config, target['name']) binary = 'bins/%s/%s' % (config.build_config, target['name'])
if os.path.isfile(binary): if os.path.isfile(binary):
out.append(config.job_spec([binary], [binary])) out.append(config.job_spec([binary], [binary],
environ={'GRPC_DEFAULT_SSL_ROOTS_FILE_PATH':
os.path.abspath(os.path.dirname(
sys.argv[0]) + '/../../src/core/tsi/test_creds/ca.pem')}))
elif args.regex == '.*' or platform_string() == 'windows': elif args.regex == '.*' or platform_string() == 'windows':
print '\nWARNING: binary not found, skipping', binary print '\nWARNING: binary not found, skipping', binary
return sorted(out) return sorted(out)
@ -192,6 +195,7 @@ class CLanguage(object):
def __str__(self): def __str__(self):
return self.make_target return self.make_target
class NodeLanguage(object): class NodeLanguage(object):
def test_specs(self, config, args): def test_specs(self, config, args):

@ -742,6 +742,20 @@
"test/core/httpcli/httpcli_test.c" "test/core/httpcli/httpcli_test.c"
] ]
}, },
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc_test_util"
],
"headers": [],
"language": "c",
"name": "httpscli_test",
"src": [
"test/core/httpcli/httpscli_test.c"
]
},
{ {
"deps": [ "deps": [
"gpr", "gpr",
@ -934,6 +948,20 @@
"test/core/security/secure_endpoint_test.c" "test/core/security/secure_endpoint_test.c"
] ]
}, },
{
"deps": [
"gpr",
"gpr_test_util",
"grpc",
"grpc_test_util"
],
"headers": [],
"language": "c",
"name": "server_chttp2_test",
"src": [
"test/core/surface/server_chttp2_test.c"
]
},
{ {
"deps": [ "deps": [
"gpr", "gpr",
@ -8517,21 +8545,6 @@
"name": "h2_uchannel_cancel_with_status_test", "name": "h2_uchannel_cancel_with_status_test",
"src": [] "src": []
}, },
{
"deps": [
"end2end_certs",
"end2end_fixture_h2_uchannel",
"end2end_test_channel_connectivity",
"gpr",
"gpr_test_util",
"grpc",
"grpc_test_util"
],
"headers": [],
"language": "c",
"name": "h2_uchannel_channel_connectivity_test",
"src": []
},
{ {
"deps": [ "deps": [
"end2end_certs", "end2end_certs",
@ -8547,36 +8560,6 @@
"name": "h2_uchannel_compressed_payload_test", "name": "h2_uchannel_compressed_payload_test",
"src": [] "src": []
}, },
{
"deps": [
"end2end_certs",
"end2end_fixture_h2_uchannel",
"end2end_test_default_host",
"gpr",
"gpr_test_util",
"grpc",
"grpc_test_util"
],
"headers": [],
"language": "c",
"name": "h2_uchannel_default_host_test",
"src": []
},
{
"deps": [
"end2end_certs",
"end2end_fixture_h2_uchannel",
"end2end_test_disappearing_server",
"gpr",
"gpr_test_util",
"grpc",
"grpc_test_util"
],
"headers": [],
"language": "c",
"name": "h2_uchannel_disappearing_server_test",
"src": []
},
{ {
"deps": [ "deps": [
"end2end_certs", "end2end_certs",
@ -8862,21 +8845,6 @@
"name": "h2_uchannel_shutdown_finishes_tags_test", "name": "h2_uchannel_shutdown_finishes_tags_test",
"src": [] "src": []
}, },
{
"deps": [
"end2end_certs",
"end2end_fixture_h2_uchannel",
"end2end_test_simple_delayed_request",
"gpr",
"gpr_test_util",
"grpc",
"grpc_test_util"
],
"headers": [],
"language": "c",
"name": "h2_uchannel_simple_delayed_request_test",
"src": []
},
{ {
"deps": [ "deps": [
"end2end_certs", "end2end_certs",
@ -13595,20 +13563,6 @@
"name": "h2_uchannel_cancel_with_status_nosec_test", "name": "h2_uchannel_cancel_with_status_nosec_test",
"src": [] "src": []
}, },
{
"deps": [
"end2end_nosec_fixture_h2_uchannel",
"end2end_nosec_test_channel_connectivity",
"gpr",
"gpr_test_util",
"grpc_test_util_unsecure",
"grpc_unsecure"
],
"headers": [],
"language": "c",
"name": "h2_uchannel_channel_connectivity_nosec_test",
"src": []
},
{ {
"deps": [ "deps": [
"end2end_nosec_fixture_h2_uchannel", "end2end_nosec_fixture_h2_uchannel",
@ -13623,34 +13577,6 @@
"name": "h2_uchannel_compressed_payload_nosec_test", "name": "h2_uchannel_compressed_payload_nosec_test",
"src": [] "src": []
}, },
{
"deps": [
"end2end_nosec_fixture_h2_uchannel",
"end2end_nosec_test_default_host",
"gpr",
"gpr_test_util",
"grpc_test_util_unsecure",
"grpc_unsecure"
],
"headers": [],
"language": "c",
"name": "h2_uchannel_default_host_nosec_test",
"src": []
},
{
"deps": [
"end2end_nosec_fixture_h2_uchannel",
"end2end_nosec_test_disappearing_server",
"gpr",
"gpr_test_util",
"grpc_test_util_unsecure",
"grpc_unsecure"
],
"headers": [],
"language": "c",
"name": "h2_uchannel_disappearing_server_nosec_test",
"src": []
},
{ {
"deps": [ "deps": [
"end2end_nosec_fixture_h2_uchannel", "end2end_nosec_fixture_h2_uchannel",
@ -13917,20 +13843,6 @@
"name": "h2_uchannel_shutdown_finishes_tags_nosec_test", "name": "h2_uchannel_shutdown_finishes_tags_nosec_test",
"src": [] "src": []
}, },
{
"deps": [
"end2end_nosec_fixture_h2_uchannel",
"end2end_nosec_test_simple_delayed_request",
"gpr",
"gpr_test_util",
"grpc_test_util_unsecure",
"grpc_unsecure"
],
"headers": [],
"language": "c",
"name": "h2_uchannel_simple_delayed_request_nosec_test",
"src": []
},
{ {
"deps": [ "deps": [
"end2end_nosec_fixture_h2_uchannel", "end2end_nosec_fixture_h2_uchannel",

@ -851,6 +851,18 @@
"posix" "posix"
] ]
}, },
{
"ci_platforms": [
"linux"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "httpscli_test",
"platforms": [
"linux"
]
},
{ {
"ci_platforms": [ "ci_platforms": [
"linux", "linux",
@ -1067,6 +1079,24 @@
"windows" "windows"
] ]
}, },
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "server_chttp2_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{ {
"ci_platforms": [ "ci_platforms": [
"linux", "linux",
@ -9119,24 +9149,6 @@
"windows" "windows"
] ]
}, },
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "h2_uchannel_channel_connectivity_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{ {
"ci_platforms": [ "ci_platforms": [
"linux", "linux",
@ -9155,42 +9167,6 @@
"windows" "windows"
] ]
}, },
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "h2_uchannel_default_host_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "h2_uchannel_disappearing_server_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{ {
"ci_platforms": [ "ci_platforms": [
"linux", "linux",
@ -9533,24 +9509,6 @@
"windows" "windows"
] ]
}, },
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "h2_uchannel_simple_delayed_request_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{ {
"ci_platforms": [ "ci_platforms": [
"linux", "linux",
@ -14962,24 +14920,6 @@
"windows" "windows"
] ]
}, },
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "h2_uchannel_channel_connectivity_nosec_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{ {
"ci_platforms": [ "ci_platforms": [
"linux", "linux",
@ -14998,42 +14938,6 @@
"windows" "windows"
] ]
}, },
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "h2_uchannel_default_host_nosec_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "h2_uchannel_disappearing_server_nosec_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{ {
"ci_platforms": [ "ci_platforms": [
"linux", "linux",
@ -15376,24 +15280,6 @@
"windows" "windows"
] ]
}, },
{
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"exclude_configs": [],
"flaky": false,
"language": "c",
"name": "h2_uchannel_simple_delayed_request_nosec_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
]
},
{ {
"ci_platforms": [ "ci_platforms": [
"linux", "linux",

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save