Merge branch 'master' into cq_limited_pollers

pull/10803/head
Sree Kuchibhotla 8 years ago
commit d7c323f5cd
  1. 53
      BUILD
  2. 28
      Makefile
  3. 4
      bazel/cc_grpc_library.bzl
  4. 11
      bazel/generate_cc.bzl
  5. 14
      bazel/grpc_build_system.bzl
  6. 7
      build.yaml
  7. 21
      doc/service_config.md
  8. 1
      grpc.def
  9. 4
      include/grpc++/impl/codegen/client_unary_call.h
  10. 36
      include/grpc++/impl/codegen/completion_queue.h
  11. 9
      include/grpc++/impl/codegen/core_codegen.h
  12. 6
      include/grpc++/impl/codegen/core_codegen_interface.h
  13. 12
      include/grpc++/impl/codegen/sync_stream.h
  14. 163
      include/grpc++/test/mock_stream.h
  15. 58
      include/grpc/grpc.h
  16. 49
      include/grpc/impl/codegen/grpc_types.h
  17. 176
      src/compiler/cpp_generator.cc
  18. 34
      src/compiler/cpp_generator.h
  19. 21
      src/compiler/cpp_plugin.cc
  20. 18
      src/core/ext/filters/client_channel/client_channel.c
  21. 8
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
  22. 2
      src/core/ext/transport/chttp2/server/chttp2_server.c
  23. 19
      src/core/lib/iomgr/udp_server.c
  24. 6
      src/core/lib/support/stack_lockfree.c
  25. 8
      src/core/lib/support/time_posix.c
  26. 20
      src/core/lib/support/tmpfile_posix.c
  27. 182
      src/core/lib/surface/completion_queue.c
  28. 6
      src/core/lib/surface/completion_queue.h
  29. 19
      src/core/lib/surface/server.c
  30. 12
      src/cpp/common/core_codegen.cc
  31. 28
      src/cpp/server/server_builder.cc
  32. 8
      src/node/ext/server_generic.cc
  33. 39
      src/proto/grpc/health/v1/BUILD
  34. 2
      src/proto/grpc/testing/BUILD
  35. 8
      src/proto/grpc/testing/compiler_test.proto
  36. 3
      src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
  37. 11
      src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
  38. 2
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  39. 3
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  40. 14
      templates/Makefile.template
  41. 2
      templates/tools/run_tests/generated/sources_and_headers.json.template
  42. 52
      test/core/end2end/fixtures/http_proxy_fixture.c
  43. 9
      test/core/end2end/tests/cancel_after_invoke.c
  44. 4
      test/core/util/port_server_client.c
  45. 10
      test/core/util/test_config.c
  46. 2
      test/cpp/codegen/BUILD
  47. 144
      test/cpp/codegen/compiler_test_golden
  48. 34
      test/cpp/codegen/compiler_test_mock_golden
  49. 31
      test/cpp/codegen/golden_file_test.cc
  50. 1
      test/cpp/end2end/BUILD
  51. 20
      test/cpp/end2end/async_end2end_test.cc
  52. 278
      test/cpp/end2end/mock_test.cc
  53. 2
      test/cpp/microbenchmarks/bm_call_create.cc
  54. 24
      test/cpp/microbenchmarks/fullstack_fixtures.h
  55. 4
      test/cpp/microbenchmarks/helpers.cc
  56. 3
      test/cpp/microbenchmarks/helpers.h
  57. 5
      third_party/gtest.BUILD
  58. 1
      tools/jenkins/run_performance.sh
  59. 2
      tools/profiling/microbenchmarks/bm2bq.py
  60. 6
      tools/profiling/microbenchmarks/bm_diff.py
  61. 83
      tools/run_tests/generated/sources_and_headers.json
  62. 2
      tools/run_tests/generated/tests.json
  63. 27
      tools/run_tests/python_utils/port_server.py
  64. 3
      vsprojects/vcxproj/test/mock_test/mock_test.vcxproj
  65. 14
      vsprojects/vcxproj/test/mock_test/mock_test.vcxproj.filters

53
BUILD

@ -54,33 +54,46 @@ grpc_cc_library(
], ],
) )
grpc_cc_library( grpc_cc_libraries(
name = "grpc", name_list = ["grpc", "grpc_unsecure",],
srcs = [ srcs = [
"src/core/lib/surface/init.c", "src/core/lib/surface/init.c",
],
additional_src_list = [
[
"src/core/plugin_registry/grpc_plugin_registry.c", "src/core/plugin_registry/grpc_plugin_registry.c",
], ],
[
"src/core/lib/surface/init_unsecure.c",
"src/core/plugin_registry/grpc_unsecure_plugin_registry.c",
],
],
language = "c", language = "c",
standalone = True, standalone = True,
deps = [ deps = [
"census", "census",
"grpc_base", "grpc_base",
"grpc_lb_policy_grpclb_secure",
"grpc_lb_policy_pick_first", "grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin", "grpc_lb_policy_round_robin",
"grpc_load_reporting", "grpc_load_reporting",
"grpc_max_age_filter", "grpc_max_age_filter",
"grpc_resolver_dns_ares",
"grpc_resolver_dns_native", "grpc_resolver_dns_native",
"grpc_resolver_sockaddr", "grpc_resolver_sockaddr",
"grpc_secure",
"grpc_transport_chttp2_client_insecure", "grpc_transport_chttp2_client_insecure",
"grpc_transport_chttp2_client_secure",
"grpc_transport_chttp2_server_insecure", "grpc_transport_chttp2_server_insecure",
"grpc_transport_chttp2_server_secure",
"grpc_message_size_filter", "grpc_message_size_filter",
"grpc_deadline_filter", "grpc_deadline_filter",
], ],
additional_dep_list = [
[
"grpc_secure",
"grpc_resolver_dns_ares",
"grpc_lb_policy_grpclb_secure",
"grpc_transport_chttp2_client_secure",
"grpc_transport_chttp2_server_secure",
],
[],
],
) )
grpc_cc_library( grpc_cc_library(
@ -98,32 +111,6 @@ grpc_cc_library(
], ],
) )
grpc_cc_library(
name = "grpc_unsecure",
srcs = [
"src/core/lib/surface/init.c",
"src/core/lib/surface/init_unsecure.c",
"src/core/plugin_registry/grpc_unsecure_plugin_registry.c",
],
language = "c",
standalone = True,
deps = [
"census",
"grpc_base",
"grpc_lb_policy_grpclb",
"grpc_lb_policy_pick_first",
"grpc_lb_policy_round_robin",
"grpc_load_reporting",
"grpc_max_age_filter",
"grpc_resolver_dns_native",
"grpc_resolver_sockaddr",
"grpc_transport_chttp2_client_insecure",
"grpc_transport_chttp2_server_insecure",
"grpc_message_size_filter",
"grpc_deadline_filter",
],
)
grpc_cc_library( grpc_cc_library(
name = "grpc++", name = "grpc++",
srcs = [ srcs = [

@ -174,7 +174,7 @@ LD_ubsan = clang
LDXX_ubsan = clang++ LDXX_ubsan = clang++
CPPFLAGS_ubsan = -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument -Wvarargs CPPFLAGS_ubsan = -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument -Wvarargs
LDFLAGS_ubsan = -fsanitize=undefined,unsigned-integer-overflow LDFLAGS_ubsan = -fsanitize=undefined,unsigned-integer-overflow
DEFINES_ubsan = NDEBUG DEFINES_ubsan = NDEBUG GRPC_UBSAN
VALID_CONFIG_tsan = 1 VALID_CONFIG_tsan = 1
REQUIRE_CUSTOM_LIBRARIES_tsan = 1 REQUIRE_CUSTOM_LIBRARIES_tsan = 1
@ -418,7 +418,7 @@ AROPTS = $(GRPC_CROSS_AROPTS) # e.g., rc --target=elf32-little
USE_BUILT_PROTOC = false USE_BUILT_PROTOC = false
endif endif
GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc -Ithird_party/googletest/googlemock/include -Ithird_party/googletest/googlemock third_party/googletest/googlemock/src/gmock-all.cc
GTEST_LIB += -lgflags GTEST_LIB += -lgflags
ifeq ($(V),1) ifeq ($(V),1)
E = @: E = @:
@ -793,7 +793,7 @@ PROTOBUF_PKG_CONFIG = false
PC_REQUIRES_GRPCXX = PC_REQUIRES_GRPCXX =
PC_LIBS_GRPCXX = PC_LIBS_GRPCXX =
CPPFLAGS := -Ithird_party/googletest/googletest/include $(CPPFLAGS) CPPFLAGS := -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googlemock/include $(CPPFLAGS)
PROTOC_PLUGINS_ALL = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(BINDIR)/$(CONFIG)/grpc_node_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_php_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin PROTOC_PLUGINS_ALL = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(BINDIR)/$(CONFIG)/grpc_node_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_php_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
PROTOC_PLUGINS_DIR = $(BINDIR)/$(CONFIG) PROTOC_PLUGINS_DIR = $(BINDIR)/$(CONFIG)
@ -2238,6 +2238,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/health/v1/health.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/health/v1/health.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/health/v1/health.pb.cc: src/proto/grpc/health/v1/health.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/health/v1/health.pb.cc: src/proto/grpc/health/v1/health.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2253,6 +2254,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc: src/proto/grpc/lb/v1/load_balancer.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc: src/proto/grpc/lb/v1/load_balancer.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2268,6 +2270,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: src/proto/grpc/reflection/v1alpha/reflection.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: src/proto/grpc/reflection/v1alpha/reflection.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2283,6 +2286,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/status/status.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/status/status.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/status/status.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/status/status.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/status/status.pb.cc: src/proto/grpc/status/status.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/status/status.pb.cc: src/proto/grpc/status/status.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2298,6 +2302,8 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2306,13 +2312,14 @@ $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc: src/proto/grpc/testing/com
$(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $< $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=generate_mock_code=true:$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
endif endif
ifeq ($(NO_PROTOC),true) ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/control.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/control.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/control.pb.cc: src/proto/grpc/testing/control.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc: src/proto/grpc/testing/control.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2328,6 +2335,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc: src/proto/grpc/testing/duplicate/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc: src/proto/grpc/testing/duplicate/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2343,6 +2351,8 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/echo.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/echo.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/echo.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2351,13 +2361,14 @@ $(GENDIR)/src/proto/grpc/testing/echo.pb.cc: src/proto/grpc/testing/echo.proto $
$(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $< $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=generate_mock_code=true:$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
endif endif
ifeq ($(NO_PROTOC),true) ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc: src/proto/grpc/testing/echo_messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc: src/proto/grpc/testing/echo_messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2373,6 +2384,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/empty.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/empty.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/empty.pb.cc: src/proto/grpc/testing/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/empty.pb.cc: src/proto/grpc/testing/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2388,6 +2400,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/messages.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/messages.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/messages.pb.cc: src/proto/grpc/testing/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc: src/proto/grpc/testing/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2403,6 +2416,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/metrics.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/metrics.pb.cc: src/proto/grpc/testing/metrics.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/metrics.pb.cc: src/proto/grpc/testing/metrics.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2418,6 +2432,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/payloads.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/payloads.pb.cc: src/proto/grpc/testing/payloads.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc: src/proto/grpc/testing/payloads.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2433,6 +2448,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/services.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/services.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/services.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/services.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2448,6 +2464,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/stats.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/stats.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/stats.pb.cc: src/proto/grpc/testing/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/stats.pb.cc: src/proto/grpc/testing/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -2463,6 +2480,7 @@ ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/test.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/test.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc: protoc_dep_error $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc: protoc_dep_error
else else
$(GENDIR)/src/proto/grpc/testing/test.pb.cc: src/proto/grpc/testing/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc: src/proto/grpc/testing/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`

@ -2,7 +2,7 @@
load("//:bazel/generate_cc.bzl", "generate_cc") load("//:bazel/generate_cc.bzl", "generate_cc")
def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, use_external = False, **kwargs): def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, generate_mock, use_external = False, **kwargs):
"""Generates C++ grpc classes from a .proto file. """Generates C++ grpc classes from a .proto file.
Assumes the generated classes will be used in cc_api_version = 2. Assumes the generated classes will be used in cc_api_version = 2.
@ -17,6 +17,7 @@ def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, use_externa
"@com_google_protobuf//:well_known_protos" "@com_google_protobuf//:well_known_protos"
use_external: When True the grpc deps are prefixed with //external. This use_external: When True the grpc deps are prefixed with //external. This
allows grpc to be used as a dependency in other bazel projects. allows grpc to be used as a dependency in other bazel projects.
generate_mock: When true GMOCk code for client stub is generated.
**kwargs: rest of arguments, e.g., compatible_with and visibility. **kwargs: rest of arguments, e.g., compatible_with and visibility.
""" """
if len(srcs) > 1: if len(srcs) > 1:
@ -54,6 +55,7 @@ def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, use_externa
srcs = [proto_target], srcs = [proto_target],
plugin = plugin, plugin = plugin,
well_known_protos = well_known_protos, well_known_protos = well_known_protos,
generate_mock = generate_mock,
**kwargs **kwargs
) )

@ -12,6 +12,8 @@ def generate_cc_impl(ctx):
if ctx.executable.plugin: if ctx.executable.plugin:
outs += [proto.basename[:-len(".proto")] + ".grpc.pb.h" for proto in protos] outs += [proto.basename[:-len(".proto")] + ".grpc.pb.h" for proto in protos]
outs += [proto.basename[:-len(".proto")] + ".grpc.pb.cc" for proto in protos] outs += [proto.basename[:-len(".proto")] + ".grpc.pb.cc" for proto in protos]
if ctx.attr.generate_mock:
outs += [proto.basename[:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos]
else: else:
outs += [proto.basename[:-len(".proto")] + ".pb.h" for proto in protos] outs += [proto.basename[:-len(".proto")] + ".pb.h" for proto in protos]
outs += [proto.basename[:-len(".proto")] + ".pb.cc" for proto in protos] outs += [proto.basename[:-len(".proto")] + ".pb.cc" for proto in protos]
@ -23,7 +25,10 @@ def generate_cc_impl(ctx):
arguments = [] arguments = []
if ctx.executable.plugin: if ctx.executable.plugin:
arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path] arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path]
arguments += ["--PLUGIN_out=" + ",".join(ctx.attr.flags) + ":" + dir_out] flags = list(ctx.attr.flags)
if ctx.attr.generate_mock:
flags.append("generate_mock_code=true")
arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out]
additional_input = [ctx.executable.plugin] additional_input = [ctx.executable.plugin]
else: else:
arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out] arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
@ -71,6 +76,10 @@ generate_cc = rule(
"well_known_protos" : attr.label( "well_known_protos" : attr.label(
mandatory = False, mandatory = False,
), ),
"generate_mock" : attr.bool(
default = False,
mandatory = False,
),
"_protoc": attr.label( "_protoc": attr.label(
default = Label("//external:protocol_compiler"), default = Label("//external:protocol_compiler"),
executable = True, executable = True,

@ -49,14 +49,17 @@ def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [], external_deps
] ]
) )
def grpc_cc_libraries(name_list, additional_dep_list, srcs = [], public_hdrs = [], hdrs = [], external_deps = [], deps = [], standalone = False, language="C++"): def grpc_cc_libraries(name_list, additional_src_list = [], additional_dep_list = [], srcs = [], public_hdrs = [], hdrs = [], external_deps = [], deps = [], standalone = False, language="C++"):
for i in range(len(name_list)): names = len(name_list)
asl = additional_src_list + [[]]*(names - len(additional_src_list))
adl = additional_dep_list + [[]]*(names - len(additional_dep_list))
for i in range(names):
grpc_cc_library( grpc_cc_library(
name = name_list[i], name = name_list[i],
srcs = srcs, srcs = srcs + asl[i],
hdrs = hdrs, hdrs = hdrs,
public_hdrs = public_hdrs, public_hdrs = public_hdrs,
deps = deps + additional_dep_list[i], deps = deps + adl[i],
external_deps = external_deps, external_deps = external_deps,
standalone = standalone, standalone = standalone,
language = language language = language
@ -72,7 +75,7 @@ def grpc_proto_plugin(name, srcs = [], deps = []):
load("//:bazel/cc_grpc_library.bzl", "cc_grpc_library") load("//:bazel/cc_grpc_library.bzl", "cc_grpc_library")
def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = None, def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = None,
has_services = True, use_external = False): has_services = True, use_external = False, generate_mock = False):
cc_grpc_library( cc_grpc_library(
name = name, name = name,
srcs = srcs, srcs = srcs,
@ -80,5 +83,6 @@ def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = None,
well_known_protos = well_known_protos, well_known_protos = well_known_protos,
proto_only = not has_services, proto_only = not has_services,
use_external = use_external, use_external = use_external,
generate_mock = generate_mock,
) )

@ -969,6 +969,7 @@ filegroups:
- name: grpc++_test - name: grpc++_test
language: c++ language: c++
public_headers: public_headers:
- include/grpc++/test/mock_stream.h
- include/grpc++/test/server_context_test_spouse.h - include/grpc++/test/server_context_test_spouse.h
deps: deps:
- grpc++ - grpc++
@ -3691,7 +3692,7 @@ targets:
- grpc - grpc
- gpr - gpr
args: args:
- --generated_file_path=gens/src/proto/grpc/testing/compiler_test.grpc.pb.h - --generated_file_path=gens/src/proto/grpc/testing/
- name: grpc_cli - name: grpc_cli
build: test build: test
run: false run: false
@ -3952,6 +3953,8 @@ targets:
gtest: true gtest: true
build: test build: test
language: c++ language: c++
headers:
- include/grpc++/test/mock_stream.h
src: src:
- test/cpp/end2end/mock_test.cc - test/cpp/end2end/mock_test.cc
deps: deps:
@ -4464,7 +4467,7 @@ configs:
CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=undefined -fno-omit-frame-pointer
-Wno-unused-command-line-argument -Wvarargs -Wno-unused-command-line-argument -Wvarargs
CXX: clang++ CXX: clang++
DEFINES: NDEBUG DEFINES: NDEBUG GRPC_UBSAN
LD: clang LD: clang
LDFLAGS: -fsanitize=undefined,unsigned-integer-overflow LDFLAGS: -fsanitize=undefined,unsigned-integer-overflow
LDXX: clang++ LDXX: clang++

@ -13,12 +13,21 @@ The service config is a JSON string of the following form:
``` ```
{ {
// Load balancing policy name. // Load balancing policy name.
// Supported values are 'round_robin' and 'grpclb'. // Currently, the only selectable client-side policy provided with gRPC
// Optional; if unset, the default behavior is pick the first available // is 'round_robin', but third parties may add their own policies.
// backend. // This field is optional; if unset, the default behavior is to pick
// Note that if the resolver returns only balancer addresses and no // the first available backend.
// backend addresses, gRPC will always use the 'grpclb' policy, // If the policy name is set via the client API, that value overrides
// regardless of what this field is set to. // the value specified here.
//
// Note that if the resolver returns at least one balancer address (as
// opposed to backend addresses), gRPC will use grpclb (see
// https://github.com/grpc/grpc/blob/master/doc/load-balancing.md),
// regardless of what LB policy is requested either here or via the
// client API. However, if the resolver returns at least one backend
// address in addition to the balancer address(es), the client may fall
// back to the requested policy if it is unable to reach any of the
// grpclb load balancers.
'loadBalancingPolicy': string, 'loadBalancingPolicy': string,
// Per-method configuration. Optional. // Per-method configuration. Optional.

@ -89,7 +89,6 @@ EXPORTS
grpc_server_request_registered_call grpc_server_request_registered_call
grpc_server_create grpc_server_create
grpc_server_register_completion_queue grpc_server_register_completion_queue
grpc_server_register_non_listening_completion_queue
grpc_server_add_insecure_http2_port grpc_server_add_insecure_http2_port
grpc_server_start grpc_server_start
grpc_server_shutdown_and_notify grpc_server_shutdown_and_notify

@ -52,7 +52,9 @@ template <class InputMessage, class OutputMessage>
Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context, const InputMessage& request, ClientContext* context, const InputMessage& request,
OutputMessage* result) { OutputMessage* result) {
CompletionQueue cq(true); // Pluckable completion queue CompletionQueue cq(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}); // Pluckable completion queue
Call call(channel->CreateCall(method, context, &cq)); Call call(channel->CreateCall(method, context, &cq));
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>, CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,

@ -102,7 +102,9 @@ class CompletionQueue : private GrpcLibraryCodegen {
public: public:
/// Default constructor. Implicitly creates a \a grpc_completion_queue /// Default constructor. Implicitly creates a \a grpc_completion_queue
/// instance. /// instance.
CompletionQueue() : CompletionQueue(false) {} CompletionQueue()
: CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING}) {}
/// Wrap \a take, taking ownership of the instance. /// Wrap \a take, taking ownership of the instance.
/// ///
@ -182,6 +184,16 @@ class CompletionQueue : private GrpcLibraryCodegen {
}; };
void CompleteAvalanching(); void CompleteAvalanching();
protected:
/// Private constructor of CompletionQueue only visible to friend classes
CompletionQueue(const grpc_completion_queue_attributes& attributes) {
cq_ = g_core_codegen_interface->grpc_completion_queue_create(
g_core_codegen_interface->grpc_completion_queue_factory_lookup(
&attributes),
&attributes, NULL);
InitialAvalanching(); // reserve this for the future shutdown
}
private: private:
// Friend synchronous wrappers so that they can access Pluck(), which is // Friend synchronous wrappers so that they can access Pluck(), which is
// a semi-private API geared towards the synchronous implementation. // a semi-private API geared towards the synchronous implementation.
@ -215,18 +227,6 @@ class CompletionQueue : private GrpcLibraryCodegen {
const InputMessage& request, const InputMessage& request,
OutputMessage* result); OutputMessage* result);
/// Private constructor of CompletionQueue only visible to friend classes
CompletionQueue(bool is_pluck) {
if (is_pluck) {
cq_ = g_core_codegen_interface->grpc_completion_queue_create_for_pluck(
nullptr);
} else {
cq_ = g_core_codegen_interface->grpc_completion_queue_create_for_next(
nullptr);
}
InitialAvalanching(); // reserve this for the future shutdown
}
NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline); NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
/// Wraps \a grpc_completion_queue_pluck. /// Wraps \a grpc_completion_queue_pluck.
@ -289,17 +289,19 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// by servers. Instantiated by \a ServerBuilder. /// by servers. Instantiated by \a ServerBuilder.
class ServerCompletionQueue : public CompletionQueue { class ServerCompletionQueue : public CompletionQueue {
public: public:
bool IsFrequentlyPolled() { return is_frequently_polled_; } bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; }
private: private:
bool is_frequently_polled_; grpc_cq_polling_type polling_type_;
friend class ServerBuilder; friend class ServerBuilder;
/// \param is_frequently_polled Informs the GRPC library about whether the /// \param is_frequently_polled Informs the GRPC library about whether the
/// server completion queue would be actively polled (by calling Next() or /// server completion queue would be actively polled (by calling Next() or
/// AsyncNext()). By default all server completion queues are assumed to be /// AsyncNext()). By default all server completion queues are assumed to be
/// frequently polled. /// frequently polled.
ServerCompletionQueue(bool is_frequently_polled = true) ServerCompletionQueue(grpc_cq_polling_type polling_type)
: is_frequently_polled_(is_frequently_polled) {} : CompletionQueue(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, polling_type}),
polling_type_(polling_type) {}
}; };
} // namespace grpc } // namespace grpc

@ -44,8 +44,15 @@
namespace grpc { namespace grpc {
/// Implementation of the core codegen interface. /// Implementation of the core codegen interface.
class CoreCodegen : public CoreCodegenInterface { class CoreCodegen final : public CoreCodegenInterface {
private: private:
virtual const grpc_completion_queue_factory*
grpc_completion_queue_factory_lookup(
const grpc_completion_queue_attributes* attributes) override;
virtual grpc_completion_queue* grpc_completion_queue_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attributes,
void* reserved) override;
grpc_completion_queue* grpc_completion_queue_create_for_next( grpc_completion_queue* grpc_completion_queue_create_for_next(
void* reserved) override; void* reserved) override;
grpc_completion_queue* grpc_completion_queue_create_for_pluck( grpc_completion_queue* grpc_completion_queue_create_for_pluck(

@ -59,6 +59,12 @@ class CoreCodegenInterface {
virtual void assert_fail(const char* failed_assertion, const char* file, virtual void assert_fail(const char* failed_assertion, const char* file,
int line) = 0; int line) = 0;
virtual const grpc_completion_queue_factory*
grpc_completion_queue_factory_lookup(
const grpc_completion_queue_attributes* attributes) = 0;
virtual grpc_completion_queue* grpc_completion_queue_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attributes, void* reserved) = 0;
virtual grpc_completion_queue* grpc_completion_queue_create_for_next( virtual grpc_completion_queue* grpc_completion_queue_create_for_next(
void* reserved) = 0; void* reserved) = 0;
virtual grpc_completion_queue* grpc_completion_queue_create_for_pluck( virtual grpc_completion_queue* grpc_completion_queue_create_for_pluck(

@ -156,7 +156,9 @@ class ClientReader final : public ClientReaderInterface<R> {
ClientReader(ChannelInterface* channel, const RpcMethod& method, ClientReader(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context, const W& request) ClientContext* context, const W& request)
: context_(context), : context_(context),
cq_(true), // Pluckable cq cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) { call_(channel->CreateCall(method, context, &cq_)) {
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
CallOpClientSendClose> CallOpClientSendClose>
@ -230,7 +232,9 @@ class ClientWriter : public ClientWriterInterface<W> {
ClientWriter(ChannelInterface* channel, const RpcMethod& method, ClientWriter(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context, R* response) ClientContext* context, R* response)
: context_(context), : context_(context),
cq_(true), // Pluckable cq cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) { call_(channel->CreateCall(method, context, &cq_)) {
finish_ops_.RecvMessage(response); finish_ops_.RecvMessage(response);
finish_ops_.AllowNoMessage(); finish_ops_.AllowNoMessage();
@ -330,7 +334,9 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method, ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method,
ClientContext* context) ClientContext* context)
: context_(context), : context_(context),
cq_(true), // Pluckable cq cq_(grpc_completion_queue_attributes{
GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK,
GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq
call_(channel->CreateCall(method, context, &cq_)) { call_(channel->CreateCall(method, context, &cq_)) {
if (!context_->initial_metadata_corked_) { if (!context_->initial_metadata_corked_) {
CallOpSet<CallOpSendInitialMetadata> ops; CallOpSet<CallOpSendInitialMetadata> ops;

@ -0,0 +1,163 @@
/*
*
* Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPCXX_TEST_MOCK_STREAM_H
#define GRPCXX_TEST_MOCK_STREAM_H
#include <stdint.h>
#include <gmock/gmock.h>
#include <grpc++/impl/codegen/call.h>
#include <grpc++/support/async_stream.h>
#include <grpc++/support/async_unary_call.h>
#include <grpc++/support/sync_stream.h>
namespace grpc {
namespace testing {
template <class R>
class MockClientReader : public ClientReaderInterface<R> {
public:
MockClientReader() = default;
// ClientStreamingInterface
MOCK_METHOD0_T(Finish, Status());
// ReaderInterface
MOCK_METHOD1_T(NextMessageSize, bool(uint32_t*));
MOCK_METHOD1_T(Read, bool(R*));
// ClientReaderInterface
MOCK_METHOD0_T(WaitForInitialMetadata, void());
};
template <class W>
class MockClientWriter : public ClientWriterInterface<W> {
public:
MockClientWriter() = default;
// ClientStreamingInterface
MOCK_METHOD0_T(Finish, Status());
// WriterInterface
MOCK_METHOD2_T(Write, bool(const W&, const WriteOptions));
// ClientWriterInterface
MOCK_METHOD0_T(WritesDone, bool());
};
template <class W, class R>
class MockClientReaderWriter : public ClientReaderWriterInterface<W, R> {
public:
MockClientReaderWriter() = default;
// ClientStreamingInterface
MOCK_METHOD0_T(Finish, Status());
// ReaderInterface
MOCK_METHOD1_T(NextMessageSize, bool(uint32_t*));
MOCK_METHOD1_T(Read, bool(R*));
// WriterInterface
MOCK_METHOD2_T(Write, bool(const W&, const WriteOptions));
// ClientReaderWriterInterface
MOCK_METHOD0_T(WaitForInitialMetadata, void());
MOCK_METHOD0_T(WritesDone, bool());
};
// TODO: We do not support mocking an async RPC for now.
template <class R>
class MockClientAsyncResponseReader
: public ClientAsyncResponseReaderInterface<R> {
public:
MockClientAsyncResponseReader() = default;
MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
MOCK_METHOD3_T(Finish, void(R*, Status*, void*));
};
template <class R>
class MockClientAsyncReader : public ClientAsyncReaderInterface<R> {
public:
MockClientAsyncReader() = default;
// ClientAsyncStreamingInterface
MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
MOCK_METHOD2_T(Finish, void(Status*, void*));
// AsyncReaderInterface
MOCK_METHOD2_T(Read, void(R*, void*));
};
template <class W>
class MockClientAsyncWriter : public ClientAsyncWriterInterface<W> {
public:
MockClientAsyncWriter() = default;
// ClientAsyncStreamingInterface
MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
MOCK_METHOD2_T(Finish, void(Status*, void*));
// AsyncWriterInterface
MOCK_METHOD2_T(Write, void(const W&, void*));
// ClientAsyncWriterInterface
MOCK_METHOD1_T(WritesDone, void(void*));
};
template <class W, class R>
class MockClientAsyncReaderWriter
: public ClientAsyncReaderWriterInterface<W, R> {
public:
MockClientAsyncReaderWriter() = default;
// ClientAsyncStreamingInterface
MOCK_METHOD1_T(ReadInitialMetadata, void(void*));
MOCK_METHOD2_T(Finish, void(Status*, void*));
// AsyncWriterInterface
MOCK_METHOD2_T(Write, void(const W&, void*));
// AsyncReaderInterface
MOCK_METHOD2_T(Read, void(R*, void*));
// ClientAsyncReaderWriterInterface
MOCK_METHOD1_T(WritesDone, void(void*));
};
} // namespace testing
} // namespace grpc
#endif // GRPCXX_TEST_MOCK_STREAM_H

@ -93,55 +93,6 @@ GRPCAPI const char *grpc_version_string(void);
/** Return a string specifying what the 'g' in gRPC stands for */ /** Return a string specifying what the 'g' in gRPC stands for */
GRPCAPI const char *grpc_g_stands_for(void); GRPCAPI const char *grpc_g_stands_for(void);
/** Specifies the type of APIs to use to pop events from the completion queue */
typedef enum {
/** Events are popped out by calling grpc_completion_queue_next() API ONLY */
GRPC_CQ_NEXT = 1,
/** Events are popped out by calling grpc_completion_queue_pluck() API ONLY*/
GRPC_CQ_PLUCK
} grpc_cq_completion_type;
/** Completion queues internally MAY maintain a set of file descriptors in a
structure called 'pollset'. This enum specifies if a completion queue has an
associated pollset and any restrictions on the type of file descriptors that
can be present in the pollset.
I/O progress can only be made when grpc_completion_queue_next() or
grpc_completion_queue_pluck() are called on the completion queue (unless the
grpc_cq_polling_type is GRPC_CQ_NON_POLLING) and hence it is very important
to actively call these APIs */
typedef enum {
/** The completion queue will have an associated pollset and there is no
restriction on the type of file descriptors the pollset may contain */
GRPC_CQ_DEFAULT_POLLING,
/** Similar to GRPC_CQ_DEFAULT_POLLING except that the completion queues will
not contain any 'listening file descriptors' (i.e file descriptors used to
listen to incoming channels) */
GRPC_CQ_NON_LISTENING,
/** The completion queue will not have an associated pollset. Note that
grpc_completion_queue_next() or grpc_completion_queue_pluck() MUST still
be called to pop events from the completion queue; it is not required to
call them actively to make I/O progress */
GRPC_CQ_NON_POLLING
} grpc_cq_polling_type;
#define GRPC_CQ_CURRENT_VERSION 1
typedef struct grpc_completion_queue_attributes {
/* The version number of this structure. More fields might be added to this
structure in future. */
int version; /* Set to GRPC_CQ_CURRENT_VERSION */
grpc_cq_completion_type cq_completion_type;
grpc_cq_polling_type cq_polling_type;
} grpc_completion_queue_attributes;
/** The completion queue factory structure is opaque to the callers of grpc */
typedef struct grpc_completion_queue_factory grpc_completion_queue_factory;
/** Returns the completion queue factory based on the attributes. MAY return a /** Returns the completion queue factory based on the attributes. MAY return a
NULL if no factory can be found */ NULL if no factory can be found */
GRPCAPI const grpc_completion_queue_factory * GRPCAPI const grpc_completion_queue_factory *
@ -427,15 +378,6 @@ GRPCAPI void grpc_server_register_completion_queue(grpc_server *server,
grpc_completion_queue *cq, grpc_completion_queue *cq,
void *reserved); void *reserved);
/** Register a non-listening completion queue with the server. This API is
similar to grpc_server_register_completion_queue except that the server will
not use this completion_queue to listen to any incoming channels.
Registering a non-listening completion queue will have negative performance
impact and hence this API is not recommended for production use cases. */
GRPCAPI void grpc_server_register_non_listening_completion_queue(
grpc_server *server, grpc_completion_queue *q, void *reserved);
/** Add a HTTP2 over plaintext over tcp listener. /** Add a HTTP2 over plaintext over tcp listener.
Returns bound port number on success, 0 on failure. Returns bound port number on success, 0 on failure.
REQUIRES: server not started */ REQUIRES: server not started */

@ -556,6 +556,55 @@ typedef struct {
typedef struct grpc_resource_quota grpc_resource_quota; typedef struct grpc_resource_quota grpc_resource_quota;
/** Completion queues internally MAY maintain a set of file descriptors in a
structure called 'pollset'. This enum specifies if a completion queue has an
associated pollset and any restrictions on the type of file descriptors that
can be present in the pollset.
I/O progress can only be made when grpc_completion_queue_next() or
grpc_completion_queue_pluck() are called on the completion queue (unless the
grpc_cq_polling_type is GRPC_CQ_NON_POLLING) and hence it is very important
to actively call these APIs */
typedef enum {
/** The completion queue will have an associated pollset and there is no
restriction on the type of file descriptors the pollset may contain */
GRPC_CQ_DEFAULT_POLLING,
/** Similar to GRPC_CQ_DEFAULT_POLLING except that the completion queues will
not contain any 'listening file descriptors' (i.e file descriptors used to
listen to incoming channels) */
GRPC_CQ_NON_LISTENING,
/** The completion queue will not have an associated pollset. Note that
grpc_completion_queue_next() or grpc_completion_queue_pluck() MUST still
be called to pop events from the completion queue; it is not required to
call them actively to make I/O progress */
GRPC_CQ_NON_POLLING
} grpc_cq_polling_type;
/** Specifies the type of APIs to use to pop events from the completion queue */
typedef enum {
/** Events are popped out by calling grpc_completion_queue_next() API ONLY */
GRPC_CQ_NEXT = 1,
/** Events are popped out by calling grpc_completion_queue_pluck() API ONLY*/
GRPC_CQ_PLUCK
} grpc_cq_completion_type;
#define GRPC_CQ_CURRENT_VERSION 1
typedef struct grpc_completion_queue_attributes {
/* The version number of this structure. More fields might be added to this
structure in future. */
int version; /* Set to GRPC_CQ_CURRENT_VERSION */
grpc_cq_completion_type cq_completion_type;
grpc_cq_polling_type cq_polling_type;
} grpc_completion_queue_attributes;
/** The completion queue factory structure is opaque to the callers of grpc */
typedef struct grpc_completion_queue_factory grpc_completion_queue_factory;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -1408,4 +1408,180 @@ grpc::string GetSourceEpilogue(grpc_generator::File *file,
return temp; return temp;
} }
// TODO(mmukhi): Make sure we need parameters or not.
grpc::string GetMockPrologue(grpc_generator::File *file,
const Parameters & /*params*/) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
auto printer = file->CreatePrinter(&output);
std::map<grpc::string, grpc::string> vars;
vars["filename"] = file->filename();
vars["filename_base"] = file->filename_without_ext();
vars["message_header_ext"] = message_header_ext();
vars["service_header_ext"] = service_header_ext();
printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
printer->Print(vars,
"// If you make any local change, they will be lost.\n");
printer->Print(vars, "// source: $filename$\n\n");
printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
printer->Print(vars, file->additional_headers().c_str());
printer->Print(vars, "\n");
}
return output;
}
// TODO(mmukhi): Add client-stream and completion-queue headers.
grpc::string GetMockIncludes(grpc_generator::File *file,
const Parameters &params) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
auto printer = file->CreatePrinter(&output);
std::map<grpc::string, grpc::string> vars;
static const char *headers_strs[] = {
"grpc++/impl/codegen/async_stream.h",
"grpc++/impl/codegen/sync_stream.h", "gmock/gmock.h",
};
std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
PrintIncludes(printer.get(), headers, params);
if (!file->package().empty()) {
std::vector<grpc::string> parts = file->package_parts();
for (auto part = parts.begin(); part != parts.end(); part++) {
vars["part"] = *part;
printer->Print(vars, "namespace $part$ {\n");
}
}
printer->Print(vars, "\n");
}
return output;
}
void PrintMockClientMethods(grpc_generator::Printer *printer,
const grpc_generator::Method *method,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
(*vars)["Response"] = method->output_type_name();
if (method->NoStreaming()) {
printer->Print(
*vars,
"MOCK_METHOD3($Method$, ::grpc::Status(::grpc::ClientContext* context, "
"const $Request$& request, $Response$* response));\n");
printer->Print(*vars,
"MOCK_METHOD3(Async$Method$Raw, "
"::grpc::ClientAsyncResponseReaderInterface< $Response$>*"
"(::grpc::ClientContext* context, const $Request$& request, "
"::grpc::CompletionQueue* cq));\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(
*vars,
"MOCK_METHOD2($Method$Raw, "
"::grpc::ClientWriterInterface< $Request$>*"
"(::grpc::ClientContext* context, $Response$* response));\n");
printer->Print(*vars,
"MOCK_METHOD4(Async$Method$Raw, "
"::grpc::ClientAsyncWriterInterface< $Request$>*"
"(::grpc::ClientContext* context, $Response$* response, "
"::grpc::CompletionQueue* cq, void* tag));\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
"MOCK_METHOD2($Method$Raw, "
"::grpc::ClientReaderInterface< $Response$>*"
"(::grpc::ClientContext* context, const $Request$& request));\n");
printer->Print(*vars,
"MOCK_METHOD4(Async$Method$Raw, "
"::grpc::ClientAsyncReaderInterface< $Response$>*"
"(::grpc::ClientContext* context, const $Request$& request, "
"::grpc::CompletionQueue* cq, void* tag));\n");
} else if (method->BidiStreaming()) {
printer->Print(
*vars,
"MOCK_METHOD1($Method$Raw, "
"::grpc::ClientReaderWriterInterface< $Request$, $Response$>*"
"(::grpc::ClientContext* context));\n");
printer->Print(
*vars,
"MOCK_METHOD3(Async$Method$Raw, "
"::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*"
"(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, "
"void* tag));\n");
}
}
void PrintMockService(grpc_generator::Printer *printer,
const grpc_generator::Service *service,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name();
printer->Print(*vars,
"class Mock$Service$Stub : public $Service$::StubInterface {\n"
" public:\n");
printer->Indent();
for (int i = 0; i < service->method_count(); ++i) {
PrintMockClientMethods(printer, service->method(i).get(), vars);
}
printer->Outdent();
printer->Print("};\n");
}
grpc::string GetMockServices(grpc_generator::File *file,
const Parameters &params) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
auto printer = file->CreatePrinter(&output);
std::map<grpc::string, grpc::string> vars;
// Package string is empty or ends with a dot. It is used to fully qualify
// method names.
vars["Package"] = file->package();
if (!file->package().empty()) {
vars["Package"].append(".");
}
if (!params.services_namespace.empty()) {
vars["services_namespace"] = params.services_namespace;
printer->Print(vars, "\nnamespace $services_namespace$ {\n\n");
}
for (int i = 0; i < file->service_count(); i++) {
PrintMockService(printer.get(), file->service(i).get(), &vars);
printer->Print("\n");
}
if (!params.services_namespace.empty()) {
printer->Print(vars, "} // namespace $services_namespace$\n\n");
}
}
return output;
}
grpc::string GetMockEpilogue(grpc_generator::File *file,
const Parameters & /*params*/) {
grpc::string temp;
if (!file->package().empty()) {
std::vector<grpc::string> parts = file->package_parts();
for (auto part = parts.begin(); part != parts.end(); part++) {
temp.append("} // namespace ");
temp.append(*part);
temp.append("\n");
}
temp.append("\n");
}
return temp;
}
} // namespace grpc_cpp_generator } // namespace grpc_cpp_generator

@ -65,6 +65,8 @@ struct Parameters {
bool use_system_headers; bool use_system_headers;
// Prefix to any grpc include // Prefix to any grpc include
grpc::string grpc_search_path; grpc::string grpc_search_path;
// Generate GMOCK code to facilitate unit testing.
bool generate_mock_code;
}; };
// Return the prologue of the generated header file. // Return the prologue of the generated header file.
@ -99,6 +101,38 @@ grpc::string GetSourceServices(grpc_generator::File *file,
grpc::string GetSourceEpilogue(grpc_generator::File *file, grpc::string GetSourceEpilogue(grpc_generator::File *file,
const Parameters &params); const Parameters &params);
// Return the prologue of the generated mock file.
grpc::string GetMockPrologue(grpc_generator::File *file,
const Parameters &params);
// Return the includes needed for generated mock file.
grpc::string GetMockIncludes(grpc_generator::File *file,
const Parameters &params);
// Return the services for generated mock file.
grpc::string GetMockServices(grpc_generator::File *file,
const Parameters &params);
// Return the epilogue of generated mock file.
grpc::string GetMockEpilogue(grpc_generator::File *file,
const Parameters &params);
// Return the prologue of the generated mock file.
grpc::string GetMockPrologue(grpc_generator::File *file,
const Parameters &params);
// Return the includes needed for generated mock file.
grpc::string GetMockIncludes(grpc_generator::File *file,
const Parameters &params);
// Return the services for generated mock file.
grpc::string GetMockServices(grpc_generator::File *file,
const Parameters &params);
// Return the epilogue of generated mock file.
grpc::string GetMockEpilogue(grpc_generator::File *file,
const Parameters &params);
} // namespace grpc_cpp_generator } // namespace grpc_cpp_generator
#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H #endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H

@ -62,6 +62,7 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
grpc_cpp_generator::Parameters generator_parameters; grpc_cpp_generator::Parameters generator_parameters;
generator_parameters.use_system_headers = true; generator_parameters.use_system_headers = true;
generator_parameters.generate_mock_code = false;
ProtoBufFile pbfile(file); ProtoBufFile pbfile(file);
@ -85,6 +86,13 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
} }
} else if (param[0] == "grpc_search_path") { } else if (param[0] == "grpc_search_path") {
generator_parameters.grpc_search_path = param[1]; generator_parameters.grpc_search_path = param[1];
} else if (param[0] == "generate_mock_code") {
if (param[1] == "true") {
generator_parameters.generate_mock_code = true;
} else if (param[1] != "false") {
*error = grpc::string("Invalid parameter: ") + *parameter_string;
return false;
}
} else { } else {
*error = grpc::string("Unknown parameter: ") + *parameter_string; *error = grpc::string("Unknown parameter: ") + *parameter_string;
return false; return false;
@ -114,6 +122,19 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get()); grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get());
source_coded_out.WriteRaw(source_code.data(), source_code.size()); source_coded_out.WriteRaw(source_code.data(), source_code.size());
if (!generator_parameters.generate_mock_code) {
return true;
}
grpc::string mock_code =
grpc_cpp_generator::GetMockPrologue(&pbfile, generator_parameters) +
grpc_cpp_generator::GetMockIncludes(&pbfile, generator_parameters) +
grpc_cpp_generator::GetMockServices(&pbfile, generator_parameters) +
grpc_cpp_generator::GetMockEpilogue(&pbfile, generator_parameters);
std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> mock_output(
context->Open(file_name + "_mock.grpc.pb.h"));
grpc::protobuf::io::CodedOutputStream mock_coded_out(mock_output.get());
mock_coded_out.WriteRaw(mock_code.data(), mock_code.size());
return true; return true;
} }

@ -400,26 +400,24 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING); GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
lb_policy_name = channel_arg->value.string; lb_policy_name = channel_arg->value.string;
} }
// Special case: If all of the addresses are balancer addresses, // Special case: If at least one balancer address is present, we use
// assume that we should use the grpclb policy, regardless of what the // the grpclb policy, regardless of what the resolver actually specified.
// resolver actually specified.
channel_arg = channel_arg =
grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES); grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
if (channel_arg != NULL && channel_arg->type == GRPC_ARG_POINTER) { if (channel_arg != NULL && channel_arg->type == GRPC_ARG_POINTER) {
grpc_lb_addresses *addresses = channel_arg->value.pointer.p; grpc_lb_addresses *addresses = channel_arg->value.pointer.p;
bool found_backend_address = false; bool found_balancer_address = false;
for (size_t i = 0; i < addresses->num_addresses; ++i) { for (size_t i = 0; i < addresses->num_addresses; ++i) {
if (!addresses->addresses[i].is_balancer) { if (addresses->addresses[i].is_balancer) {
found_backend_address = true; found_balancer_address = true;
break; break;
} }
} }
if (!found_backend_address) { if (found_balancer_address) {
if (lb_policy_name != NULL && strcmp(lb_policy_name, "grpclb") != 0) { if (lb_policy_name != NULL && strcmp(lb_policy_name, "grpclb") != 0) {
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
"resolver requested LB policy %s but provided only balancer " "resolver requested LB policy %s but provided at least one "
"addresses, no backend addresses -- forcing use of grpclb LB " "balancer address -- forcing use of grpclb LB policy",
"policy",
lb_policy_name); lb_policy_name);
} }
lb_policy_name = "grpclb"; lb_policy_name = "grpclb";

@ -831,10 +831,10 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
/* Count the number of gRPC-LB addresses. There must be at least one. /* Count the number of gRPC-LB addresses. There must be at least one.
* TODO(roth): For now, we ignore non-balancer addresses, but in the * TODO(roth): For now, we ignore non-balancer addresses, but in the
* future, we may change the behavior such that we fall back to using * future, we may change the behavior such that we fall back to using
* the non-balancer addresses if we cannot reach any balancers. At that * the non-balancer addresses if we cannot reach any balancers. In the
* time, this should be changed to allow a list with no balancer addresses, * fallback case, we should use the LB policy indicated by
* since the resolver might fail to return a balancer address even when * GRPC_ARG_LB_POLICY_NAME (although if that specifies grpclb or is
* this is the right LB policy to use. */ * unset, we should default to pick_first). */
const grpc_arg *arg = const grpc_arg *arg =
grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
if (arg == NULL || arg->type != GRPC_ARG_POINTER) { if (arg == NULL || arg->type != GRPC_ARG_POINTER) {

@ -80,7 +80,7 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_lock(&connection_state->server_state->mu); gpr_mu_lock(&connection_state->server_state->mu);
if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) { if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) {
const char *error_str = grpc_error_string(error); const char *error_str = grpc_error_string(error);
gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str); gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str);
if (error == GRPC_ERROR_NONE && args->endpoint != NULL) { if (error == GRPC_ERROR_NONE && args->endpoint != NULL) {
// We were shut down after handshaking completed successfully, so // We were shut down after handshaking completed successfully, so

@ -92,6 +92,11 @@ struct grpc_udp_listener {
struct grpc_udp_listener *next; struct grpc_udp_listener *next;
}; };
struct shutdown_fd_args {
grpc_fd *fd;
gpr_mu *server_mu;
};
/* the overall server */ /* the overall server */
struct grpc_udp_server { struct grpc_udp_server {
gpr_mu mu; gpr_mu mu;
@ -151,8 +156,13 @@ grpc_udp_server *grpc_udp_server_create(const grpc_channel_args *args) {
return s; return s;
} }
static void shutdown_fd(grpc_exec_ctx *exec_ctx, void *fd, grpc_error *error) { static void shutdown_fd(grpc_exec_ctx *exec_ctx, void *args,
grpc_fd_shutdown(exec_ctx, (grpc_fd *)fd, GRPC_ERROR_REF(error)); grpc_error *error) {
struct shutdown_fd_args *shutdown_args = (struct shutdown_fd_args *)args;
gpr_mu_lock(shutdown_args->server_mu);
grpc_fd_shutdown(exec_ctx, shutdown_args->fd, GRPC_ERROR_REF(error));
gpr_mu_unlock(shutdown_args->server_mu);
gpr_free(shutdown_args);
} }
static void dummy_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { static void dummy_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
@ -242,7 +252,10 @@ void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *s,
if (s->active_ports) { if (s->active_ports) {
for (sp = s->head; sp; sp = sp->next) { for (sp = s->head; sp; sp = sp->next) {
GPR_ASSERT(sp->orphan_cb); GPR_ASSERT(sp->orphan_cb);
grpc_closure_init(&sp->orphan_fd_closure, shutdown_fd, sp->emfd, struct shutdown_fd_args *args = gpr_malloc(sizeof(*args));
args->fd = sp->emfd;
args->server_mu = &s->mu;
grpc_closure_init(&sp->orphan_fd_closure, shutdown_fd, args,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
sp->orphan_cb(exec_ctx, sp->emfd, &sp->orphan_fd_closure, sp->orphan_cb(exec_ctx, sp->emfd, &sp->orphan_fd_closure,
sp->server->user_data); sp->server->user_data);

@ -76,13 +76,13 @@ struct gpr_stack_lockfree {
gpr_stack_lockfree *gpr_stack_lockfree_create(size_t entries) { gpr_stack_lockfree *gpr_stack_lockfree_create(size_t entries) {
gpr_stack_lockfree *stack; gpr_stack_lockfree *stack;
stack = gpr_malloc(sizeof(*stack)); stack = (gpr_stack_lockfree *)gpr_malloc(sizeof(*stack));
/* Since we only allocate 16 bits to represent an entry number, /* Since we only allocate 16 bits to represent an entry number,
* make sure that we are within the desired range */ * make sure that we are within the desired range */
/* Reserve the highest entry number as a dummy */ /* Reserve the highest entry number as a dummy */
GPR_ASSERT(entries < INVALID_ENTRY_INDEX); GPR_ASSERT(entries < INVALID_ENTRY_INDEX);
stack->entries = gpr_malloc_aligned(entries * sizeof(stack->entries[0]), stack->entries = (lockfree_node *)gpr_malloc_aligned(
ENTRY_ALIGNMENT_BITS); entries * sizeof(stack->entries[0]), ENTRY_ALIGNMENT_BITS);
/* Clear out all entries */ /* Clear out all entries */
memset(stack->entries, 0, entries * sizeof(stack->entries[0])); memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
memset(&stack->head, 0, sizeof(stack->head)); memset(&stack->head, 0, sizeof(stack->head));

@ -42,6 +42,7 @@
#ifdef __linux__ #ifdef __linux__
#include <sys/syscall.h> #include <sys/syscall.h>
#endif #endif
#include <grpc/support/atm.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "src/core/lib/support/block_annotate.h" #include "src/core/lib/support/block_annotate.h"
@ -144,7 +145,14 @@ static gpr_timespec now_impl(gpr_clock_type clock) {
gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type) = now_impl; gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type) = now_impl;
#ifdef GPR_LOW_LEVEL_COUNTERS
gpr_atm gpr_now_call_count;
#endif
gpr_timespec gpr_now(gpr_clock_type clock_type) { gpr_timespec gpr_now(gpr_clock_type clock_type) {
#ifdef GPR_LOW_LEVEL_COUNTERS
__atomic_fetch_add(&gpr_now_call_count, 1, __ATOMIC_RELAXED);
#endif
return gpr_now_impl(clock_type); return gpr_now_impl(clock_type);
} }

@ -50,34 +50,34 @@
FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) { FILE *gpr_tmpfile(const char *prefix, char **tmp_filename) {
FILE *result = NULL; FILE *result = NULL;
char *template; char *filename_template;
int fd; int fd;
if (tmp_filename != NULL) *tmp_filename = NULL; if (tmp_filename != NULL) *tmp_filename = NULL;
gpr_asprintf(&template, "/tmp/%s_XXXXXX", prefix); gpr_asprintf(&filename_template, "/tmp/%s_XXXXXX", prefix);
GPR_ASSERT(template != NULL); GPR_ASSERT(filename_template != NULL);
fd = mkstemp(template); fd = mkstemp(filename_template);
if (fd == -1) { if (fd == -1) {
gpr_log(GPR_ERROR, "mkstemp failed for template %s with error %s.", gpr_log(GPR_ERROR, "mkstemp failed for filename_template %s with error %s.",
template, strerror(errno)); filename_template, strerror(errno));
goto end; goto end;
} }
result = fdopen(fd, "w+"); result = fdopen(fd, "w+");
if (result == NULL) { if (result == NULL) {
gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).", gpr_log(GPR_ERROR, "Could not open file %s from fd %d (error = %s).",
template, fd, strerror(errno)); filename_template, fd, strerror(errno));
unlink(template); unlink(filename_template);
close(fd); close(fd);
goto end; goto end;
} }
end: end:
if (result != NULL && tmp_filename != NULL) { if (result != NULL && tmp_filename != NULL) {
*tmp_filename = template; *tmp_filename = filename_template;
} else { } else {
gpr_free(template); gpr_free(filename_template);
} }
return result; return result;
} }

@ -60,13 +60,154 @@ typedef struct {
void *tag; void *tag;
} plucker; } plucker;
typedef struct {
bool can_get_pollset;
bool can_listen;
size_t (*size)(void);
void (*init)(grpc_pollset *pollset, gpr_mu **mu);
grpc_error *(*kick)(grpc_pollset *pollset,
grpc_pollset_worker *specific_worker);
grpc_error *(*work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker **worker, gpr_timespec now,
gpr_timespec deadline);
void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_closure *closure);
void (*destroy)(grpc_pollset *pollset);
} cq_poller_vtable;
typedef struct non_polling_worker {
gpr_cv cv;
bool kicked;
struct non_polling_worker *next;
struct non_polling_worker *prev;
} non_polling_worker;
typedef struct {
gpr_mu mu;
non_polling_worker *root;
grpc_closure *shutdown;
} non_polling_poller;
static size_t non_polling_poller_size(void) {
return sizeof(non_polling_poller);
}
static void non_polling_poller_init(grpc_pollset *pollset, gpr_mu **mu) {
non_polling_poller *npp = (non_polling_poller *)pollset;
gpr_mu_init(&npp->mu);
*mu = &npp->mu;
}
static void non_polling_poller_destroy(grpc_pollset *pollset) {
non_polling_poller *npp = (non_polling_poller *)pollset;
gpr_mu_destroy(&npp->mu);
}
static grpc_error *non_polling_poller_work(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset,
grpc_pollset_worker **worker,
gpr_timespec now,
gpr_timespec deadline) {
non_polling_poller *npp = (non_polling_poller *)pollset;
if (npp->shutdown) return GRPC_ERROR_NONE;
non_polling_worker w;
gpr_cv_init(&w.cv);
if (worker != NULL) *worker = (grpc_pollset_worker *)&w;
if (npp->root == NULL) {
npp->root = w.next = w.prev = &w;
} else {
w.next = npp->root;
w.prev = w.next->prev;
w.next->prev = w.prev->next = &w;
}
w.kicked = false;
while (!npp->shutdown && !w.kicked && !gpr_cv_wait(&w.cv, &npp->mu, deadline))
;
if (&w == npp->root) {
npp->root = w.next;
if (&w == npp->root) {
if (npp->shutdown) {
grpc_closure_sched(exec_ctx, npp->shutdown, GRPC_ERROR_NONE);
}
npp->root = NULL;
}
}
w.next->prev = w.prev;
w.prev->next = w.next;
gpr_cv_destroy(&w.cv);
if (worker != NULL) *worker = NULL;
return GRPC_ERROR_NONE;
}
static grpc_error *non_polling_poller_kick(
grpc_pollset *pollset, grpc_pollset_worker *specific_worker) {
non_polling_poller *p = (non_polling_poller *)pollset;
if (specific_worker == NULL) specific_worker = (grpc_pollset_worker *)p->root;
if (specific_worker != NULL) {
non_polling_worker *w = (non_polling_worker *)specific_worker;
if (!w->kicked) {
w->kicked = true;
gpr_cv_signal(&w->cv);
}
}
return GRPC_ERROR_NONE;
}
static void non_polling_poller_shutdown(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset,
grpc_closure *closure) {
non_polling_poller *p = (non_polling_poller *)pollset;
GPR_ASSERT(closure != NULL);
p->shutdown = closure;
if (p->root == NULL) {
grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
} else {
non_polling_worker *w = p->root;
do {
gpr_cv_signal(&w->cv);
w = w->next;
} while (w != p->root);
}
}
static const cq_poller_vtable g_poller_vtable_by_poller_type[] = {
/* GRPC_CQ_DEFAULT_POLLING */
{.can_get_pollset = true,
.can_listen = true,
.size = grpc_pollset_size,
.init = grpc_pollset_init,
.kick = grpc_pollset_kick,
.work = grpc_pollset_work,
.shutdown = grpc_pollset_shutdown,
.destroy = grpc_pollset_destroy},
/* GRPC_CQ_NON_LISTENING */
{.can_get_pollset = true,
.can_listen = false,
.size = grpc_pollset_size,
.init = grpc_pollset_init,
.kick = grpc_pollset_kick,
.work = grpc_pollset_work,
.shutdown = grpc_pollset_shutdown,
.destroy = grpc_pollset_destroy},
/* GRPC_CQ_NON_POLLING */
{.can_get_pollset = false,
.can_listen = false,
.size = non_polling_poller_size,
.init = non_polling_poller_init,
.kick = non_polling_poller_kick,
.work = non_polling_poller_work,
.shutdown = non_polling_poller_shutdown,
.destroy = non_polling_poller_destroy},
};
/* Completion queue structure */ /* Completion queue structure */
struct grpc_completion_queue { struct grpc_completion_queue {
/** owned by pollset */ /** owned by pollset */
gpr_mu *mu; gpr_mu *mu;
grpc_cq_completion_type completion_type; grpc_cq_completion_type completion_type;
grpc_cq_polling_type polling_type;
const cq_poller_vtable *poller_vtable;
/** completed events */ /** completed events */
grpc_cq_completion completed_head; grpc_cq_completion completed_head;
@ -127,15 +268,18 @@ grpc_completion_queue *grpc_completion_queue_create_internal(
"polling_type=%d)", "polling_type=%d)",
2, (completion_type, polling_type)); 2, (completion_type, polling_type));
cc = gpr_zalloc(sizeof(grpc_completion_queue) + grpc_pollset_size()); const cq_poller_vtable *poller_vtable =
grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu); &g_poller_vtable_by_poller_type[polling_type];
cc = gpr_zalloc(sizeof(grpc_completion_queue) + poller_vtable->size());
poller_vtable->init(POLLSET_FROM_CQ(cc), &cc->mu);
#ifndef NDEBUG #ifndef NDEBUG
cc->outstanding_tags = NULL; cc->outstanding_tags = NULL;
cc->outstanding_tag_capacity = 0; cc->outstanding_tag_capacity = 0;
#endif #endif
cc->completion_type = completion_type; cc->completion_type = completion_type;
cc->polling_type = polling_type; cc->poller_vtable = poller_vtable;
/* Initial ref is dropped by grpc_completion_queue_shutdown */ /* Initial ref is dropped by grpc_completion_queue_shutdown */
gpr_ref_init(&cc->pending_events, 1); gpr_ref_init(&cc->pending_events, 1);
@ -164,10 +308,6 @@ grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc) {
return cc->completion_type; return cc->completion_type;
} }
grpc_cq_polling_type grpc_get_cq_polling_type(grpc_completion_queue *cc) {
return cc->polling_type;
}
#ifdef GRPC_CQ_REF_COUNT_DEBUG #ifdef GRPC_CQ_REF_COUNT_DEBUG
void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason, void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason,
const char *file, int line) { const char *file, int line) {
@ -195,7 +335,7 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc) {
#endif #endif
if (gpr_unref(&cc->owning_refs)) { if (gpr_unref(&cc->owning_refs)) {
GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head); GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head);
grpc_pollset_destroy(POLLSET_FROM_CQ(cc)); cc->poller_vtable->destroy(POLLSET_FROM_CQ(cc));
#ifndef NDEBUG #ifndef NDEBUG
gpr_free(cc->outstanding_tags); gpr_free(cc->outstanding_tags);
#endif #endif
@ -280,7 +420,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
} }
} }
grpc_error *kick_error = grpc_error *kick_error =
grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker); cc->poller_vtable->kick(POLLSET_FROM_CQ(cc), pluck_worker);
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
if (kick_error != GRPC_ERROR_NONE) { if (kick_error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(kick_error); const char *msg = grpc_error_string(kick_error);
@ -295,7 +435,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
GPR_ASSERT(!cc->shutdown); GPR_ASSERT(!cc->shutdown);
GPR_ASSERT(cc->shutdown_called); GPR_ASSERT(cc->shutdown_called);
cc->shutdown = 1; cc->shutdown = 1;
grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc), cc->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cc),
&cc->pollset_shutdown_done); &cc->pollset_shutdown_done);
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
} }
@ -452,8 +592,8 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_mu_lock(cc->mu); gpr_mu_lock(cc->mu);
continue; continue;
} else { } else {
grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), NULL, grpc_error *err = cc->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cc),
now, iteration_deadline); NULL, now, iteration_deadline);
if (err != GRPC_ERROR_NONE) { if (err != GRPC_ERROR_NONE) {
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
const char *msg = grpc_error_string(err); const char *msg = grpc_error_string(err);
@ -644,8 +784,8 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
grpc_exec_ctx_flush(&exec_ctx); grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(cc->mu); gpr_mu_lock(cc->mu);
} else { } else {
grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), grpc_error *err = cc->poller_vtable->work(
&worker, now, iteration_deadline); &exec_ctx, POLLSET_FROM_CQ(cc), &worker, now, iteration_deadline);
if (err != GRPC_ERROR_NONE) { if (err != GRPC_ERROR_NONE) {
del_plucker(cc, tag, &worker); del_plucker(cc, tag, &worker);
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
@ -689,7 +829,7 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
if (gpr_unref(&cc->pending_events)) { if (gpr_unref(&cc->pending_events)) {
GPR_ASSERT(!cc->shutdown); GPR_ASSERT(!cc->shutdown);
cc->shutdown = 1; cc->shutdown = 1;
grpc_pollset_shutdown(&exec_ctx, POLLSET_FROM_CQ(cc), cc->poller_vtable->shutdown(&exec_ctx, POLLSET_FROM_CQ(cc),
&cc->pollset_shutdown_done); &cc->pollset_shutdown_done);
} }
gpr_mu_unlock(cc->mu); gpr_mu_unlock(cc->mu);
@ -706,7 +846,7 @@ void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
} }
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) { grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
return POLLSET_FROM_CQ(cc); return cc->poller_vtable->can_get_pollset ? POLLSET_FROM_CQ(cc) : NULL;
} }
grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps) { grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps) {
@ -727,4 +867,10 @@ bool grpc_cq_is_non_listening_server_cq(grpc_completion_queue *cc) {
void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; } void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; }
int grpc_cq_is_server_cq(grpc_completion_queue *cc) { return cc->is_server_cq; } bool grpc_cq_is_server_cq(grpc_completion_queue *cc) {
return cc->is_server_cq;
}
bool grpc_cq_can_listen(grpc_completion_queue *cc) {
return cc->poller_vtable->can_listen;
}

@ -94,13 +94,11 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc); grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps); grpc_completion_queue *grpc_cq_from_pollset(grpc_pollset *ps);
void grpc_cq_mark_non_listening_server_cq(grpc_completion_queue *cc);
bool grpc_cq_is_non_listening_server_cq(grpc_completion_queue *cc);
void grpc_cq_mark_server_cq(grpc_completion_queue *cc); void grpc_cq_mark_server_cq(grpc_completion_queue *cc);
int grpc_cq_is_server_cq(grpc_completion_queue *cc); bool grpc_cq_is_server_cq(grpc_completion_queue *cc);
bool grpc_cq_can_listen(grpc_completion_queue *cc);
grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc); grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc);
grpc_cq_polling_type grpc_get_cq_polling_type(grpc_completion_queue *cc);
grpc_completion_queue *grpc_completion_queue_create_internal( grpc_completion_queue *grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type); grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type);

@ -981,7 +981,7 @@ const grpc_channel_filter grpc_server_top_filter = {
static void register_completion_queue(grpc_server *server, static void register_completion_queue(grpc_server *server,
grpc_completion_queue *cq, grpc_completion_queue *cq,
bool is_non_listening, void *reserved) { void *reserved) {
size_t i, n; size_t i, n;
GPR_ASSERT(!reserved); GPR_ASSERT(!reserved);
for (i = 0; i < server->cq_count; i++) { for (i = 0; i < server->cq_count; i++) {
@ -990,10 +990,6 @@ static void register_completion_queue(grpc_server *server,
grpc_cq_mark_server_cq(cq); grpc_cq_mark_server_cq(cq);
if (is_non_listening) {
grpc_cq_mark_non_listening_server_cq(cq);
}
GRPC_CQ_INTERNAL_REF(cq, "server"); GRPC_CQ_INTERNAL_REF(cq, "server");
n = server->cq_count++; n = server->cq_count++;
server->cqs = gpr_realloc(server->cqs, server->cqs = gpr_realloc(server->cqs,
@ -1016,16 +1012,7 @@ void grpc_server_register_completion_queue(grpc_server *server,
calls grpc_completion_queue_pluck() on server completion queues */ calls grpc_completion_queue_pluck() on server completion queues */
} }
register_completion_queue(server, cq, false, reserved); register_completion_queue(server, cq, reserved);
}
void grpc_server_register_non_listening_completion_queue(
grpc_server *server, grpc_completion_queue *cq, void *reserved) {
GRPC_API_TRACE(
"grpc_server_register_non_listening_completion_queue(server=%p, cq=%p, "
"reserved=%p)",
3, (server, cq, reserved));
register_completion_queue(server, cq, true, reserved);
} }
grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
@ -1121,7 +1108,7 @@ void grpc_server_start(grpc_server *server) {
server->requested_calls_per_cq = server->requested_calls_per_cq =
gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count); gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count);
for (i = 0; i < server->cq_count; i++) { for (i = 0; i < server->cq_count; i++) {
if (!grpc_cq_is_non_listening_server_cq(server->cqs[i])) { if (grpc_cq_can_listen(server->cqs[i])) {
server->pollsets[server->pollset_count++] = server->pollsets[server->pollset_count++] =
grpc_cq_pollset(server->cqs[i]); grpc_cq_pollset(server->cqs[i]);
} }

@ -54,6 +54,18 @@ struct grpc_byte_buffer;
namespace grpc { namespace grpc {
const grpc_completion_queue_factory*
CoreCodegen::grpc_completion_queue_factory_lookup(
const grpc_completion_queue_attributes* attributes) {
return ::grpc_completion_queue_factory_lookup(attributes);
}
grpc_completion_queue* CoreCodegen::grpc_completion_queue_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attributes, void* reserved) {
return ::grpc_completion_queue_create(factory, attributes, reserved);
}
grpc_completion_queue* CoreCodegen::grpc_completion_queue_create_for_next( grpc_completion_queue* CoreCodegen::grpc_completion_queue_create_for_next(
void* reserved) { void* reserved) {
return ::grpc_completion_queue_create_for_next(reserved); return ::grpc_completion_queue_create_for_next(reserved);

@ -83,7 +83,8 @@ ServerBuilder::~ServerBuilder() {
std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue( std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
bool is_frequently_polled) { bool is_frequently_polled) {
ServerCompletionQueue* cq = new ServerCompletionQueue(is_frequently_polled); ServerCompletionQueue* cq = new ServerCompletionQueue(
is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING);
cqs_.push_back(cq); cqs_.push_back(cq);
return std::unique_ptr<ServerCompletionQueue>(cq); return std::unique_ptr<ServerCompletionQueue>(cq);
} }
@ -242,6 +243,16 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
sync_server_cqs(std::make_shared< sync_server_cqs(std::make_shared<
std::vector<std::unique_ptr<ServerCompletionQueue>>>()); std::vector<std::unique_ptr<ServerCompletionQueue>>>());
int num_frequently_polled_cqs = 0;
for (auto it = cqs_.begin(); it != cqs_.end(); ++it) {
if ((*it)->IsFrequentlyPolled()) {
num_frequently_polled_cqs++;
}
}
const bool is_hybrid_server =
has_sync_methods && num_frequently_polled_cqs > 0;
if (has_sync_methods) { if (has_sync_methods) {
// This is a Sync server // This is a Sync server
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
@ -251,9 +262,12 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
sync_server_settings_.max_pollers, sync_server_settings_.max_pollers,
sync_server_settings_.cq_timeout_msec); sync_server_settings_.cq_timeout_msec);
grpc_cq_polling_type polling_type =
is_hybrid_server ? GRPC_CQ_NON_POLLING : GRPC_CQ_DEFAULT_POLLING;
// Create completion queues to listen to incoming rpc requests // Create completion queues to listen to incoming rpc requests
for (int i = 0; i < sync_server_settings_.num_cqs; i++) { for (int i = 0; i < sync_server_settings_.num_cqs; i++) {
sync_server_cqs->emplace_back(new ServerCompletionQueue()); sync_server_cqs->emplace_back(new ServerCompletionQueue(polling_type));
} }
} }
@ -269,12 +283,10 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
// server // server
// 2. cqs_: Completion queues added via AddCompletionQueue() call // 2. cqs_: Completion queues added via AddCompletionQueue() call
// All sync cqs (if any) are frequently polled by ThreadManager
int num_frequently_polled_cqs = sync_server_cqs->size();
for (auto it = sync_server_cqs->begin(); it != sync_server_cqs->end(); ++it) { for (auto it = sync_server_cqs->begin(); it != sync_server_cqs->end(); ++it) {
grpc_server_register_completion_queue(server->server_, (*it)->cq(), grpc_server_register_completion_queue(server->server_, (*it)->cq(),
nullptr); nullptr);
num_frequently_polled_cqs++;
} }
// cqs_ contains the completion queue added by calling the ServerBuilder's // cqs_ contains the completion queue added by calling the ServerBuilder's
@ -283,14 +295,8 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
// listening to incoming channels. Such completion queues must be registered // listening to incoming channels. Such completion queues must be registered
// as non-listening queues // as non-listening queues
for (auto it = cqs_.begin(); it != cqs_.end(); ++it) { for (auto it = cqs_.begin(); it != cqs_.end(); ++it) {
if ((*it)->IsFrequentlyPolled()) {
grpc_server_register_completion_queue(server->server_, (*it)->cq(), grpc_server_register_completion_queue(server->server_, (*it)->cq(),
nullptr); nullptr);
num_frequently_polled_cqs++;
} else {
grpc_server_register_non_listening_completion_queue(server->server_,
(*it)->cq(), nullptr);
}
} }
if (num_frequently_polled_cqs == 0) { if (num_frequently_polled_cqs == 0) {

@ -44,9 +44,11 @@ namespace grpc {
namespace node { namespace node {
Server::Server(grpc_server *server) : wrapped_server(server) { Server::Server(grpc_server *server) : wrapped_server(server) {
shutdown_queue = grpc_completion_queue_create_for_pluck(NULL); grpc_completion_queue_attributes attrs = {
grpc_server_register_non_listening_completion_queue(server, shutdown_queue, GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, GRPC_CQ_NON_LISTENING};
NULL); shutdown_queue = grpc_completion_queue_create(
grpc_completion_queue_factory_lookup(&attrs), &attrs, NULL);
grpc_server_register_completion_queue(server, shutdown_queue, NULL);
} }
Server::~Server() { Server::~Server() {

@ -0,0 +1,39 @@
# Copyright 2017, 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.
licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//visibility:public"])
load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
grpc_proto_library(
name = "health_proto",
srcs = ["health.proto"],
)

@ -36,6 +36,7 @@ load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
grpc_proto_library( grpc_proto_library(
name = "compiler_test_proto", name = "compiler_test_proto",
srcs = ["compiler_test.proto"], srcs = ["compiler_test.proto"],
generate_mock = True,
) )
grpc_proto_library( grpc_proto_library(
@ -55,6 +56,7 @@ grpc_proto_library(
name = "echo_proto", name = "echo_proto",
srcs = ["echo.proto"], srcs = ["echo.proto"],
deps = ["echo_messages_proto"], deps = ["echo_messages_proto"],
generate_mock = True,
) )
grpc_proto_library( grpc_proto_library(

@ -59,6 +59,14 @@ service ServiceA {
// Method A2 leading comment 2 // Method A2 leading comment 2
rpc MethodA2(stream Request) returns (Response); rpc MethodA2(stream Request) returns (Response);
// MethodA2 trailing comment 1 // MethodA2 trailing comment 1
// Method A3 leading comment 1
rpc MethodA3(Request) returns (stream Response);
// Method A3 trailing comment 1
// Method A4 leading comment 1
rpc MethodA4(stream Request) returns (stream Response);
// Method A4 trailing comment 1
} }
// Ignored ServiceA trailing comment 1 // Ignored ServiceA trailing comment 1

@ -356,8 +356,6 @@ cdef extern from "grpc/grpc.h":
void grpc_server_register_completion_queue(grpc_server *server, void grpc_server_register_completion_queue(grpc_server *server,
grpc_completion_queue *cq, grpc_completion_queue *cq,
void *reserved) nogil void *reserved) nogil
void grpc_server_register_non_listening_completion_queue(
grpc_server *server, grpc_completion_queue *cq, void *reserved) nogil
int grpc_server_add_insecure_http2_port( int grpc_server_add_insecure_http2_port(
grpc_server *server, const char *addr) nogil grpc_server *server, const char *addr) nogil
void grpc_server_start(grpc_server *server) nogil void grpc_server_start(grpc_server *server) nogil
@ -502,4 +500,3 @@ cdef extern from "grpc/compression.h":
int grpc_compression_options_is_algorithm_enabled( int grpc_compression_options_is_algorithm_enabled(
const grpc_compression_options *opts, const grpc_compression_options *opts,
grpc_compression_algorithm algorithm) nogil grpc_compression_algorithm algorithm) nogil

@ -82,20 +82,11 @@ cdef class Server:
self.c_server, queue.c_completion_queue, NULL) self.c_server, queue.c_completion_queue, NULL)
self.registered_completion_queues.append(queue) self.registered_completion_queues.append(queue)
def register_non_listening_completion_queue(
self, CompletionQueue queue not None):
if self.is_started:
raise ValueError("cannot register completion queues after start")
with nogil:
grpc_server_register_non_listening_completion_queue(
self.c_server, queue.c_completion_queue, NULL)
self.registered_completion_queues.append(queue)
def start(self): def start(self):
if self.is_started: if self.is_started:
raise ValueError("the server has already started") raise ValueError("the server has already started")
self.backup_shutdown_queue = CompletionQueue() self.backup_shutdown_queue = CompletionQueue()
self.register_non_listening_completion_queue(self.backup_shutdown_queue) self.register_completion_queue(self.backup_shutdown_queue)
self.is_started = True self.is_started = True
with nogil: with nogil:
grpc_server_start(self.c_server) grpc_server_start(self.c_server)

@ -127,7 +127,6 @@ grpc_server_register_method_type grpc_server_register_method_import;
grpc_server_request_registered_call_type grpc_server_request_registered_call_import; grpc_server_request_registered_call_type grpc_server_request_registered_call_import;
grpc_server_create_type grpc_server_create_import; grpc_server_create_type grpc_server_create_import;
grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import; grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
grpc_server_register_non_listening_completion_queue_type grpc_server_register_non_listening_completion_queue_import;
grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import; grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import;
grpc_server_start_type grpc_server_start_import; grpc_server_start_type grpc_server_start_import;
grpc_server_shutdown_and_notify_type grpc_server_shutdown_and_notify_import; grpc_server_shutdown_and_notify_type grpc_server_shutdown_and_notify_import;
@ -425,7 +424,6 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_server_request_registered_call_import = (grpc_server_request_registered_call_type) GetProcAddress(library, "grpc_server_request_registered_call"); grpc_server_request_registered_call_import = (grpc_server_request_registered_call_type) GetProcAddress(library, "grpc_server_request_registered_call");
grpc_server_create_import = (grpc_server_create_type) GetProcAddress(library, "grpc_server_create"); grpc_server_create_import = (grpc_server_create_type) GetProcAddress(library, "grpc_server_create");
grpc_server_register_completion_queue_import = (grpc_server_register_completion_queue_type) GetProcAddress(library, "grpc_server_register_completion_queue"); grpc_server_register_completion_queue_import = (grpc_server_register_completion_queue_type) GetProcAddress(library, "grpc_server_register_completion_queue");
grpc_server_register_non_listening_completion_queue_import = (grpc_server_register_non_listening_completion_queue_type) GetProcAddress(library, "grpc_server_register_non_listening_completion_queue");
grpc_server_add_insecure_http2_port_import = (grpc_server_add_insecure_http2_port_type) GetProcAddress(library, "grpc_server_add_insecure_http2_port"); grpc_server_add_insecure_http2_port_import = (grpc_server_add_insecure_http2_port_type) GetProcAddress(library, "grpc_server_add_insecure_http2_port");
grpc_server_start_import = (grpc_server_start_type) GetProcAddress(library, "grpc_server_start"); grpc_server_start_import = (grpc_server_start_type) GetProcAddress(library, "grpc_server_start");
grpc_server_shutdown_and_notify_import = (grpc_server_shutdown_and_notify_type) GetProcAddress(library, "grpc_server_shutdown_and_notify"); grpc_server_shutdown_and_notify_import = (grpc_server_shutdown_and_notify_type) GetProcAddress(library, "grpc_server_shutdown_and_notify");

@ -332,9 +332,6 @@ extern grpc_server_create_type grpc_server_create_import;
typedef void(*grpc_server_register_completion_queue_type)(grpc_server *server, grpc_completion_queue *cq, void *reserved); typedef void(*grpc_server_register_completion_queue_type)(grpc_server *server, grpc_completion_queue *cq, void *reserved);
extern grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import; extern grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
#define grpc_server_register_completion_queue grpc_server_register_completion_queue_import #define grpc_server_register_completion_queue grpc_server_register_completion_queue_import
typedef void(*grpc_server_register_non_listening_completion_queue_type)(grpc_server *server, grpc_completion_queue *q, void *reserved);
extern grpc_server_register_non_listening_completion_queue_type grpc_server_register_non_listening_completion_queue_import;
#define grpc_server_register_non_listening_completion_queue grpc_server_register_non_listening_completion_queue_import
typedef int(*grpc_server_add_insecure_http2_port_type)(grpc_server *server, const char *addr); typedef int(*grpc_server_add_insecure_http2_port_type)(grpc_server *server, const char *addr);
extern grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import; extern grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import;
#define grpc_server_add_insecure_http2_port grpc_server_add_insecure_http2_port_import #define grpc_server_add_insecure_http2_port grpc_server_add_insecure_http2_port_import

@ -311,7 +311,7 @@
USE_BUILT_PROTOC = false USE_BUILT_PROTOC = false
endif endif
GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc -Ithird_party/googletest/googlemock/include -Ithird_party/googletest/googlemock third_party/googletest/googlemock/src/gmock-all.cc
GTEST_LIB += -lgflags GTEST_LIB += -lgflags
ifeq ($(V),1) ifeq ($(V),1)
E = @: E = @:
@ -716,7 +716,7 @@
PC_REQUIRES_GRPCXX = PC_REQUIRES_GRPCXX =
PC_LIBS_GRPCXX = PC_LIBS_GRPCXX =
CPPFLAGS := -Ithird_party/googletest/googletest/include $(CPPFLAGS) CPPFLAGS := -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googlemock/include $(CPPFLAGS)
PROTOC_PLUGINS_ALL =\ PROTOC_PLUGINS_ALL =\
% for tgt in targets: % for tgt in targets:
@ -1240,6 +1240,14 @@
$(GENDIR)/${p}.pb.cc: protoc_dep_error $(GENDIR)/${p}.pb.cc: protoc_dep_error
$(GENDIR)/${p}.grpc.pb.cc: protoc_dep_error $(GENDIR)/${p}.grpc.pb.cc: protoc_dep_error
else else
<%
pluginflags=""
%>
% if p in ["src/proto/grpc/testing/compiler_test", "src/proto/grpc/testing/echo"]:
<%
pluginflags="generate_mock_code=true:"
%>
% endif
$(GENDIR)/${p}.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc' % q for q in proto_deps.get(p, []))} $(GENDIR)/${p}.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc' % q for q in proto_deps.get(p, []))}
$(E) "[PROTOC] Generating protobuf CC file from $<" $(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
@ -1248,7 +1256,7 @@
$(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc $(GENDIR)/%s.grpc.pb.cc' % (q,q) for q in proto_deps.get(p, []))} $(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc $(GENDIR)/%s.grpc.pb.cc' % (q,q) for q in proto_deps.get(p, []))}
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@` $(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $< $(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=${pluginflags}$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
endif endif
% endfor % endfor

@ -9,7 +9,7 @@
for f in src: for f in src:
name, ext = os.path.splitext(f) name, ext = os.path.splitext(f)
if ext == '.proto': if ext == '.proto':
out.extend(fmt % name for fmt in ['%s.grpc.pb.h', '%s.pb.h']) out.extend(fmt % name for fmt in ['%s.grpc.pb.h', '%s.pb.h', '%s_mock.grpc.pb.h'])
return out return out
def all_targets(targets, libs, filegroups): def all_targets(targets, libs, filegroups):

@ -59,6 +59,7 @@
#include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/tcp_client.h" #include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/iomgr/tcp_server.h" #include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_internal.h"
#include "test/core/util/port.h" #include "test/core/util/port.h"
@ -69,7 +70,7 @@ struct grpc_end2end_http_proxy {
grpc_channel_args* channel_args; grpc_channel_args* channel_args;
gpr_mu* mu; gpr_mu* mu;
grpc_pollset* pollset; grpc_pollset* pollset;
gpr_atm shutdown; gpr_refcount users;
}; };
// //
@ -77,6 +78,8 @@ struct grpc_end2end_http_proxy {
// //
typedef struct proxy_connection { typedef struct proxy_connection {
grpc_end2end_http_proxy* proxy;
grpc_endpoint* client_endpoint; grpc_endpoint* client_endpoint;
grpc_endpoint* server_endpoint; grpc_endpoint* server_endpoint;
@ -103,13 +106,20 @@ typedef struct proxy_connection {
grpc_http_request http_request; grpc_http_request http_request;
} proxy_connection; } proxy_connection;
static void proxy_connection_ref(proxy_connection* conn, const char* reason) {
gpr_ref(&conn->refcount);
}
// Helper function to destroy the proxy connection. // Helper function to destroy the proxy connection.
static void proxy_connection_unref(grpc_exec_ctx* exec_ctx, static void proxy_connection_unref(grpc_exec_ctx* exec_ctx,
proxy_connection* conn) { proxy_connection* conn, const char* reason) {
if (gpr_unref(&conn->refcount)) { if (gpr_unref(&conn->refcount)) {
gpr_log(GPR_DEBUG, "endpoints: %p %p", conn->client_endpoint,
conn->server_endpoint);
grpc_endpoint_destroy(exec_ctx, conn->client_endpoint); grpc_endpoint_destroy(exec_ctx, conn->client_endpoint);
if (conn->server_endpoint != NULL) if (conn->server_endpoint != NULL) {
grpc_endpoint_destroy(exec_ctx, conn->server_endpoint); grpc_endpoint_destroy(exec_ctx, conn->server_endpoint);
}
grpc_pollset_set_destroy(exec_ctx, conn->pollset_set); grpc_pollset_set_destroy(exec_ctx, conn->pollset_set);
grpc_slice_buffer_destroy_internal(exec_ctx, &conn->client_read_buffer); grpc_slice_buffer_destroy_internal(exec_ctx, &conn->client_read_buffer);
grpc_slice_buffer_destroy_internal(exec_ctx, grpc_slice_buffer_destroy_internal(exec_ctx,
@ -121,6 +131,7 @@ static void proxy_connection_unref(grpc_exec_ctx* exec_ctx,
grpc_slice_buffer_destroy_internal(exec_ctx, &conn->server_write_buffer); grpc_slice_buffer_destroy_internal(exec_ctx, &conn->server_write_buffer);
grpc_http_parser_destroy(&conn->http_parser); grpc_http_parser_destroy(&conn->http_parser);
grpc_http_request_destroy(&conn->http_request); grpc_http_request_destroy(&conn->http_request);
gpr_unref(&conn->proxy->users);
gpr_free(conn); gpr_free(conn);
} }
} }
@ -139,7 +150,7 @@ static void proxy_connection_failed(grpc_exec_ctx* exec_ctx,
grpc_endpoint_shutdown(exec_ctx, conn->server_endpoint, grpc_endpoint_shutdown(exec_ctx, conn->server_endpoint,
GRPC_ERROR_REF(error)); GRPC_ERROR_REF(error));
} }
proxy_connection_unref(exec_ctx, conn); proxy_connection_unref(exec_ctx, conn, "conn_failed");
} }
// Callback for writing proxy data to the client. // Callback for writing proxy data to the client.
@ -163,7 +174,7 @@ static void on_client_write_done(grpc_exec_ctx* exec_ctx, void* arg,
&conn->on_client_write_done); &conn->on_client_write_done);
} else { } else {
// No more writes. Unref the connection. // No more writes. Unref the connection.
proxy_connection_unref(exec_ctx, conn); proxy_connection_unref(exec_ctx, conn, "write_done");
} }
} }
@ -188,7 +199,7 @@ static void on_server_write_done(grpc_exec_ctx* exec_ctx, void* arg,
&conn->on_server_write_done); &conn->on_server_write_done);
} else { } else {
// No more writes. Unref the connection. // No more writes. Unref the connection.
proxy_connection_unref(exec_ctx, conn); proxy_connection_unref(exec_ctx, conn, "server_write");
} }
} }
@ -214,7 +225,7 @@ static void on_client_read_done(grpc_exec_ctx* exec_ctx, void* arg,
} else { } else {
grpc_slice_buffer_move_into(&conn->client_read_buffer, grpc_slice_buffer_move_into(&conn->client_read_buffer,
&conn->server_write_buffer); &conn->server_write_buffer);
gpr_ref(&conn->refcount); proxy_connection_ref(conn, "client_read");
grpc_endpoint_write(exec_ctx, conn->server_endpoint, grpc_endpoint_write(exec_ctx, conn->server_endpoint,
&conn->server_write_buffer, &conn->server_write_buffer,
&conn->on_server_write_done); &conn->on_server_write_done);
@ -246,7 +257,7 @@ static void on_server_read_done(grpc_exec_ctx* exec_ctx, void* arg,
} else { } else {
grpc_slice_buffer_move_into(&conn->server_read_buffer, grpc_slice_buffer_move_into(&conn->server_read_buffer,
&conn->client_write_buffer); &conn->client_write_buffer);
gpr_ref(&conn->refcount); proxy_connection_ref(conn, "server_read");
grpc_endpoint_write(exec_ctx, conn->client_endpoint, grpc_endpoint_write(exec_ctx, conn->client_endpoint,
&conn->client_write_buffer, &conn->client_write_buffer,
&conn->on_client_write_done); &conn->on_client_write_done);
@ -270,7 +281,9 @@ static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg,
// Start reading from both client and server. One of the read // Start reading from both client and server. One of the read
// requests inherits our ref to conn, but we need to take a new ref // requests inherits our ref to conn, but we need to take a new ref
// for the other one. // for the other one.
gpr_ref(&conn->refcount); proxy_connection_ref(conn, "client_read");
proxy_connection_ref(conn, "server_read");
proxy_connection_unref(exec_ctx, conn, "write_response");
grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer, grpc_endpoint_read(exec_ctx, conn->client_endpoint, &conn->client_read_buffer,
&conn->on_client_read_done); &conn->on_client_read_done);
grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer, grpc_endpoint_read(exec_ctx, conn->server_endpoint, &conn->server_read_buffer,
@ -312,6 +325,8 @@ static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg,
static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg, static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) { grpc_error* error) {
proxy_connection* conn = arg; proxy_connection* conn = arg;
gpr_log(GPR_DEBUG, "on_read_request_done: %p %s", conn,
grpc_error_string(error));
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
proxy_connection_failed(exec_ctx, conn, true /* is_client */, proxy_connection_failed(exec_ctx, conn, true /* is_client */,
"HTTP proxy read request", error); "HTTP proxy read request", error);
@ -376,12 +391,14 @@ static void on_accept(grpc_exec_ctx* exec_ctx, void* arg,
gpr_free(acceptor); gpr_free(acceptor);
grpc_end2end_http_proxy* proxy = arg; grpc_end2end_http_proxy* proxy = arg;
// Instantiate proxy_connection. // Instantiate proxy_connection.
proxy_connection* conn = gpr_malloc(sizeof(*conn)); proxy_connection* conn = gpr_zalloc(sizeof(*conn));
memset(conn, 0, sizeof(*conn)); gpr_ref(&proxy->users);
conn->client_endpoint = endpoint; conn->client_endpoint = endpoint;
conn->proxy = proxy;
gpr_ref_init(&conn->refcount, 1); gpr_ref_init(&conn->refcount, 1);
conn->pollset_set = grpc_pollset_set_create(); conn->pollset_set = grpc_pollset_set_create();
grpc_pollset_set_add_pollset(exec_ctx, conn->pollset_set, proxy->pollset); grpc_pollset_set_add_pollset(exec_ctx, conn->pollset_set, proxy->pollset);
grpc_endpoint_add_to_pollset_set(exec_ctx, endpoint, conn->pollset_set);
grpc_closure_init(&conn->on_read_request_done, on_read_request_done, conn, grpc_closure_init(&conn->on_read_request_done, on_read_request_done, conn,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
grpc_closure_init(&conn->on_server_connect_done, on_server_connect_done, conn, grpc_closure_init(&conn->on_server_connect_done, on_server_connect_done, conn,
@ -416,6 +433,7 @@ static void thread_main(void* arg) {
grpc_end2end_http_proxy* proxy = arg; grpc_end2end_http_proxy* proxy = arg;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
do { do {
gpr_ref(&proxy->users);
const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
const gpr_timespec deadline = const gpr_timespec deadline =
gpr_time_add(now, gpr_time_from_seconds(1, GPR_TIMESPAN)); gpr_time_add(now, gpr_time_from_seconds(1, GPR_TIMESPAN));
@ -426,7 +444,7 @@ static void thread_main(void* arg) {
grpc_pollset_work(&exec_ctx, proxy->pollset, &worker, now, deadline)); grpc_pollset_work(&exec_ctx, proxy->pollset, &worker, now, deadline));
gpr_mu_unlock(proxy->mu); gpr_mu_unlock(proxy->mu);
grpc_exec_ctx_flush(&exec_ctx); grpc_exec_ctx_flush(&exec_ctx);
} while (!gpr_atm_acq_load(&proxy->shutdown)); } while (!gpr_unref(&proxy->users));
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
} }
@ -434,6 +452,7 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create(void) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_end2end_http_proxy* proxy = gpr_malloc(sizeof(*proxy)); grpc_end2end_http_proxy* proxy = gpr_malloc(sizeof(*proxy));
memset(proxy, 0, sizeof(*proxy)); memset(proxy, 0, sizeof(*proxy));
gpr_ref_init(&proxy->users, 1);
// Construct proxy address. // Construct proxy address.
const int proxy_port = grpc_pick_unused_port_or_die(); const int proxy_port = grpc_pick_unused_port_or_die();
gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port); gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port);
@ -474,17 +493,16 @@ static void destroy_pollset(grpc_exec_ctx* exec_ctx, void* arg,
} }
void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) { void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) {
gpr_atm_rel_store(&proxy->shutdown, 1); // Signal proxy thread to shutdown. gpr_unref(&proxy->users); // Signal proxy thread to shutdown.
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
gpr_thd_join(proxy->thd); gpr_thd_join(proxy->thd);
grpc_tcp_server_shutdown_listeners(&exec_ctx, proxy->server); grpc_tcp_server_shutdown_listeners(&exec_ctx, proxy->server);
grpc_tcp_server_unref(&exec_ctx, proxy->server); grpc_tcp_server_unref(&exec_ctx, proxy->server);
gpr_free(proxy->proxy_name); gpr_free(proxy->proxy_name);
grpc_channel_args_destroy(&exec_ctx, proxy->channel_args); grpc_channel_args_destroy(&exec_ctx, proxy->channel_args);
grpc_closure destroyed; grpc_pollset_shutdown(&exec_ctx, proxy->pollset,
grpc_closure_init(&destroyed, destroy_pollset, proxy->pollset, grpc_closure_create(destroy_pollset, proxy->pollset,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx));
grpc_pollset_shutdown(&exec_ctx, proxy->pollset, &destroyed);
gpr_free(proxy); gpr_free(proxy);
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
} }

@ -49,11 +49,12 @@ static void *tag(intptr_t t) { return (void *)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char *test_name, const char *test_name,
cancellation_mode mode, cancellation_mode mode,
size_t test_ops,
grpc_channel_args *client_args, grpc_channel_args *client_args,
grpc_channel_args *server_args) { grpc_channel_args *server_args) {
grpc_end2end_test_fixture f; grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s/%s", test_name, config.name, gpr_log(GPR_INFO, "Running test: %s/%s/%s [%" PRIdPTR " ops]", test_name,
mode.name); config.name, mode.name, test_ops);
f = config.create_fixture(client_args, server_args); f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args); config.init_server(&f, server_args);
config.init_client(&f, client_args); config.init_client(&f, client_args);
@ -108,8 +109,8 @@ static void test_cancel_after_invoke(grpc_end2end_test_config config,
grpc_op ops[6]; grpc_op ops[6];
grpc_op *op; grpc_op *op;
grpc_call *c; grpc_call *c;
grpc_end2end_test_fixture f = grpc_end2end_test_fixture f = begin_test(config, "test_cancel_after_invoke",
begin_test(config, "test_cancel_after_invoke", mode, NULL, NULL); mode, test_ops, NULL, NULL);
cq_verifier *cqv = cq_verifier_create(f.cq); cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_metadata_array initial_metadata_recv; grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv; grpc_metadata_array trailing_metadata_recv;

@ -103,7 +103,7 @@ void grpc_free_port_using_server(int port) {
grpc_resource_quota *resource_quota = grpc_resource_quota *resource_quota =
grpc_resource_quota_create("port_server_client/free"); grpc_resource_quota_create("port_server_client/free");
grpc_httpcli_get(&exec_ctx, &context, &pr.pops, resource_quota, &req, grpc_httpcli_get(&exec_ctx, &context, &pr.pops, resource_quota, &req,
grpc_timeout_seconds_to_deadline(10), grpc_timeout_seconds_to_deadline(30),
grpc_closure_create(freed_port_from_server, &pr, grpc_closure_create(freed_port_from_server, &pr,
grpc_schedule_on_exec_ctx), grpc_schedule_on_exec_ctx),
&rsp); &rsp);
@ -235,7 +235,7 @@ int grpc_pick_port_using_server(void) {
grpc_resource_quota_create("port_server_client/pick"); grpc_resource_quota_create("port_server_client/pick");
grpc_httpcli_get( grpc_httpcli_get(
&exec_ctx, &context, &pr.pops, resource_quota, &req, &exec_ctx, &context, &pr.pops, resource_quota, &req,
grpc_timeout_seconds_to_deadline(10), grpc_timeout_seconds_to_deadline(30),
grpc_closure_create(got_port_from_server, &pr, grpc_schedule_on_exec_ctx), grpc_closure_create(got_port_from_server, &pr, grpc_schedule_on_exec_ctx),
&pr.response); &pr.response);
grpc_resource_quota_unref_internal(&exec_ctx, resource_quota); grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);

@ -348,6 +348,14 @@ bool BuiltUnderMsan() {
#endif #endif
} }
bool BuiltUnderUbsan() {
#ifdef GRPC_UBSAN
return true;
#else
return false;
#endif
}
int64_t grpc_test_sanitizer_slowdown_factor() { int64_t grpc_test_sanitizer_slowdown_factor() {
int64_t sanitizer_multiplier = 1; int64_t sanitizer_multiplier = 1;
if (BuiltUnderValgrind()) { if (BuiltUnderValgrind()) {
@ -358,6 +366,8 @@ int64_t grpc_test_sanitizer_slowdown_factor() {
sanitizer_multiplier = 3; sanitizer_multiplier = 3;
} else if (BuiltUnderMsan()) { } else if (BuiltUnderMsan()) {
sanitizer_multiplier = 4; sanitizer_multiplier = 4;
} else if (BuiltUnderUbsan()) {
sanitizer_multiplier = 5;
} }
return sanitizer_multiplier; return sanitizer_multiplier;
} }

@ -62,7 +62,7 @@ cc_test(
cc_test( cc_test(
name = "golden_file_test", name = "golden_file_test",
srcs = ["golden_file_test.cc"], srcs = ["golden_file_test.cc"],
args = ["--generated_file_path=$(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.h"], args = ["--generated_file_path=$(GENDIR)/src/proto/grpc/testing/"],
data = [ data = [
":compiler_test_golden", ":compiler_test_golden",
"//src/proto/grpc/testing:_compiler_test_proto_grpc_codegen", "//src/proto/grpc/testing:_compiler_test_proto_grpc_codegen",

@ -89,10 +89,30 @@ class ServiceA final {
return std::unique_ptr< ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>>(AsyncMethodA2Raw(context, response, cq, tag)); return std::unique_ptr< ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>>(AsyncMethodA2Raw(context, response, cq, tag));
} }
// MethodA2 trailing comment 1 // MethodA2 trailing comment 1
// Method A3 leading comment 1
std::unique_ptr< ::grpc::ClientReaderInterface< ::grpc::testing::Response>> MethodA3(::grpc::ClientContext* context, const ::grpc::testing::Request& request) {
return std::unique_ptr< ::grpc::ClientReaderInterface< ::grpc::testing::Response>>(MethodA3Raw(context, request));
}
std::unique_ptr< ::grpc::ClientAsyncReaderInterface< ::grpc::testing::Response>> AsyncMethodA3(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< ::grpc::testing::Response>>(AsyncMethodA3Raw(context, request, cq, tag));
}
// Method A3 trailing comment 1
// Method A4 leading comment 1
std::unique_ptr< ::grpc::ClientReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>> MethodA4(::grpc::ClientContext* context) {
return std::unique_ptr< ::grpc::ClientReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>>(MethodA4Raw(context));
}
std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>> AsyncMethodA4(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>>(AsyncMethodA4Raw(context, cq, tag));
}
// Method A4 trailing comment 1
private: private:
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0; virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientWriterInterface< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) = 0; virtual ::grpc::ClientWriterInterface< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) = 0;
virtual ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>* AsyncMethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) = 0; virtual ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>* AsyncMethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) = 0;
virtual ::grpc::ClientReaderInterface< ::grpc::testing::Response>* MethodA3Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request) = 0;
virtual ::grpc::ClientAsyncReaderInterface< ::grpc::testing::Response>* AsyncMethodA3Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag) = 0;
virtual ::grpc::ClientReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4Raw(::grpc::ClientContext* context) = 0;
virtual ::grpc::ClientAsyncReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>* AsyncMethodA4Raw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) = 0;
}; };
class Stub final : public StubInterface { class Stub final : public StubInterface {
public: public:
@ -107,14 +127,32 @@ class ServiceA final {
std::unique_ptr< ::grpc::ClientAsyncWriter< ::grpc::testing::Request>> AsyncMethodA2(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) { std::unique_ptr< ::grpc::ClientAsyncWriter< ::grpc::testing::Request>> AsyncMethodA2(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncWriter< ::grpc::testing::Request>>(AsyncMethodA2Raw(context, response, cq, tag)); return std::unique_ptr< ::grpc::ClientAsyncWriter< ::grpc::testing::Request>>(AsyncMethodA2Raw(context, response, cq, tag));
} }
std::unique_ptr< ::grpc::ClientReader< ::grpc::testing::Response>> MethodA3(::grpc::ClientContext* context, const ::grpc::testing::Request& request) {
return std::unique_ptr< ::grpc::ClientReader< ::grpc::testing::Response>>(MethodA3Raw(context, request));
}
std::unique_ptr< ::grpc::ClientAsyncReader< ::grpc::testing::Response>> AsyncMethodA3(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReader< ::grpc::testing::Response>>(AsyncMethodA3Raw(context, request, cq, tag));
}
std::unique_ptr< ::grpc::ClientReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>> MethodA4(::grpc::ClientContext* context) {
return std::unique_ptr< ::grpc::ClientReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>>(MethodA4Raw(context));
}
std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>> AsyncMethodA4(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>>(AsyncMethodA4Raw(context, cq, tag));
}
private: private:
std::shared_ptr< ::grpc::ChannelInterface> channel_; std::shared_ptr< ::grpc::ChannelInterface> channel_;
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override; ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientWriter< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) override; ::grpc::ClientWriter< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) override;
::grpc::ClientAsyncWriter< ::grpc::testing::Request>* AsyncMethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) override; ::grpc::ClientAsyncWriter< ::grpc::testing::Request>* AsyncMethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag) override;
::grpc::ClientReader< ::grpc::testing::Response>* MethodA3Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request) override;
::grpc::ClientAsyncReader< ::grpc::testing::Response>* AsyncMethodA3Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag) override;
::grpc::ClientReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4Raw(::grpc::ClientContext* context) override;
::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>* AsyncMethodA4Raw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) override;
const ::grpc::RpcMethod rpcmethod_MethodA1_; const ::grpc::RpcMethod rpcmethod_MethodA1_;
const ::grpc::RpcMethod rpcmethod_MethodA2_; const ::grpc::RpcMethod rpcmethod_MethodA2_;
const ::grpc::RpcMethod rpcmethod_MethodA3_;
const ::grpc::RpcMethod rpcmethod_MethodA4_;
}; };
static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
@ -131,6 +169,12 @@ class ServiceA final {
// Method A2 leading comment 2 // Method A2 leading comment 2
virtual ::grpc::Status MethodA2(::grpc::ServerContext* context, ::grpc::ServerReader< ::grpc::testing::Request>* reader, ::grpc::testing::Response* response); virtual ::grpc::Status MethodA2(::grpc::ServerContext* context, ::grpc::ServerReader< ::grpc::testing::Request>* reader, ::grpc::testing::Response* response);
// MethodA2 trailing comment 1 // MethodA2 trailing comment 1
// Method A3 leading comment 1
virtual ::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer);
// Method A3 trailing comment 1
// Method A4 leading comment 1
virtual ::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream);
// Method A4 trailing comment 1
}; };
template <class BaseClass> template <class BaseClass>
class WithAsyncMethod_MethodA1 : public BaseClass { class WithAsyncMethod_MethodA1 : public BaseClass {
@ -172,7 +216,47 @@ class ServiceA final {
::grpc::Service::RequestAsyncClientStreaming(1, context, reader, new_call_cq, notification_cq, tag); ::grpc::Service::RequestAsyncClientStreaming(1, context, reader, new_call_cq, notification_cq, tag);
} }
}; };
typedef WithAsyncMethod_MethodA1<WithAsyncMethod_MethodA2<Service > > AsyncService; template <class BaseClass>
class WithAsyncMethod_MethodA3 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithAsyncMethod_MethodA3() {
::grpc::Service::MarkMethodAsync(2);
}
~WithAsyncMethod_MethodA3() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestMethodA3(::grpc::ServerContext* context, ::grpc::testing::Request* request, ::grpc::ServerAsyncWriter< ::grpc::testing::Response>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncServerStreaming(2, context, request, writer, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithAsyncMethod_MethodA4 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithAsyncMethod_MethodA4() {
::grpc::Service::MarkMethodAsync(3);
}
~WithAsyncMethod_MethodA4() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestMethodA4(::grpc::ServerContext* context, ::grpc::ServerAsyncReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncBidiStreaming(3, context, stream, new_call_cq, notification_cq, tag);
}
};
typedef WithAsyncMethod_MethodA1<WithAsyncMethod_MethodA2<WithAsyncMethod_MethodA3<WithAsyncMethod_MethodA4<Service > > > > AsyncService;
template <class BaseClass> template <class BaseClass>
class WithGenericMethod_MethodA1 : public BaseClass { class WithGenericMethod_MethodA1 : public BaseClass {
private: private:
@ -208,6 +292,40 @@ class ServiceA final {
} }
}; };
template <class BaseClass> template <class BaseClass>
class WithGenericMethod_MethodA3 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithGenericMethod_MethodA3() {
::grpc::Service::MarkMethodGeneric(2);
}
~WithGenericMethod_MethodA3() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithGenericMethod_MethodA4 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithGenericMethod_MethodA4() {
::grpc::Service::MarkMethodGeneric(3);
}
~WithGenericMethod_MethodA4() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status MethodA4(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::testing::Response, ::grpc::testing::Request>* stream) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithStreamedUnaryMethod_MethodA1 : public BaseClass { class WithStreamedUnaryMethod_MethodA1 : public BaseClass {
private: private:
void BaseClassMustBeDerivedFromService(const Service *service) {} void BaseClassMustBeDerivedFromService(const Service *service) {}
@ -228,8 +346,28 @@ class ServiceA final {
virtual ::grpc::Status StreamedMethodA1(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::grpc::testing::Request,::grpc::testing::Response>* server_unary_streamer) = 0; virtual ::grpc::Status StreamedMethodA1(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::grpc::testing::Request,::grpc::testing::Response>* server_unary_streamer) = 0;
}; };
typedef WithStreamedUnaryMethod_MethodA1<Service > StreamedUnaryService; typedef WithStreamedUnaryMethod_MethodA1<Service > StreamedUnaryService;
typedef Service SplitStreamedService; template <class BaseClass>
typedef WithStreamedUnaryMethod_MethodA1<Service > StreamedService; class WithSplitStreamingMethod_MethodA3 : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithSplitStreamingMethod_MethodA3() {
::grpc::Service::MarkMethodStreamed(2,
new ::grpc::SplitServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithSplitStreamingMethod_MethodA3<BaseClass>::StreamedMethodA3, this, std::placeholders::_1, std::placeholders::_2)));
}
~WithSplitStreamingMethod_MethodA3() override {
BaseClassMustBeDerivedFromService(this);
}
// disable regular version of this method
::grpc::Status MethodA3(::grpc::ServerContext* context, const ::grpc::testing::Request* request, ::grpc::ServerWriter< ::grpc::testing::Response>* writer) final override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
// replace default version of method with split streamed
virtual ::grpc::Status StreamedMethodA3(::grpc::ServerContext* context, ::grpc::ServerSplitStreamer< ::grpc::testing::Request,::grpc::testing::Response>* server_split_streamer) = 0;
};
typedef WithSplitStreamingMethod_MethodA3<Service > SplitStreamedService;
typedef WithStreamedUnaryMethod_MethodA1<WithSplitStreamingMethod_MethodA3<Service > > StreamedService;
}; };
// ServiceB leading comment 1 // ServiceB leading comment 1

@ -0,0 +1,34 @@
// Generated by the gRPC C++ plugin.
// If you make any local change, they will be lost.
// source: src/proto/grpc/testing/compiler_test.proto
#include "src/proto/grpc/testing/compiler_test.pb.h"
#include "src/proto/grpc/testing/compiler_test.grpc.pb.h"
#include <grpc++/impl/codegen/async_stream.h>
#include <grpc++/impl/codegen/sync_stream.h>
#include <gmock/gmock.h>
namespace grpc {
namespace testing {
class MockServiceAStub : public ServiceA::StubInterface {
public:
MOCK_METHOD3(MethodA1, ::grpc::Status(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::testing::Response* response));
MOCK_METHOD3(AsyncMethodA1Raw, ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>*(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq));
MOCK_METHOD2(MethodA2Raw, ::grpc::ClientWriterInterface< ::grpc::testing::Request>*(::grpc::ClientContext* context, ::grpc::testing::Response* response));
MOCK_METHOD4(AsyncMethodA2Raw, ::grpc::ClientAsyncWriterInterface< ::grpc::testing::Request>*(::grpc::ClientContext* context, ::grpc::testing::Response* response, ::grpc::CompletionQueue* cq, void* tag));
MOCK_METHOD2(MethodA3Raw, ::grpc::ClientReaderInterface< ::grpc::testing::Response>*(::grpc::ClientContext* context, const ::grpc::testing::Request& request));
MOCK_METHOD4(AsyncMethodA3Raw, ::grpc::ClientAsyncReaderInterface< ::grpc::testing::Response>*(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq, void* tag));
MOCK_METHOD1(MethodA4Raw, ::grpc::ClientReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>*(::grpc::ClientContext* context));
MOCK_METHOD3(AsyncMethodA4Raw, ::grpc::ClientAsyncReaderWriterInterface<::grpc::testing::Request, ::grpc::testing::Response>*(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag));
};
class MockServiceBStub : public ServiceB::StubInterface {
public:
MOCK_METHOD3(MethodB1, ::grpc::Status(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::testing::Response* response));
MOCK_METHOD3(AsyncMethodB1Raw, ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>*(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq));
};
} // namespace grpc
} // namespace testing

@ -37,16 +37,18 @@
#include <gflags/gflags.h> #include <gflags/gflags.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
DEFINE_string(generated_file_path, "", DEFINE_string(
"path to the generated compiler_test.grpc.pb.h file"); generated_file_path, "",
"path to the directory containing generated files compiler_test.grpc.pb.h"
"and compiler_test_mock.grpc.pb.h");
const char kGoldenFilePath[] = "test/cpp/codegen/compiler_test_golden"; const char kGoldenFilePath[] = "test/cpp/codegen/compiler_test_golden";
const char kMockGoldenFilePath[] = "test/cpp/codegen/compiler_test_mock_golden";
TEST(GoldenFileTest, TestGeneratedFile) { void run_test(std::basic_string<char> generated_file,
ASSERT_FALSE(FLAGS_generated_file_path.empty()); std::basic_string<char> golden_file) {
std::ifstream generated(generated_file);
std::ifstream generated(FLAGS_generated_file_path); std::ifstream golden(golden_file);
std::ifstream golden(kGoldenFilePath);
ASSERT_TRUE(generated.good()); ASSERT_TRUE(generated.good());
ASSERT_TRUE(golden.good()); ASSERT_TRUE(golden.good());
@ -61,8 +63,23 @@ TEST(GoldenFileTest, TestGeneratedFile) {
golden.close(); golden.close();
} }
TEST(GoldenFileTest, TestGeneratedFile) {
run_test(FLAGS_generated_file_path + "compiler_test.grpc.pb.h",
kGoldenFilePath);
}
TEST(GoldenMockFileTest, TestGeneratedMockFile) {
run_test(FLAGS_generated_file_path + "compiler_test_mock.grpc.pb.h",
kMockGoldenFilePath);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
::google::ParseCommandLineFlags(&argc, &argv, true); ::google::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_generated_file_path.empty()) {
FLAGS_generated_file_path = "gens/src/proto/grpc/testing/";
}
if (FLAGS_generated_file_path.back() != '/')
FLAGS_generated_file_path.append("/");
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }

@ -51,6 +51,7 @@ cc_test(
"//src/proto/grpc/testing:echo_messages_proto", "//src/proto/grpc/testing:echo_messages_proto",
"//src/proto/grpc/testing:echo_proto", "//src/proto/grpc/testing:echo_proto",
"//src/proto/grpc/testing/duplicate:echo_duplicate_proto", "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
"//src/proto/grpc/health/v1:health_proto",
"//test/core/util:gpr_test_util", "//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util", "//test/core/util:grpc_test_util",
"//test/cpp/util:test_util", "//test/cpp/util:test_util",

@ -38,6 +38,7 @@
#include <grpc++/channel.h> #include <grpc++/channel.h>
#include <grpc++/client_context.h> #include <grpc++/client_context.h>
#include <grpc++/create_channel.h> #include <grpc++/create_channel.h>
#include <grpc++/ext/health_check_service_server_builder_option.h>
#include <grpc++/server.h> #include <grpc++/server.h>
#include <grpc++/server_builder.h> #include <grpc++/server_builder.h>
#include <grpc++/server_context.h> #include <grpc++/server_context.h>
@ -49,6 +50,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "src/core/lib/iomgr/port.h" #include "src/core/lib/iomgr/port.h"
#include "src/proto/grpc/health/v1/health.grpc.pb.h"
#include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h" #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h" #include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h" #include "test/core/util/port.h"
@ -224,13 +226,15 @@ class ServerBuilderSyncPluginDisabler : public ::grpc::ServerBuilderOption {
class TestScenario { class TestScenario {
public: public:
TestScenario(bool non_block, const grpc::string& creds_type, TestScenario(bool non_block, const grpc::string& creds_type, bool hcs,
const grpc::string& content) const grpc::string& content)
: disable_blocking(non_block), : disable_blocking(non_block),
health_check_service(hcs),
credentials_type(creds_type), credentials_type(creds_type),
message_content(content) {} message_content(content) {}
void Log() const; void Log() const;
bool disable_blocking; bool disable_blocking;
bool health_check_service;
// Although the below grpc::string's are logically const, we can't declare // Although the below grpc::string's are logically const, we can't declare
// them const because of a limitation in the way old compilers (e.g., gcc-4.4) // them const because of a limitation in the way old compilers (e.g., gcc-4.4)
// manage vector insertion using a copy constructor // manage vector insertion using a copy constructor
@ -243,6 +247,8 @@ static std::ostream& operator<<(std::ostream& out,
return out << "TestScenario{disable_blocking=" return out << "TestScenario{disable_blocking="
<< (scenario.disable_blocking ? "true" : "false") << (scenario.disable_blocking ? "true" : "false")
<< ", credentials='" << scenario.credentials_type << ", credentials='" << scenario.credentials_type
<< ", health_check_service="
<< (scenario.health_check_service ? "true" : "false")
<< "', message_size=" << scenario.message_content.size() << "}"; << "', message_size=" << scenario.message_content.size() << "}";
} }
@ -252,6 +258,8 @@ void TestScenario::Log() const {
gpr_log(GPR_DEBUG, "%s", out.str().c_str()); gpr_log(GPR_DEBUG, "%s", out.str().c_str());
} }
class HealthCheck : public health::v1::Health::Service {};
class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> { class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
protected: protected:
AsyncEnd2endTest() { GetParam().Log(); } AsyncEnd2endTest() { GetParam().Log(); }
@ -268,6 +276,9 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
GetParam().credentials_type); GetParam().credentials_type);
builder.AddListeningPort(server_address_.str(), server_creds); builder.AddListeningPort(server_address_.str(), server_creds);
builder.RegisterService(&service_); builder.RegisterService(&service_);
if (GetParam().health_check_service) {
builder.RegisterService(&health_check_);
}
cq_ = builder.AddCompletionQueue(); cq_ = builder.AddCompletionQueue();
// TODO(zyc): make a test option to choose wheather sync plugins should be // TODO(zyc): make a test option to choose wheather sync plugins should be
@ -340,6 +351,7 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<TestScenario> {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
std::unique_ptr<Server> server_; std::unique_ptr<Server> server_;
grpc::testing::EchoTestService::AsyncService service_; grpc::testing::EchoTestService::AsyncService service_;
HealthCheck health_check_;
std::ostringstream server_address_; std::ostringstream server_address_;
int port_; int port_;
@ -1754,12 +1766,14 @@ std::vector<TestScenario> CreateTestScenarios(bool test_disable_blocking,
messages.push_back(big_msg); messages.push_back(big_msg);
} }
for (auto health_check_service : {false, true}) {
for (auto cred = credentials_types.begin(); cred != credentials_types.end(); for (auto cred = credentials_types.begin(); cred != credentials_types.end();
++cred) { ++cred) {
for (auto msg = messages.begin(); msg != messages.end(); msg++) { for (auto msg = messages.begin(); msg != messages.end(); msg++) {
scenarios.emplace_back(false, *cred, *msg); scenarios.emplace_back(false, *cred, health_check_service, *msg);
if (test_disable_blocking) { if (test_disable_blocking) {
scenarios.emplace_back(true, *cred, *msg); scenarios.emplace_back(true, *cred, health_check_service, *msg);
}
} }
} }
} }

@ -34,6 +34,7 @@
#include <climits> #include <climits>
#include <thread> #include <thread>
#include <gmock/gmock.h>
#include <grpc++/channel.h> #include <grpc++/channel.h>
#include <grpc++/client_context.h> #include <grpc++/client_context.h>
#include <grpc++/create_channel.h> #include <grpc++/create_channel.h>
@ -46,120 +47,35 @@
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <grpc++/test/mock_stream.h>
#include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h" #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h" #include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "src/proto/grpc/testing/echo_mock.grpc.pb.h"
#include "test/core/util/port.h" #include "test/core/util/port.h"
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
#include <iostream>
using namespace std;
using grpc::testing::EchoRequest; using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse; using grpc::testing::EchoResponse;
using grpc::testing::EchoTestService; using grpc::testing::EchoTestService;
using grpc::testing::MockClientReaderWriter;
using std::chrono::system_clock; using std::chrono::system_clock;
using ::testing::AtLeast;
using ::testing::SetArgPointee;
using ::testing::SaveArg;
using ::testing::_;
using ::testing::Return;
using ::testing::Invoke;
using ::testing::WithArg;
using ::testing::DoAll;
namespace grpc { namespace grpc {
namespace testing { namespace testing {
namespace { namespace {
template <class W, class R>
class MockClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
public:
void WaitForInitialMetadata() override {}
bool NextMessageSize(uint32_t* sz) override {
*sz = UINT_MAX;
return true;
}
bool Read(R* msg) override { return true; }
bool Write(const W& msg) override { return true; }
bool WritesDone() override { return true; }
Status Finish() override { return Status::OK; }
};
template <>
class MockClientReaderWriter<EchoRequest, EchoResponse> final
: public ClientReaderWriterInterface<EchoRequest, EchoResponse> {
public:
MockClientReaderWriter() : writes_done_(false) {}
void WaitForInitialMetadata() override {}
bool NextMessageSize(uint32_t* sz) override {
*sz = UINT_MAX;
return true;
}
bool Read(EchoResponse* msg) override {
if (writes_done_) return false;
msg->set_message(last_message_);
return true;
}
bool Write(const EchoRequest& msg, WriteOptions options) override {
gpr_log(GPR_INFO, "mock recv msg %s", msg.message().c_str());
last_message_ = msg.message();
return true;
}
bool WritesDone() override {
writes_done_ = true;
return true;
}
Status Finish() override { return Status::OK; }
private:
bool writes_done_;
grpc::string last_message_;
};
// Mocked stub.
class MockStub : public EchoTestService::StubInterface {
public:
MockStub() {}
~MockStub() {}
Status Echo(ClientContext* context, const EchoRequest& request,
EchoResponse* response) override {
response->set_message(request.message());
return Status::OK;
}
Status Unimplemented(ClientContext* context, const EchoRequest& request,
EchoResponse* response) override {
return Status::OK;
}
private:
ClientAsyncResponseReaderInterface<EchoResponse>* AsyncEchoRaw(
ClientContext* context, const EchoRequest& request,
CompletionQueue* cq) override {
return nullptr;
}
ClientWriterInterface<EchoRequest>* RequestStreamRaw(
ClientContext* context, EchoResponse* response) override {
return nullptr;
}
ClientAsyncWriterInterface<EchoRequest>* AsyncRequestStreamRaw(
ClientContext* context, EchoResponse* response, CompletionQueue* cq,
void* tag) override {
return nullptr;
}
ClientReaderInterface<EchoResponse>* ResponseStreamRaw(
ClientContext* context, const EchoRequest& request) override {
return nullptr;
}
ClientAsyncReaderInterface<EchoResponse>* AsyncResponseStreamRaw(
ClientContext* context, const EchoRequest& request, CompletionQueue* cq,
void* tag) override {
return nullptr;
}
ClientReaderWriterInterface<EchoRequest, EchoResponse>* BidiStreamRaw(
ClientContext* context) override {
return new MockClientReaderWriter<EchoRequest, EchoResponse>();
}
ClientAsyncReaderWriterInterface<EchoRequest, EchoResponse>*
AsyncBidiStreamRaw(ClientContext* context, CompletionQueue* cq,
void* tag) override {
return nullptr;
}
ClientAsyncResponseReaderInterface<EchoResponse>* AsyncUnimplementedRaw(
ClientContext* context, const EchoRequest& request,
CompletionQueue* cq) override {
return nullptr;
}
};
class FakeClient { class FakeClient {
public: public:
explicit FakeClient(EchoTestService::StubInterface* stub) : stub_(stub) {} explicit FakeClient(EchoTestService::StubInterface* stub) : stub_(stub) {}
@ -174,6 +90,55 @@ class FakeClient {
EXPECT_TRUE(s.ok()); EXPECT_TRUE(s.ok());
} }
void DoRequestStream() {
EchoRequest request;
EchoResponse response;
ClientContext context;
grpc::string msg("hello");
grpc::string exp(msg);
std::unique_ptr<ClientWriterInterface<EchoRequest>> cstream =
stub_->RequestStream(&context, &response);
request.set_message(msg);
EXPECT_TRUE(cstream->Write(request));
msg = ", world";
request.set_message(msg);
exp.append(msg);
EXPECT_TRUE(cstream->Write(request));
cstream->WritesDone();
Status s = cstream->Finish();
EXPECT_EQ(exp, response.message());
EXPECT_TRUE(s.ok());
}
void DoResponseStream() {
EchoRequest request;
EchoResponse response;
request.set_message("hello world");
ClientContext context;
std::unique_ptr<ClientReaderInterface<EchoResponse>> cstream =
stub_->ResponseStream(&context, request);
grpc::string exp = "";
EXPECT_TRUE(cstream->Read(&response));
exp.append(response.message() + " ");
EXPECT_TRUE(cstream->Read(&response));
exp.append(response.message());
EXPECT_FALSE(cstream->Read(&response));
EXPECT_EQ(request.message(), exp);
Status s = cstream->Finish();
EXPECT_TRUE(s.ok());
}
void DoBidiStream() { void DoBidiStream() {
EchoRequest request; EchoRequest request;
EchoResponse response; EchoResponse response;
@ -219,6 +184,30 @@ class TestServiceImpl : public EchoTestService::Service {
return Status::OK; return Status::OK;
} }
Status RequestStream(ServerContext* context,
ServerReader<EchoRequest>* reader,
EchoResponse* response) override {
EchoRequest request;
grpc::string resp("");
while (reader->Read(&request)) {
gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
resp.append(request.message());
}
response->set_message(resp);
return Status::OK;
}
Status ResponseStream(ServerContext* context, const EchoRequest* request,
ServerWriter<EchoResponse>* writer) override {
EchoResponse response;
vector<grpc::string> tokens = split(request->message());
for (grpc::string token : tokens) {
response.set_message(token);
writer->Write(response);
}
return Status::OK;
}
Status BidiStream( Status BidiStream(
ServerContext* context, ServerContext* context,
ServerReaderWriter<EchoResponse, EchoRequest>* stream) override { ServerReaderWriter<EchoResponse, EchoRequest>* stream) override {
@ -231,6 +220,25 @@ class TestServiceImpl : public EchoTestService::Service {
} }
return Status::OK; return Status::OK;
} }
private:
const vector<grpc::string> split(const grpc::string& input) {
grpc::string buff("");
vector<grpc::string> result;
for (auto n : input) {
if (n != ' ') {
buff += n;
continue;
}
if (buff == "") continue;
result.push_back(buff);
buff = "";
}
if (buff != "") result.push_back(buff);
return result;
}
}; };
class MockTest : public ::testing::Test { class MockTest : public ::testing::Test {
@ -267,16 +275,82 @@ TEST_F(MockTest, SimpleRpc) {
ResetStub(); ResetStub();
FakeClient client(stub_.get()); FakeClient client(stub_.get());
client.DoEcho(); client.DoEcho();
MockStub stub; MockEchoTestServiceStub stub;
EchoResponse resp;
resp.set_message("hello world");
EXPECT_CALL(stub, Echo(_, _, _))
.Times(AtLeast(1))
.WillOnce(DoAll(SetArgPointee<2>(resp), Return(Status::OK)));
client.ResetStub(&stub); client.ResetStub(&stub);
client.DoEcho(); client.DoEcho();
} }
TEST_F(MockTest, ClientStream) {
ResetStub();
FakeClient client(stub_.get());
client.DoRequestStream();
MockEchoTestServiceStub stub;
auto w = new MockClientWriter<EchoRequest>();
EchoResponse resp;
resp.set_message("hello, world");
EXPECT_CALL(*w, Write(_, _)).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(*w, WritesDone());
EXPECT_CALL(*w, Finish()).WillOnce(Return(Status::OK));
EXPECT_CALL(stub, RequestStreamRaw(_, _))
.WillOnce(DoAll(SetArgPointee<1>(resp), Return(w)));
client.ResetStub(&stub);
client.DoRequestStream();
}
TEST_F(MockTest, ServerStream) {
ResetStub();
FakeClient client(stub_.get());
client.DoResponseStream();
MockEchoTestServiceStub stub;
auto r = new MockClientReader<EchoResponse>();
EchoResponse resp1;
resp1.set_message("hello");
EchoResponse resp2;
resp2.set_message("world");
EXPECT_CALL(*r, Read(_))
.WillOnce(DoAll(SetArgPointee<0>(resp1), Return(true)))
.WillOnce(DoAll(SetArgPointee<0>(resp2), Return(true)))
.WillOnce(Return(false));
EXPECT_CALL(*r, Finish()).WillOnce(Return(Status::OK));
EXPECT_CALL(stub, ResponseStreamRaw(_, _)).WillOnce(Return(r));
client.ResetStub(&stub);
client.DoResponseStream();
}
ACTION_P(copy, msg) { arg0->set_message(msg->message()); }
TEST_F(MockTest, BidiStream) { TEST_F(MockTest, BidiStream) {
ResetStub(); ResetStub();
FakeClient client(stub_.get()); FakeClient client(stub_.get());
client.DoBidiStream(); client.DoBidiStream();
MockStub stub; MockEchoTestServiceStub stub;
auto rw = new MockClientReaderWriter<EchoRequest, EchoResponse>();
EchoRequest msg;
EXPECT_CALL(*rw, Write(_, _))
.Times(3)
.WillRepeatedly(DoAll(SaveArg<0>(&msg), Return(true)));
EXPECT_CALL(*rw, Read(_))
.WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true)))
.WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true)))
.WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true)))
.WillOnce(Return(false));
EXPECT_CALL(*rw, WritesDone());
EXPECT_CALL(*rw, Finish()).WillOnce(Return(Status::OK));
EXPECT_CALL(stub, BidiStreamRaw(_)).WillOnce(Return(rw));
client.ResetStub(&stub); client.ResetStub(&stub);
client.DoBidiStream(); client.DoBidiStream();
} }

@ -68,10 +68,12 @@ auto &force_library_initialization = Library::get();
void BM_Zalloc(benchmark::State &state) { void BM_Zalloc(benchmark::State &state) {
// speed of light for call creation is zalloc, so benchmark a few interesting // speed of light for call creation is zalloc, so benchmark a few interesting
// sizes // sizes
TrackCounters track_counters;
size_t sz = state.range(0); size_t sz = state.range(0);
while (state.KeepRunning()) { while (state.KeepRunning()) {
gpr_free(gpr_zalloc(sz)); gpr_free(gpr_zalloc(sz));
} }
track_counters.Finish(state);
} }
BENCHMARK(BM_Zalloc) BENCHMARK(BM_Zalloc)
->Arg(64) ->Arg(64)

@ -113,13 +113,17 @@ class TCP : public FullstackFixture {
public: public:
TCP(Service* service, const FixtureConfiguration& fixture_configuration = TCP(Service* service, const FixtureConfiguration& fixture_configuration =
FixtureConfiguration()) FixtureConfiguration())
: FullstackFixture(service, fixture_configuration, MakeAddress()) {} : FullstackFixture(service, fixture_configuration, MakeAddress(&port_)) {}
~TCP() { grpc_recycle_unused_port(port_); }
private: private:
static grpc::string MakeAddress() { int port_;
int port = grpc_pick_unused_port_or_die();
static grpc::string MakeAddress(int* port) {
*port = grpc_pick_unused_port_or_die();
std::stringstream addr; std::stringstream addr;
addr << "localhost:" << port; addr << "localhost:" << *port;
return addr.str(); return addr.str();
} }
}; };
@ -128,14 +132,18 @@ class UDS : public FullstackFixture {
public: public:
UDS(Service* service, const FixtureConfiguration& fixture_configuration = UDS(Service* service, const FixtureConfiguration& fixture_configuration =
FixtureConfiguration()) FixtureConfiguration())
: FullstackFixture(service, fixture_configuration, MakeAddress()) {} : FullstackFixture(service, fixture_configuration, MakeAddress(&port_)) {}
~UDS() { grpc_recycle_unused_port(port_); }
private: private:
static grpc::string MakeAddress() { int port_;
int port = grpc_pick_unused_port_or_die(); // just for a unique id - not a
static grpc::string MakeAddress(int* port) {
*port = grpc_pick_unused_port_or_die(); // just for a unique id - not a
// real port // real port
std::stringstream addr; std::stringstream addr;
addr << "unix:/tmp/bm_fullstack." << port; addr << "unix:/tmp/bm_fullstack." << *port;
return addr.str(); return addr.str();
} }
}; };

@ -57,6 +57,10 @@ void TrackCounters::AddToLabel(std::ostream &out, benchmark::State &state) {
<< ((double)(gpr_atm_no_barrier_load(&gpr_counter_atm_add) - << ((double)(gpr_atm_no_barrier_load(&gpr_counter_atm_add) -
atm_add_at_start_) / atm_add_at_start_) /
(double)state.iterations()) (double)state.iterations())
<< " nows/iter:"
<< ((double)(gpr_atm_no_barrier_load(&gpr_now_call_count) -
now_calls_at_start_) /
(double)state.iterations())
<< " allocs/iter:" << " allocs/iter:"
<< ((double)(counters_at_end.total_allocs_absolute - << ((double)(counters_at_end.total_allocs_absolute -
counters_at_start_.total_allocs_absolute) / counters_at_start_.total_allocs_absolute) /

@ -72,6 +72,7 @@ class Library {
extern "C" gpr_atm gpr_mu_locks; extern "C" gpr_atm gpr_mu_locks;
extern "C" gpr_atm gpr_counter_atm_cas; extern "C" gpr_atm gpr_counter_atm_cas;
extern "C" gpr_atm gpr_counter_atm_add; extern "C" gpr_atm gpr_counter_atm_add;
extern "C" gpr_atm gpr_now_call_count;
#endif #endif
class TrackCounters { class TrackCounters {
@ -86,6 +87,8 @@ class TrackCounters {
gpr_atm_no_barrier_load(&gpr_counter_atm_cas); gpr_atm_no_barrier_load(&gpr_counter_atm_cas);
const size_t atm_add_at_start_ = const size_t atm_add_at_start_ =
gpr_atm_no_barrier_load(&gpr_counter_atm_add); gpr_atm_no_barrier_load(&gpr_counter_atm_add);
const size_t now_calls_at_start_ =
gpr_atm_no_barrier_load(&gpr_now_call_count);
grpc_memory_counters counters_at_start_ = grpc_memory_counters_snapshot(); grpc_memory_counters counters_at_start_ = grpc_memory_counters_snapshot();
#endif #endif
}; };

@ -2,11 +2,14 @@ cc_library(
name = "gtest", name = "gtest",
srcs = [ srcs = [
"googletest/src/gtest-all.cc", "googletest/src/gtest-all.cc",
"googlemock/src/gmock-all.cc"
], ],
hdrs = glob(["googletest/include/**/*.h", "googletest/src/*.cc", "googletest/src/*.h"]), hdrs = glob(["googletest/include/**/*.h", "googletest/src/*.cc", "googletest/src/*.h", "googlemock/include/**/*.h", "googlemock/src/*.cc", "googlemock/src/*.h"]),
includes = [ includes = [
"googletest", "googletest",
"googletest/include", "googletest/include",
"googlemock",
"googlemock/include",
], ],
linkstatic = 1, linkstatic = 1,
visibility = [ visibility = [

@ -37,4 +37,5 @@ BENCHMARKS_TO_RUN="bm_fullstack_unary_ping_pong bm_fullstack_streaming_ping_pong
# Enter the gRPC repo root # Enter the gRPC repo root
cd $(dirname $0)/../.. cd $(dirname $0)/../..
tools/run_tests/start_port_server.py
tools/profiling/microbenchmarks/bm_diff.py -d origin/$ghprbTargetBranch -b $BENCHMARKS_TO_RUN tools/profiling/microbenchmarks/bm_diff.py -d origin/$ghprbTargetBranch -b $BENCHMARKS_TO_RUN

@ -71,6 +71,7 @@ columns = [
('end_of_stream', 'boolean'), ('end_of_stream', 'boolean'),
('header_bytes_per_iteration', 'float'), ('header_bytes_per_iteration', 'float'),
('framing_bytes_per_iteration', 'float'), ('framing_bytes_per_iteration', 'float'),
('nows_per_iteration', 'float'),
] ]
SANITIZE = { SANITIZE = {
@ -103,4 +104,3 @@ for row in bm_json.expand_json(js, js2):
if row[name] == '': continue if row[name] == '': continue
sane_row[name] = SANITIZE[sql_type](row[name]) sane_row[name] = SANITIZE[sql_type](row[name])
writer.writerow(sane_row) writer.writerow(sane_row)

@ -56,6 +56,7 @@ _INTERESTING = (
'writes_per_iteration', 'writes_per_iteration',
'atm_cas_per_iteration', 'atm_cas_per_iteration',
'atm_add_per_iteration', 'atm_add_per_iteration',
'nows_per_iteration',
) )
def changed_ratio(n, o): def changed_ratio(n, o):
@ -203,7 +204,10 @@ def eintr_be_gone(fn):
def read_json(filename): def read_json(filename):
try:
with open(filename) as f: return json.loads(f.read()) with open(filename) as f: return json.loads(f.read())
except ValueError, e:
return None
def finalize(): def finalize():
@ -216,11 +220,13 @@ def finalize():
js_old_ctr = read_json('%s.counters.old.%d.json' % (bm, loop)) js_old_ctr = read_json('%s.counters.old.%d.json' % (bm, loop))
js_old_opt = read_json('%s.opt.old.%d.json' % (bm, loop)) js_old_opt = read_json('%s.opt.old.%d.json' % (bm, loop))
if js_new_ctr:
for row in bm_json.expand_json(js_new_ctr, js_new_opt): for row in bm_json.expand_json(js_new_ctr, js_new_opt):
print row print row
name = row['cpp_name'] name = row['cpp_name']
if name.endswith('_mean') or name.endswith('_stddev'): continue if name.endswith('_mean') or name.endswith('_stddev'): continue
benchmarks[name].add_sample(row, True) benchmarks[name].add_sample(row, True)
if js_old_ctr:
for row in bm_json.expand_json(js_old_ctr, js_old_opt): for row in bm_json.expand_json(js_old_ctr, js_old_opt):
print row print row
name = row['cpp_name'] name = row['cpp_name']

@ -2871,14 +2871,19 @@
"headers": [ "headers": [
"src/proto/grpc/testing/control.grpc.pb.h", "src/proto/grpc/testing/control.grpc.pb.h",
"src/proto/grpc/testing/control.pb.h", "src/proto/grpc/testing/control.pb.h",
"src/proto/grpc/testing/control_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/payloads.grpc.pb.h", "src/proto/grpc/testing/payloads.grpc.pb.h",
"src/proto/grpc/testing/payloads.pb.h", "src/proto/grpc/testing/payloads.pb.h",
"src/proto/grpc/testing/payloads_mock.grpc.pb.h",
"src/proto/grpc/testing/services.grpc.pb.h", "src/proto/grpc/testing/services.grpc.pb.h",
"src/proto/grpc/testing/services.pb.h", "src/proto/grpc/testing/services.pb.h",
"src/proto/grpc/testing/services_mock.grpc.pb.h",
"src/proto/grpc/testing/stats.grpc.pb.h", "src/proto/grpc/testing/stats.grpc.pb.h",
"src/proto/grpc/testing/stats.pb.h" "src/proto/grpc/testing/stats.pb.h",
"src/proto/grpc/testing/stats_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -2899,14 +2904,19 @@
"headers": [ "headers": [
"src/proto/grpc/testing/control.grpc.pb.h", "src/proto/grpc/testing/control.grpc.pb.h",
"src/proto/grpc/testing/control.pb.h", "src/proto/grpc/testing/control.pb.h",
"src/proto/grpc/testing/control_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/payloads.grpc.pb.h", "src/proto/grpc/testing/payloads.grpc.pb.h",
"src/proto/grpc/testing/payloads.pb.h", "src/proto/grpc/testing/payloads.pb.h",
"src/proto/grpc/testing/payloads_mock.grpc.pb.h",
"src/proto/grpc/testing/services.grpc.pb.h", "src/proto/grpc/testing/services.grpc.pb.h",
"src/proto/grpc/testing/services.pb.h", "src/proto/grpc/testing/services.pb.h",
"src/proto/grpc/testing/services_mock.grpc.pb.h",
"src/proto/grpc/testing/stats.grpc.pb.h", "src/proto/grpc/testing/stats.grpc.pb.h",
"src/proto/grpc/testing/stats.pb.h" "src/proto/grpc/testing/stats.pb.h",
"src/proto/grpc/testing/stats_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3027,7 +3037,8 @@
], ],
"headers": [ "headers": [
"src/proto/grpc/testing/echo_messages.grpc.pb.h", "src/proto/grpc/testing/echo_messages.grpc.pb.h",
"src/proto/grpc/testing/echo_messages.pb.h" "src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3084,7 +3095,8 @@
], ],
"headers": [ "headers": [
"src/proto/grpc/testing/compiler_test.grpc.pb.h", "src/proto/grpc/testing/compiler_test.grpc.pb.h",
"src/proto/grpc/testing/compiler_test.pb.h" "src/proto/grpc/testing/compiler_test.pb.h",
"src/proto/grpc/testing/compiler_test_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3229,7 +3241,9 @@
"src/proto/grpc/testing/echo.grpc.pb.h", "src/proto/grpc/testing/echo.grpc.pb.h",
"src/proto/grpc/testing/echo.pb.h", "src/proto/grpc/testing/echo.pb.h",
"src/proto/grpc/testing/echo_messages.grpc.pb.h", "src/proto/grpc/testing/echo_messages.grpc.pb.h",
"src/proto/grpc/testing/echo_messages.pb.h" "src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h",
"src/proto/grpc/testing/echo_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3249,7 +3263,8 @@
], ],
"headers": [ "headers": [
"src/proto/grpc/lb/v1/load_balancer.grpc.pb.h", "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h",
"src/proto/grpc/lb/v1/load_balancer.pb.h" "src/proto/grpc/lb/v1/load_balancer.pb.h",
"src/proto/grpc/lb/v1/load_balancer_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3271,7 +3286,8 @@
], ],
"headers": [ "headers": [
"src/proto/grpc/lb/v1/load_balancer.grpc.pb.h", "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h",
"src/proto/grpc/lb/v1/load_balancer.pb.h" "src/proto/grpc/lb/v1/load_balancer.pb.h",
"src/proto/grpc/lb/v1/load_balancer_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3426,6 +3442,7 @@
"headers": [ "headers": [
"src/proto/grpc/testing/metrics.grpc.pb.h", "src/proto/grpc/testing/metrics.grpc.pb.h",
"src/proto/grpc/testing/metrics.pb.h", "src/proto/grpc/testing/metrics.pb.h",
"src/proto/grpc/testing/metrics_mock.grpc.pb.h",
"test/cpp/util/metrics_server.h" "test/cpp/util/metrics_server.h"
], ],
"is_filegroup": false, "is_filegroup": false,
@ -3447,11 +3464,14 @@
"grpc++_test_util", "grpc++_test_util",
"grpc_test_util" "grpc_test_util"
], ],
"headers": [], "headers": [
"include/grpc++/test/mock_stream.h"
],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
"name": "mock_test", "name": "mock_test",
"src": [ "src": [
"include/grpc++/test/mock_stream.h",
"test/cpp/end2end/mock_test.cc" "test/cpp/end2end/mock_test.cc"
], ],
"third_party": false, "third_party": false,
@ -3610,10 +3630,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h" "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3639,10 +3662,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h" "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3743,7 +3769,9 @@
"src/proto/grpc/testing/echo.grpc.pb.h", "src/proto/grpc/testing/echo.grpc.pb.h",
"src/proto/grpc/testing/echo.pb.h", "src/proto/grpc/testing/echo.pb.h",
"src/proto/grpc/testing/echo_messages.grpc.pb.h", "src/proto/grpc/testing/echo_messages.grpc.pb.h",
"src/proto/grpc/testing/echo_messages.pb.h" "src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h",
"src/proto/grpc/testing/echo_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -3880,12 +3908,16 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/metrics.grpc.pb.h", "src/proto/grpc/testing/metrics.grpc.pb.h",
"src/proto/grpc/testing/metrics.pb.h", "src/proto/grpc/testing/metrics.pb.h",
"src/proto/grpc/testing/metrics_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h", "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h",
"test/cpp/interop/client_helper.h", "test/cpp/interop/client_helper.h",
"test/cpp/interop/interop_client.h", "test/cpp/interop/interop_client.h",
"test/cpp/interop/stress_interop_client.h", "test/cpp/interop/stress_interop_client.h",
@ -5900,7 +5932,8 @@
"headers": [ "headers": [
"include/grpc++/support/error_details.h", "include/grpc++/support/error_details.h",
"src/proto/grpc/status/status.grpc.pb.h", "src/proto/grpc/status/status.grpc.pb.h",
"src/proto/grpc/status/status.pb.h" "src/proto/grpc/status/status.pb.h",
"src/proto/grpc/status/status_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -5980,12 +6013,16 @@
"headers": [ "headers": [
"src/proto/grpc/health/v1/health.grpc.pb.h", "src/proto/grpc/health/v1/health.grpc.pb.h",
"src/proto/grpc/health/v1/health.pb.h", "src/proto/grpc/health/v1/health.pb.h",
"src/proto/grpc/health/v1/health_mock.grpc.pb.h",
"src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h", "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h",
"src/proto/grpc/testing/duplicate/echo_duplicate.pb.h", "src/proto/grpc/testing/duplicate/echo_duplicate.pb.h",
"src/proto/grpc/testing/duplicate/echo_duplicate_mock.grpc.pb.h",
"src/proto/grpc/testing/echo.grpc.pb.h", "src/proto/grpc/testing/echo.grpc.pb.h",
"src/proto/grpc/testing/echo.pb.h", "src/proto/grpc/testing/echo.pb.h",
"src/proto/grpc/testing/echo_messages.grpc.pb.h", "src/proto/grpc/testing/echo_messages.grpc.pb.h",
"src/proto/grpc/testing/echo_messages.pb.h", "src/proto/grpc/testing/echo_messages.pb.h",
"src/proto/grpc/testing/echo_messages_mock.grpc.pb.h",
"src/proto/grpc/testing/echo_mock.grpc.pb.h",
"test/cpp/end2end/test_service_impl.h", "test/cpp/end2end/test_service_impl.h",
"test/cpp/util/byte_buffer_proto_helper.h", "test/cpp/util/byte_buffer_proto_helper.h",
"test/cpp/util/create_test_channel.h", "test/cpp/util/create_test_channel.h",
@ -6165,10 +6202,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h", "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h",
"test/cpp/interop/http2_client.h" "test/cpp/interop/http2_client.h"
], ],
"is_filegroup": false, "is_filegroup": false,
@ -6192,6 +6232,7 @@
"headers": [ "headers": [
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"test/cpp/interop/client_helper.h" "test/cpp/interop/client_helper.h"
], ],
"is_filegroup": false, "is_filegroup": false,
@ -6218,10 +6259,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h", "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h",
"test/cpp/interop/interop_client.h" "test/cpp/interop/interop_client.h"
], ],
"is_filegroup": false, "is_filegroup": false,
@ -6270,10 +6314,13 @@
"headers": [ "headers": [
"src/proto/grpc/testing/empty.grpc.pb.h", "src/proto/grpc/testing/empty.grpc.pb.h",
"src/proto/grpc/testing/empty.pb.h", "src/proto/grpc/testing/empty.pb.h",
"src/proto/grpc/testing/empty_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/test.grpc.pb.h", "src/proto/grpc/testing/test.grpc.pb.h",
"src/proto/grpc/testing/test.pb.h" "src/proto/grpc/testing/test.pb.h",
"src/proto/grpc/testing/test_mock.grpc.pb.h"
], ],
"is_filegroup": false, "is_filegroup": false,
"language": "c++", "language": "c++",
@ -6307,14 +6354,19 @@
"headers": [ "headers": [
"src/proto/grpc/testing/control.grpc.pb.h", "src/proto/grpc/testing/control.grpc.pb.h",
"src/proto/grpc/testing/control.pb.h", "src/proto/grpc/testing/control.pb.h",
"src/proto/grpc/testing/control_mock.grpc.pb.h",
"src/proto/grpc/testing/messages.grpc.pb.h", "src/proto/grpc/testing/messages.grpc.pb.h",
"src/proto/grpc/testing/messages.pb.h", "src/proto/grpc/testing/messages.pb.h",
"src/proto/grpc/testing/messages_mock.grpc.pb.h",
"src/proto/grpc/testing/payloads.grpc.pb.h", "src/proto/grpc/testing/payloads.grpc.pb.h",
"src/proto/grpc/testing/payloads.pb.h", "src/proto/grpc/testing/payloads.pb.h",
"src/proto/grpc/testing/payloads_mock.grpc.pb.h",
"src/proto/grpc/testing/services.grpc.pb.h", "src/proto/grpc/testing/services.grpc.pb.h",
"src/proto/grpc/testing/services.pb.h", "src/proto/grpc/testing/services.pb.h",
"src/proto/grpc/testing/services_mock.grpc.pb.h",
"src/proto/grpc/testing/stats.grpc.pb.h", "src/proto/grpc/testing/stats.grpc.pb.h",
"src/proto/grpc/testing/stats.pb.h", "src/proto/grpc/testing/stats.pb.h",
"src/proto/grpc/testing/stats_mock.grpc.pb.h",
"test/cpp/qps/benchmark_config.h", "test/cpp/qps/benchmark_config.h",
"test/cpp/qps/client.h", "test/cpp/qps/client.h",
"test/cpp/qps/driver.h", "test/cpp/qps/driver.h",
@ -9020,7 +9072,8 @@
"deps": [], "deps": [],
"headers": [ "headers": [
"src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h", "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h",
"src/proto/grpc/reflection/v1alpha/reflection.pb.h" "src/proto/grpc/reflection/v1alpha/reflection.pb.h",
"src/proto/grpc/reflection/v1alpha/reflection_mock.grpc.pb.h"
], ],
"is_filegroup": true, "is_filegroup": true,
"language": "c++", "language": "c++",
@ -9034,12 +9087,14 @@
"grpc++" "grpc++"
], ],
"headers": [ "headers": [
"include/grpc++/test/mock_stream.h",
"include/grpc++/test/server_context_test_spouse.h" "include/grpc++/test/server_context_test_spouse.h"
], ],
"is_filegroup": true, "is_filegroup": true,
"language": "c++", "language": "c++",
"name": "grpc++_test", "name": "grpc++_test",
"src": [ "src": [
"include/grpc++/test/mock_stream.h",
"include/grpc++/test/server_context_test_spouse.h" "include/grpc++/test/server_context_test_spouse.h"
], ],
"third_party": false, "third_party": false,

@ -3329,7 +3329,7 @@
}, },
{ {
"args": [ "args": [
"--generated_file_path=gens/src/proto/grpc/testing/compiler_test.grpc.pb.h" "--generated_file_path=gens/src/proto/grpc/testing/"
], ],
"ci_platforms": [ "ci_platforms": [
"linux", "linux",

@ -33,18 +33,20 @@
from __future__ import print_function from __future__ import print_function
import argparse import argparse
from six.moves import BaseHTTPServer from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
import hashlib import hashlib
import os import os
import socket import socket
import sys import sys
import time import time
from SocketServer import ThreadingMixIn
import threading
# increment this number whenever making a change to ensure that # increment this number whenever making a change to ensure that
# the changes are picked up by running CI servers # the changes are picked up by running CI servers
# note that all changes must be backwards compatible # note that all changes must be backwards compatible
_MY_VERSION = 9 _MY_VERSION = 14
if len(sys.argv) == 2 and sys.argv[1] == 'dump_version': if len(sys.argv) == 2 and sys.argv[1] == 'dump_version':
@ -68,6 +70,7 @@ print('port server running on port %d' % args.port)
pool = [] pool = []
in_use = {} in_use = {}
mu = threading.Lock()
def refill_pool(max_timeout, req): def refill_pool(max_timeout, req):
@ -95,28 +98,33 @@ def refill_pool(max_timeout, req):
def allocate_port(req): def allocate_port(req):
global pool global pool
global in_use global in_use
global mu
mu.acquire()
max_timeout = 600 max_timeout = 600
while not pool: while not pool:
refill_pool(max_timeout, req) refill_pool(max_timeout, req)
if not pool: if not pool:
req.log_message("failed to find ports: retrying soon") req.log_message("failed to find ports: retrying soon")
mu.release()
time.sleep(1) time.sleep(1)
mu.acquire()
max_timeout /= 2 max_timeout /= 2
port = pool[0] port = pool[0]
pool = pool[1:] pool = pool[1:]
in_use[port] = time.time() in_use[port] = time.time()
mu.release()
return port return port
keep_running = True keep_running = True
class Handler(BaseHTTPServer.BaseHTTPRequestHandler): class Handler(BaseHTTPRequestHandler):
def setup(self): def setup(self):
# If the client is unreachable for 5 seconds, close the connection # If the client is unreachable for 5 seconds, close the connection
self.timeout = 5 self.timeout = 5
BaseHTTPServer.BaseHTTPRequestHandler.setup(self) BaseHTTPRequestHandler.setup(self)
def do_GET(self): def do_GET(self):
global keep_running global keep_running
@ -158,12 +166,11 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
elif self.path == '/quitquitquit': elif self.path == '/quitquitquit':
self.send_response(200) self.send_response(200)
self.end_headers() self.end_headers()
keep_running = False self.server.shutdown()
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread"""
httpd = BaseHTTPServer.HTTPServer(('', args.port), Handler)
while keep_running:
httpd.handle_request()
sys.stderr.flush()
print('done') ThreadedHTTPServer(('', args.port), Handler).serve_forever()

@ -159,6 +159,9 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="$(SolutionDir)\..\include\grpc++\test\mock_stream.h" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\mock_test.cc"> <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\mock_test.cc">
</ClCompile> </ClCompile>

@ -5,8 +5,22 @@
<Filter>test\cpp\end2end</Filter> <Filter>test\cpp\end2end</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ClInclude Include="$(SolutionDir)\..\include\grpc++\test\mock_stream.h">
<Filter>include\grpc++\test</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="include">
<UniqueIdentifier>{b827d6d2-cfa5-2dd4-6ebc-afcccd5e8e0c}</UniqueIdentifier>
</Filter>
<Filter Include="include\grpc++">
<UniqueIdentifier>{28289e8f-b68e-b9f5-7680-c15d77b574a5}</UniqueIdentifier>
</Filter>
<Filter Include="include\grpc++\test">
<UniqueIdentifier>{4a7b43be-c730-6221-d190-e394521f9ae7}</UniqueIdentifier>
</Filter>
<Filter Include="test"> <Filter Include="test">
<UniqueIdentifier>{69c257a2-3e4c-a86e-ce0d-1a97b237d294}</UniqueIdentifier> <UniqueIdentifier>{69c257a2-3e4c-a86e-ce0d-1a97b237d294}</UniqueIdentifier>
</Filter> </Filter>

Loading…
Cancel
Save