Browse Source

Merge remote-tracking branch 'upstream/master' into trailing_metadata_status

kpayson64 7 years ago
parent
commit
586267cd8d
100 changed files with 1254 additions and 3972 deletions
  1. 6 0
      .clang-tidy
  2. 9 2
      .pylintrc
  3. 9 2
      .pylintrc-tests
  4. 47 0
      CMakeLists.txt
  5. 50 0
      Makefile
  6. 2 1
      bazel/grpc_build_system.bzl
  7. 1 0
      build.yaml
  8. 1 0
      gRPC-Core.podspec
  9. 2 0
      grpc.gyp
  10. 2 0
      include/grpc/impl/codegen/grpc_types.h
  11. 7 4
      include/grpcpp/impl/codegen/call.h
  12. 26 3
      include/grpcpp/impl/codegen/server_interface.h
  13. 2 0
      include/grpcpp/server_builder.h
  14. 2 1
      src/compiler/csharp_generator.cc
  15. 63 36
      src/core/ext/filters/client_channel/client_channel.cc
  16. 13 0
      src/core/ext/filters/client_channel/http_proxy.cc
  17. 29 34
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
  18. 2 3
      src/core/ext/filters/deadline/deadline_filter.cc
  19. 1 3
      src/core/ext/filters/load_reporting/server_load_reporting_filter.cc
  20. 1 1
      src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc
  21. 3 2
      src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc
  22. 2 0
      src/core/lib/gprpp/inlined_vector.h
  23. 12 12
      src/core/lib/iomgr/call_combiner.h
  24. 3 1
      src/core/lib/iomgr/cfstream_handle.cc
  25. 2 2
      src/core/lib/iomgr/endpoint_pair_posix.cc
  26. 12 0
      src/core/lib/iomgr/error.cc
  27. 5 0
      src/core/lib/iomgr/error.h
  28. 36 9
      src/core/lib/iomgr/ev_epoll1_linux.cc
  29. 45 10
      src/core/lib/iomgr/ev_epollex_linux.cc
  30. 47 21
      src/core/lib/iomgr/ev_epollsig_linux.cc
  31. 10 4
      src/core/lib/iomgr/ev_poll_posix.cc
  32. 17 9
      src/core/lib/iomgr/ev_posix.cc
  33. 20 4
      src/core/lib/iomgr/ev_posix.h
  34. 7 7
      src/core/lib/iomgr/tcp_client_cfstream.cc
  35. 3 5
      src/core/lib/iomgr/tcp_client_posix.cc
  36. 1 1
      src/core/lib/iomgr/tcp_posix.cc
  37. 3 3
      src/core/lib/iomgr/tcp_server_posix.cc
  38. 1 1
      src/core/lib/iomgr/tcp_server_utils_posix_common.cc
  39. 2 3
      src/core/lib/iomgr/udp_server.cc
  40. 14 4
      src/core/lib/surface/call.cc
  41. 1 1
      src/csharp/Grpc.Core.Testing/TestCalls.cs
  42. 2 0
      src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
  43. 101 0
      src/csharp/Grpc.Examples.Tests/MathClientMockableTest.cs
  44. 47 0
      src/csharp/Grpc.Examples.Tests/MathServiceImplTestabilityTest.cs
  45. 12 12
      src/csharp/Grpc.Examples/MathGrpc.cs
  46. 4 4
      src/csharp/Grpc.HealthCheck/HealthGrpc.cs
  47. 12 12
      src/csharp/Grpc.IntegrationTesting/BenchmarkServiceGrpc.cs
  48. 0 23
      src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
  49. 0 1
      src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
  50. 7 7
      src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
  51. 4 4
      src/csharp/Grpc.IntegrationTesting/ReportQpsScenarioServiceGrpc.cs
  52. 33 33
      src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
  53. 15 15
      src/csharp/Grpc.IntegrationTesting/WorkerServiceGrpc.cs
  54. 4 4
      src/csharp/Grpc.Reflection/ReflectionGrpc.cs
  55. 3 1
      src/csharp/tests.json
  56. 4 1
      src/objective-c/GRPCClient/GRPCCall.m
  57. 16 7
      src/objective-c/GRPCClient/private/GRPCHost.m
  58. 1 16
      src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj
  59. 2 0
      src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m
  60. 3 3
      src/objective-c/tests/Connectivity/Podfile
  61. 2 1
      src/objective-c/tests/GRPCClientTests.m
  62. 2 1
      src/php/README.md
  63. 0 4
      src/proto/grpc/testing/messages.proto
  64. 10 8
      src/python/grpcio/grpc/__init__.py
  65. 2 5
      src/python/grpcio/grpc/_channel.py
  66. 0 0
      src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pxd.pxi
  67. 0 0
      src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi
  68. 1 1
      src/python/grpcio/grpc/_cython/cygrpc.pxd
  69. 1 1
      src/python/grpcio/grpc/_cython/cygrpc.pyx
  70. 13 4
      src/python/grpcio/grpc/_interceptor.py
  71. 20 1
      src/python/grpcio/grpc/_server.py
  72. 2 0
      src/python/grpcio/grpc/_utilities.py
  73. 1 0
      src/python/grpcio/grpc/beta/_server_adaptations.py
  74. 2 0
      src/python/grpcio/grpc/beta/utilities.py
  75. 4 4
      src/python/grpcio/grpc/framework/foundation/stream_util.py
  76. 1 1
      src/python/grpcio_testing/grpc_testing/__init__.py
  77. 2 2
      src/python/grpcio_testing/grpc_testing/_server/_handler.py
  78. 6 5
      src/python/grpcio_tests/tests/_loader.py
  79. 15 26
      src/python/grpcio_tests/tests/_result.py
  80. 2 2
      src/python/grpcio_tests/tests/interop/methods.py
  81. 1 0
      src/python/grpcio_tests/tests/tests.json
  82. 0 13
      src/python/grpcio_tests/tests/unit/_junkdrawer/__init__.py
  83. 0 164
      src/python/grpcio_tests/tests/unit/_junkdrawer/stock_pb2.py
  84. 52 0
      src/python/grpcio_tests/tests/unit/_server_test.py
  85. 3 3
      templates/test/cpp/naming/resolver_component_tests_defs.include
  86. 0 3359
      test/core/avl/avl_test.cc
  87. 8 0
      test/core/end2end/end2end_nosec_tests.cc
  88. 8 0
      test/core/end2end/end2end_tests.cc
  89. 1 0
      test/core/end2end/gen_build_yaml.py
  90. 1 0
      test/core/end2end/generate_tests.bzl
  91. 246 0
      test/core/end2end/tests/no_error_on_hotpath.cc
  92. 2 0
      test/core/gprpp/inlined_vector_test.cc
  93. 1 0
      test/core/iomgr/BUILD
  94. 4 6
      test/core/iomgr/ev_epollsig_linux_test.cc
  95. 8 8
      test/core/iomgr/fd_posix_test.cc
  96. 2 3
      test/core/iomgr/pollset_set_test.cc
  97. 12 8
      test/core/iomgr/tcp_posix_test.cc
  98. 19 6
      test/core/transport/status_conversion_test.cc
  99. 5 0
      test/cpp/end2end/end2end_test.cc
  100. 4 4
      test/cpp/microbenchmarks/bm_pollset.cc

+ 6 - 0
.clang-tidy

@@ -0,0 +1,6 @@
+---
+Checks: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size'
+WarningsAsErrors: 'modernize-use-nullptr,google-build-namespaces,google-build-explicit-make-pair,readability-function-size'
+CheckOptions:
+  - key:    readability-function-size.StatementThreshold
+    value:  '450'

+ 9 - 2
.pylintrc

@@ -72,6 +72,13 @@ disable=
 	# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have
 	# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have
 	# this one if we extracted just a few more helper functions...
 	# this one if we extracted just a few more helper functions...
 	too-many-nested-blocks,
 	too-many-nested-blocks,
-	# NOTE(nathaniel): I have disputed the premise of this inspection from
-	# the beginning and will continue to do so until it goes away for good.
+	# TODO(https://github.com/grpc/grpc/issues/261): Disable unnecessary
+	# super-init requirement for abstract class implementations for now.
+	super-init-not-called,
+	# NOTE(nathaniel): A single statement that always returns program
+	# control is better than two statements the first of which sometimes
+	# returns program control and the second of which always returns
+	# program control. Probably generally, but definitely in the cases of
+	# if:/else: and for:/else:.
 	useless-else-on-loop,
 	useless-else-on-loop,
+	no-else-return,

+ 9 - 2
.pylintrc-tests

@@ -103,6 +103,13 @@ disable=
 	# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have
 	# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have
 	# this one if we extracted just a few more helper functions...
 	# this one if we extracted just a few more helper functions...
 	too-many-nested-blocks,
 	too-many-nested-blocks,
-	# NOTE(nathaniel): I have disputed the premise of this inspection from
-	# the beginning and will continue to do so until it goes away for good.
+	# TODO(https://github.com/grpc/grpc/issues/261): Disable unnecessary
+	# super-init requirement for abstract class implementations for now.
+	super-init-not-called,
+	# NOTE(nathaniel): A single statement that always returns program
+	# control is better than two statements the first of which sometimes
+	# returns program control and the second of which always returns
+	# program control. Probably generally, but definitely in the cases of
+	# if:/else: and for:/else:.
 	useless-else-on-loop,
 	useless-else-on-loop,
+	no-else-return,

+ 47 - 0
CMakeLists.txt

@@ -663,6 +663,9 @@ endif()
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx address_sorting_test)
 add_dependencies(buildtests_cxx address_sorting_test)
 endif()
 endif()
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_dependencies(buildtests_cxx cancel_ares_query_test)
+endif()
 
 
 add_custom_target(buildtests
 add_custom_target(buildtests
   DEPENDS buildtests_c buildtests_cxx)
   DEPENDS buildtests_c buildtests_cxx)
@@ -5298,6 +5301,7 @@ add_library(end2end_tests
   test/core/end2end/tests/max_message_length.cc
   test/core/end2end/tests/max_message_length.cc
   test/core/end2end/tests/negative_deadline.cc
   test/core/end2end/tests/negative_deadline.cc
   test/core/end2end/tests/network_status_change.cc
   test/core/end2end/tests/network_status_change.cc
+  test/core/end2end/tests/no_error_on_hotpath.cc
   test/core/end2end/tests/no_logging.cc
   test/core/end2end/tests/no_logging.cc
   test/core/end2end/tests/no_op.cc
   test/core/end2end/tests/no_op.cc
   test/core/end2end/tests/payload.cc
   test/core/end2end/tests/payload.cc
@@ -5416,6 +5420,7 @@ add_library(end2end_nosec_tests
   test/core/end2end/tests/max_message_length.cc
   test/core/end2end/tests/max_message_length.cc
   test/core/end2end/tests/negative_deadline.cc
   test/core/end2end/tests/negative_deadline.cc
   test/core/end2end/tests/network_status_change.cc
   test/core/end2end/tests/network_status_change.cc
+  test/core/end2end/tests/no_error_on_hotpath.cc
   test/core/end2end/tests/no_logging.cc
   test/core/end2end/tests/no_logging.cc
   test/core/end2end/tests/no_op.cc
   test/core/end2end/tests/no_op.cc
   test/core/end2end/tests/payload.cc
   test/core/end2end/tests/payload.cc
@@ -15840,6 +15845,48 @@ target_link_libraries(address_sorting_test
   ${_gRPC_GFLAGS_LIBRARIES}
   ${_gRPC_GFLAGS_LIBRARIES}
 )
 )
 
 
+endif()
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
+add_executable(cancel_ares_query_test
+  test/cpp/naming/cancel_ares_query_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(cancel_ares_query_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+  PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+  PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+  PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+  PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(cancel_ares_query_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test_util
+  grpc_test_util
+  gpr_test_util
+  grpc++
+  grpc
+  gpr
+  grpc++_test_config
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
 endif()
 endif()
 endif (gRPC_BUILD_TESTS)
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)

+ 50 - 0
Makefile

@@ -1316,6 +1316,7 @@ resolver_component_tests_runner_invoker_unsecure: $(BINDIR)/$(CONFIG)/resolver_c
 resolver_component_tests_runner_invoker: $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker
 resolver_component_tests_runner_invoker: $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker
 address_sorting_test_unsecure: $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure
 address_sorting_test_unsecure: $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure
 address_sorting_test: $(BINDIR)/$(CONFIG)/address_sorting_test
 address_sorting_test: $(BINDIR)/$(CONFIG)/address_sorting_test
+cancel_ares_query_test: $(BINDIR)/$(CONFIG)/cancel_ares_query_test
 alts_credentials_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/alts_credentials_fuzzer_one_entry
 alts_credentials_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/alts_credentials_fuzzer_one_entry
 api_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/api_fuzzer_one_entry
 api_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/api_fuzzer_one_entry
 client_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/client_fuzzer_one_entry
 client_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/client_fuzzer_one_entry
@@ -1753,6 +1754,7 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker \
   $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure \
   $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure \
   $(BINDIR)/$(CONFIG)/address_sorting_test \
   $(BINDIR)/$(CONFIG)/address_sorting_test \
+  $(BINDIR)/$(CONFIG)/cancel_ares_query_test \
 
 
 else
 else
 buildtests_cxx: privatelibs_cxx \
 buildtests_cxx: privatelibs_cxx \
@@ -1877,6 +1879,7 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker \
   $(BINDIR)/$(CONFIG)/resolver_component_tests_runner_invoker \
   $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure \
   $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure \
   $(BINDIR)/$(CONFIG)/address_sorting_test \
   $(BINDIR)/$(CONFIG)/address_sorting_test \
+  $(BINDIR)/$(CONFIG)/cancel_ares_query_test \
 
 
 endif
 endif
 
 
@@ -2362,6 +2365,8 @@ test_cxx: buildtests_cxx
 	$(Q) $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure || ( echo test address_sorting_test_unsecure failed ; exit 1 )
 	$(Q) $(BINDIR)/$(CONFIG)/address_sorting_test_unsecure || ( echo test address_sorting_test_unsecure failed ; exit 1 )
 	$(E) "[RUN]     Testing address_sorting_test"
 	$(E) "[RUN]     Testing address_sorting_test"
 	$(Q) $(BINDIR)/$(CONFIG)/address_sorting_test || ( echo test address_sorting_test failed ; exit 1 )
 	$(Q) $(BINDIR)/$(CONFIG)/address_sorting_test || ( echo test address_sorting_test failed ; exit 1 )
+	$(E) "[RUN]     Testing cancel_ares_query_test"
+	$(Q) $(BINDIR)/$(CONFIG)/cancel_ares_query_test || ( echo test cancel_ares_query_test failed ; exit 1 )
 
 
 
 
 flaky_test_cxx: buildtests_cxx
 flaky_test_cxx: buildtests_cxx
@@ -9991,6 +9996,7 @@ LIBEND2END_TESTS_SRC = \
     test/core/end2end/tests/max_message_length.cc \
     test/core/end2end/tests/max_message_length.cc \
     test/core/end2end/tests/negative_deadline.cc \
     test/core/end2end/tests/negative_deadline.cc \
     test/core/end2end/tests/network_status_change.cc \
     test/core/end2end/tests/network_status_change.cc \
+    test/core/end2end/tests/no_error_on_hotpath.cc \
     test/core/end2end/tests/no_logging.cc \
     test/core/end2end/tests/no_logging.cc \
     test/core/end2end/tests/no_op.cc \
     test/core/end2end/tests/no_op.cc \
     test/core/end2end/tests/payload.cc \
     test/core/end2end/tests/payload.cc \
@@ -10107,6 +10113,7 @@ LIBEND2END_NOSEC_TESTS_SRC = \
     test/core/end2end/tests/max_message_length.cc \
     test/core/end2end/tests/max_message_length.cc \
     test/core/end2end/tests/negative_deadline.cc \
     test/core/end2end/tests/negative_deadline.cc \
     test/core/end2end/tests/network_status_change.cc \
     test/core/end2end/tests/network_status_change.cc \
+    test/core/end2end/tests/no_error_on_hotpath.cc \
     test/core/end2end/tests/no_logging.cc \
     test/core/end2end/tests/no_logging.cc \
     test/core/end2end/tests/no_op.cc \
     test/core/end2end/tests/no_op.cc \
     test/core/end2end/tests/payload.cc \
     test/core/end2end/tests/payload.cc \
@@ -23687,6 +23694,49 @@ endif
 endif
 endif
 
 
 
 
+CANCEL_ARES_QUERY_TEST_SRC = \
+    test/cpp/naming/cancel_ares_query_test.cc \
+
+CANCEL_ARES_QUERY_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CANCEL_ARES_QUERY_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/cancel_ares_query_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/cancel_ares_query_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/cancel_ares_query_test: $(PROTOBUF_DEP) $(CANCEL_ARES_QUERY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(CANCEL_ARES_QUERY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/cancel_ares_query_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/naming/cancel_ares_query_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+
+deps_cancel_ares_query_test: $(CANCEL_ARES_QUERY_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CANCEL_ARES_QUERY_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 ALTS_CREDENTIALS_FUZZER_ONE_ENTRY_SRC = \
 ALTS_CREDENTIALS_FUZZER_ONE_ENTRY_SRC = \
     test/core/security/alts_credentials_fuzzer.cc \
     test/core/security/alts_credentials_fuzzer.cc \
     test/core/util/one_corpus_entry_fuzzer.cc \
     test/core/util/one_corpus_entry_fuzzer.cc \

+ 2 - 1
bazel/grpc_build_system.bzl

@@ -110,7 +110,7 @@ def grpc_proto_library(name, srcs = [], deps = [], well_known_protos = False,
     generate_mocks = generate_mocks,
     generate_mocks = generate_mocks,
   )
   )
 
 
-def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = "moderate"):
+def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++", size = "medium", timeout = "moderate", tags = []):
   copts = []
   copts = []
   if language.upper() == "C":
   if language.upper() == "C":
     copts = if_not_windows(["-std=c99"])
     copts = if_not_windows(["-std=c99"])
@@ -140,6 +140,7 @@ def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data
           poller,
           poller,
           '$(location %s)' % name,
           '$(location %s)' % name,
         ] + args['args'],
         ] + args['args'],
+        tags = tags,
       )
       )
   else:
   else:
     native.cc_test(**args)
     native.cc_test(**args)

+ 1 - 0
build.yaml

@@ -2032,6 +2032,7 @@ targets:
   dict: test/core/end2end/fuzzers/api_fuzzer.dictionary
   dict: test/core/end2end/fuzzers/api_fuzzer.dictionary
   maxlen: 2048
   maxlen: 2048
 - name: arena_test
 - name: arena_test
+  cpu_cost: 10
   build: test
   build: test
   language: c
   language: c
   src:
   src:

+ 1 - 0
gRPC-Core.podspec

@@ -1216,6 +1216,7 @@ Pod::Spec.new do |s|
                       'test/core/end2end/tests/max_message_length.cc',
                       'test/core/end2end/tests/max_message_length.cc',
                       'test/core/end2end/tests/negative_deadline.cc',
                       'test/core/end2end/tests/negative_deadline.cc',
                       'test/core/end2end/tests/network_status_change.cc',
                       'test/core/end2end/tests/network_status_change.cc',
+                      'test/core/end2end/tests/no_error_on_hotpath.cc',
                       'test/core/end2end/tests/no_logging.cc',
                       'test/core/end2end/tests/no_logging.cc',
                       'test/core/end2end/tests/no_op.cc',
                       'test/core/end2end/tests/no_op.cc',
                       'test/core/end2end/tests/payload.cc',
                       'test/core/end2end/tests/payload.cc',

+ 2 - 0
grpc.gyp

@@ -2630,6 +2630,7 @@
         'test/core/end2end/tests/max_message_length.cc',
         'test/core/end2end/tests/max_message_length.cc',
         'test/core/end2end/tests/negative_deadline.cc',
         'test/core/end2end/tests/negative_deadline.cc',
         'test/core/end2end/tests/network_status_change.cc',
         'test/core/end2end/tests/network_status_change.cc',
+        'test/core/end2end/tests/no_error_on_hotpath.cc',
         'test/core/end2end/tests/no_logging.cc',
         'test/core/end2end/tests/no_logging.cc',
         'test/core/end2end/tests/no_op.cc',
         'test/core/end2end/tests/no_op.cc',
         'test/core/end2end/tests/payload.cc',
         'test/core/end2end/tests/payload.cc',
@@ -2720,6 +2721,7 @@
         'test/core/end2end/tests/max_message_length.cc',
         'test/core/end2end/tests/max_message_length.cc',
         'test/core/end2end/tests/negative_deadline.cc',
         'test/core/end2end/tests/negative_deadline.cc',
         'test/core/end2end/tests/network_status_change.cc',
         'test/core/end2end/tests/network_status_change.cc',
+        'test/core/end2end/tests/no_error_on_hotpath.cc',
         'test/core/end2end/tests/no_logging.cc',
         'test/core/end2end/tests/no_logging.cc',
         'test/core/end2end/tests/no_op.cc',
         'test/core/end2end/tests/no_op.cc',
         'test/core/end2end/tests/payload.cc',
         'test/core/end2end/tests/payload.cc',

+ 2 - 0
include/grpc/impl/codegen/grpc_types.h

@@ -336,6 +336,8 @@ typedef struct {
 /** If non-zero, client authority filter is disabled for the channel */
 /** If non-zero, client authority filter is disabled for the channel */
 #define GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER \
 #define GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER \
   "grpc.disable_client_authority_filter"
   "grpc.disable_client_authority_filter"
+/** If set to zero, disables use of http proxies. Enabled by default. */
+#define GRPC_ARG_ENABLE_HTTP_PROXY "grpc.enable_http_proxy"
 /** \} */
 /** \} */
 
 
 /** Result of a grpc call. If the caller satisfies the prerequisites of a
 /** Result of a grpc call. If the caller satisfies the prerequisites of a

+ 7 - 4
include/grpcpp/impl/codegen/call.h

@@ -573,10 +573,13 @@ class CallOpClientRecvStatus {
       binary_error_details =
       binary_error_details =
           grpc::string(iter->second.begin(), iter->second.length());
           grpc::string(iter->second.begin(), iter->second.length());
     }
     }
-    *recv_status_ = Status(static_cast<StatusCode>(status_code_),
-                           grpc::string(GRPC_SLICE_START_PTR(error_message_),
-                                        GRPC_SLICE_END_PTR(error_message_)),
-                           binary_error_details);
+    *recv_status_ =
+        Status(static_cast<StatusCode>(status_code_),
+               GRPC_SLICE_IS_EMPTY(error_message_)
+                   ? grpc::string()
+                   : grpc::string(GRPC_SLICE_START_PTR(error_message_),
+                                  GRPC_SLICE_END_PTR(error_message_)),
+               binary_error_details);
     client_context_->set_debug_error_string(
     client_context_->set_debug_error_string(
         debug_error_string_ != nullptr ? debug_error_string_ : "");
         debug_error_string_ != nullptr ? debug_error_string_ : "");
     g_core_codegen_interface->grpc_slice_unref(error_message_);
     g_core_codegen_interface->grpc_slice_unref(error_message_);

+ 26 - 3
include/grpcpp/impl/codegen/server_interface.h

@@ -49,12 +49,35 @@ class ServerInterface : public internal::CallHook {
  public:
  public:
   virtual ~ServerInterface() {}
   virtual ~ServerInterface() {}
 
 
-  /// Shutdown the server, blocking until all rpc processing finishes.
-  /// Forcefully terminate pending calls after \a deadline expires.
+  /// \a Shutdown does the following things:
+  ///
+  /// 1. Shutdown the server: deactivate all listening ports, mark it in
+  ///    "shutdown mode" so that further call Request's or incoming RPC matches
+  ///    are no longer allowed. Also return all Request'ed-but-not-yet-active
+  ///    calls as failed (!ok). This refers to calls that have been requested
+  ///    at the server by the server-side library or application code but that
+  ///    have not yet been matched to incoming RPCs from the client. Note that
+  ///    this would even include default calls added automatically by the gRPC
+  ///    C++ API without the user's input (e.g., "Unimplemented RPC method")
+  ///
+  /// 2. Block until all rpc method handlers invoked automatically by the sync
+  ///    API finish.
+  ///
+  /// 3. If all pending calls complete (and all their operations are
+  ///    retrieved by Next) before \a deadline expires, this finishes
+  ///    gracefully. Otherwise, forcefully cancel all pending calls associated
+  ///    with the server after \a deadline expires. In the case of the sync API,
+  ///    if the RPC function for a streaming call has already been started and
+  ///    takes a week to complete, the RPC function won't be forcefully
+  ///    terminated (since that would leave state corrupt and incomplete) and
+  ///    the method handler will just keep running (which will prevent the
+  ///    server from completing the "join" operation that it needs to do at
+  ///    shutdown time).
   ///
   ///
   /// All completion queue associated with the server (for example, for async
   /// All completion queue associated with the server (for example, for async
   /// serving) must be shutdown *after* this method has returned:
   /// serving) must be shutdown *after* this method has returned:
   /// See \a ServerBuilder::AddCompletionQueue for details.
   /// See \a ServerBuilder::AddCompletionQueue for details.
+  /// They must also be drained (by repeated Next) after being shutdown.
   ///
   ///
   /// \param deadline How long to wait until pending rpcs are forcefully
   /// \param deadline How long to wait until pending rpcs are forcefully
   /// terminated.
   /// terminated.
@@ -63,7 +86,7 @@ class ServerInterface : public internal::CallHook {
     ShutdownInternal(TimePoint<T>(deadline).raw_time());
     ShutdownInternal(TimePoint<T>(deadline).raw_time());
   }
   }
 
 
-  /// Shutdown the server, waiting for all rpc processing to finish.
+  /// Shutdown the server without a deadline and forced cancellation.
   ///
   ///
   /// All completion queue associated with the server (for example, for async
   /// All completion queue associated with the server (for example, for async
   /// serving) must be shutdown *after* this method has returned:
   /// serving) must be shutdown *after* this method has returned:

+ 2 - 0
include/grpcpp/server_builder.h

@@ -144,12 +144,14 @@ class ServerBuilder {
   // Fine control knobs
   // Fine control knobs
 
 
   /// Set max receive message size in bytes.
   /// Set max receive message size in bytes.
+  /// The default is GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH.
   ServerBuilder& SetMaxReceiveMessageSize(int max_receive_message_size) {
   ServerBuilder& SetMaxReceiveMessageSize(int max_receive_message_size) {
     max_receive_message_size_ = max_receive_message_size;
     max_receive_message_size_ = max_receive_message_size;
     return *this;
     return *this;
   }
   }
 
 
   /// Set max send message size in bytes.
   /// Set max send message size in bytes.
+  /// The default is GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH.
   ServerBuilder& SetMaxSendMessageSize(int max_send_message_size) {
   ServerBuilder& SetMaxSendMessageSize(int max_send_message_size) {
     max_send_message_size_ = max_send_message_size;
     max_send_message_size_ = max_send_message_size;
     return *this;
     return *this;

+ 2 - 1
src/compiler/csharp_generator.cc

@@ -202,7 +202,8 @@ std::string GetCSharpMethodType(MethodType method_type) {
 std::string GetServiceNameFieldName() { return "__ServiceName"; }
 std::string GetServiceNameFieldName() { return "__ServiceName"; }
 
 
 std::string GetMarshallerFieldName(const Descriptor* message) {
 std::string GetMarshallerFieldName(const Descriptor* message) {
-  return "__Marshaller_" + message->name();
+  return "__Marshaller_" +
+         grpc_generator::StringReplace(message->full_name(), ".", "_", true);
 }
 }
 
 
 std::string GetMethodFieldName(const MethodDescriptor* method) {
 std::string GetMethodFieldName(const MethodDescriptor* method) {

+ 63 - 36
src/core/ext/filters/client_channel/client_channel.cc

@@ -1723,6 +1723,29 @@ static void recv_message_ready(void* arg, grpc_error* error) {
 // recv_trailing_metadata handling
 // recv_trailing_metadata handling
 //
 //
 
 
+// Sets *status and *server_pushback_md based on batch_data and error.
+static void get_call_status(subchannel_batch_data* batch_data,
+                            grpc_error* error, grpc_status_code* status,
+                            grpc_mdelem** server_pushback_md) {
+  grpc_call_element* elem = batch_data->elem;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  if (error != GRPC_ERROR_NONE) {
+    grpc_error_get_status(error, calld->deadline, status, nullptr, nullptr,
+                          nullptr);
+  } else {
+    grpc_metadata_batch* md_batch =
+        batch_data->batch.payload->recv_trailing_metadata
+            .recv_trailing_metadata;
+    GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
+    *status =
+        grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md);
+    if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
+      *server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
 // Adds recv_trailing_metadata_ready closure to closures.
 // Adds recv_trailing_metadata_ready closure to closures.
 static void add_closure_for_recv_trailing_metadata_ready(
 static void add_closure_for_recv_trailing_metadata_ready(
     grpc_call_element* elem, subchannel_batch_data* batch_data,
     grpc_call_element* elem, subchannel_batch_data* batch_data,
@@ -1837,6 +1860,34 @@ static void add_closures_to_fail_unstarted_pending_batches(
   GRPC_ERROR_UNREF(error);
   GRPC_ERROR_UNREF(error);
 }
 }
 
 
+// Runs necessary closures upon completion of a call attempt.
+static void run_closures_for_completed_call(subchannel_batch_data* batch_data,
+                                            grpc_error* error) {
+  grpc_call_element* elem = batch_data->elem;
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  subchannel_call_retry_state* retry_state =
+      static_cast<subchannel_call_retry_state*>(
+          grpc_connected_subchannel_call_get_parent_data(
+              batch_data->subchannel_call));
+  // Construct list of closures to execute.
+  grpc_core::CallCombinerClosureList closures;
+  // First, add closure for recv_trailing_metadata_ready.
+  add_closure_for_recv_trailing_metadata_ready(
+      elem, batch_data, GRPC_ERROR_REF(error), &closures);
+  // If there are deferred recv_initial_metadata_ready or recv_message_ready
+  // callbacks, add them to closures.
+  add_closures_for_deferred_recv_callbacks(batch_data, retry_state, &closures);
+  // Add closures to fail any pending batches that have not yet been started.
+  add_closures_to_fail_unstarted_pending_batches(
+      elem, retry_state, GRPC_ERROR_REF(error), &closures);
+  // Don't need batch_data anymore.
+  batch_data_unref(batch_data);
+  // Schedule all of the closures identified above.
+  // Note: This will release the call combiner.
+  closures.RunClosures(calld->call_combiner);
+  GRPC_ERROR_UNREF(error);
+}
+
 // Intercepts recv_trailing_metadata_ready callback for retries.
 // Intercepts recv_trailing_metadata_ready callback for retries.
 // Commits the call and returns the trailing metadata up the stack.
 // Commits the call and returns the trailing metadata up the stack.
 static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
 static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
@@ -1857,20 +1908,8 @@ static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
   // Get the call's status and check for server pushback metadata.
   // Get the call's status and check for server pushback metadata.
   grpc_status_code status = GRPC_STATUS_OK;
   grpc_status_code status = GRPC_STATUS_OK;
   grpc_mdelem* server_pushback_md = nullptr;
   grpc_mdelem* server_pushback_md = nullptr;
-  if (error != GRPC_ERROR_NONE) {
-    grpc_error_get_status(error, calld->deadline, &status, nullptr, nullptr,
-                          nullptr);
-  } else {
-    grpc_metadata_batch* md_batch =
-        batch_data->batch.payload->recv_trailing_metadata
-            .recv_trailing_metadata;
-    GPR_ASSERT(md_batch->idx.named.grpc_status != nullptr);
-    status =
-        grpc_get_status_code_from_metadata(md_batch->idx.named.grpc_status->md);
-    if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
-      server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
-    }
-  }
+  get_call_status(batch_data, GRPC_ERROR_REF(error), &status,
+                  &server_pushback_md);
   if (grpc_client_channel_trace.enabled()) {
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_INFO, "chand=%p calld=%p: call finished, status=%s", chand,
     gpr_log(GPR_INFO, "chand=%p calld=%p: call finished, status=%s", chand,
             calld, grpc_status_code_to_string(status));
             calld, grpc_status_code_to_string(status));
@@ -1892,36 +1931,24 @@ static void recv_trailing_metadata_ready(void* arg, grpc_error* error) {
   }
   }
   // Not retrying, so commit the call.
   // Not retrying, so commit the call.
   retry_commit(elem, retry_state);
   retry_commit(elem, retry_state);
-  // Construct list of closures to execute.
-  grpc_core::CallCombinerClosureList closures;
-  // First, add closure for recv_trailing_metadata_ready.
-  add_closure_for_recv_trailing_metadata_ready(
-      elem, batch_data, GRPC_ERROR_REF(error), &closures);
-  // If there are deferred recv_initial_metadata_ready or recv_message_ready
-  // callbacks, add them to closures.
-  add_closures_for_deferred_recv_callbacks(batch_data, retry_state, &closures);
-  // Add closures to fail any pending batches that have not yet been started.
-  add_closures_to_fail_unstarted_pending_batches(
-      elem, retry_state, GRPC_ERROR_REF(error), &closures);
-  // Don't need batch_data anymore.
-  batch_data_unref(batch_data);
-  // Schedule all of the closures identified above.
-  // Note: This will release the call combiner.
-  closures.RunClosures(calld->call_combiner);
+  // Run any necessary closures.
+  run_closures_for_completed_call(batch_data, GRPC_ERROR_REF(error));
 }
 }
 
 
 //
 //
 // on_complete callback handling
 // on_complete callback handling
 //
 //
 
 
-// For any pending batch completed in batch_data, adds the necessary
-// completion closures to closures.
+// Adds the on_complete closure for the pending batch completed in
+// batch_data to closures.
 static void add_closure_for_completed_pending_batch(
 static void add_closure_for_completed_pending_batch(
     grpc_call_element* elem, subchannel_batch_data* batch_data,
     grpc_call_element* elem, subchannel_batch_data* batch_data,
     subchannel_call_retry_state* retry_state, grpc_error* error,
     subchannel_call_retry_state* retry_state, grpc_error* error,
     grpc_core::CallCombinerClosureList* closures) {
     grpc_core::CallCombinerClosureList* closures) {
   pending_batch* pending = pending_batch_find(
   pending_batch* pending = pending_batch_find(
       elem, "completed", [batch_data](grpc_transport_stream_op_batch* batch) {
       elem, "completed", [batch_data](grpc_transport_stream_op_batch* batch) {
+        // Match the pending batch with the same set of send ops as the
+        // subchannel batch we've just completed.
         return batch->on_complete != nullptr &&
         return batch->on_complete != nullptr &&
                batch_data->batch.send_initial_metadata ==
                batch_data->batch.send_initial_metadata ==
                    batch->send_initial_metadata &&
                    batch->send_initial_metadata &&
@@ -2023,8 +2050,8 @@ static void on_complete(void* arg, grpc_error* error) {
     // Add closure for the completed pending batch, if any.
     // Add closure for the completed pending batch, if any.
     add_closure_for_completed_pending_batch(elem, batch_data, retry_state,
     add_closure_for_completed_pending_batch(elem, batch_data, retry_state,
                                             GRPC_ERROR_REF(error), &closures);
                                             GRPC_ERROR_REF(error), &closures);
-    // If needed, add a callback to start_retriable_subchannel_batches() to
-    // start any replay or pending send ops on the subchannel call.
+    // If needed, add a callback to start any replay or pending send ops on
+    // the subchannel call.
     if (!retry_state->completed_recv_trailing_metadata) {
     if (!retry_state->completed_recv_trailing_metadata) {
       add_closures_for_replay_or_pending_send_ops(elem, batch_data, retry_state,
       add_closures_for_replay_or_pending_send_ops(elem, batch_data, retry_state,
                                                   &closures);
                                                   &closures);
@@ -2033,7 +2060,7 @@ static void on_complete(void* arg, grpc_error* error) {
   // Track number of pending subchannel send batches and determine if this
   // Track number of pending subchannel send batches and determine if this
   // was the last one.
   // was the last one.
   --calld->num_pending_retriable_subchannel_send_batches;
   --calld->num_pending_retriable_subchannel_send_batches;
-  const bool last_callback_complete =
+  const bool last_send_batch_complete =
       calld->num_pending_retriable_subchannel_send_batches == 0;
       calld->num_pending_retriable_subchannel_send_batches == 0;
   // Don't need batch_data anymore.
   // Don't need batch_data anymore.
   batch_data_unref(batch_data);
   batch_data_unref(batch_data);
@@ -2041,7 +2068,7 @@ static void on_complete(void* arg, grpc_error* error) {
   // Note: This yeilds the call combiner.
   // Note: This yeilds the call combiner.
   closures.RunClosures(calld->call_combiner);
   closures.RunClosures(calld->call_combiner);
   // If this was the last subchannel send batch, unref the call stack.
   // If this was the last subchannel send batch, unref the call stack.
-  if (last_callback_complete) {
+  if (last_send_batch_complete) {
     GRPC_CALL_STACK_UNREF(calld->owning_call, "subchannel_send_batches");
     GRPC_CALL_STACK_UNREF(calld->owning_call, "subchannel_send_batches");
   }
   }
 }
 }

+ 13 - 0
src/core/ext/filters/client_channel/http_proxy.cc

@@ -83,11 +83,24 @@ done:
   return proxy_name;
   return proxy_name;
 }
 }
 
 
+/**
+ * Checks the value of GRPC_ARG_ENABLE_HTTP_PROXY to determine if http_proxy
+ * should be used.
+ */
+bool http_proxy_enabled(const grpc_channel_args* args) {
+  const grpc_arg* arg =
+      grpc_channel_args_find(args, GRPC_ARG_ENABLE_HTTP_PROXY);
+  return grpc_channel_arg_get_bool(arg, true);
+}
+
 static bool proxy_mapper_map_name(grpc_proxy_mapper* mapper,
 static bool proxy_mapper_map_name(grpc_proxy_mapper* mapper,
                                   const char* server_uri,
                                   const char* server_uri,
                                   const grpc_channel_args* args,
                                   const grpc_channel_args* args,
                                   char** name_to_resolve,
                                   char** name_to_resolve,
                                   grpc_channel_args** new_args) {
                                   grpc_channel_args** new_args) {
+  if (!http_proxy_enabled(args)) {
+    return false;
+  }
   char* user_cred = nullptr;
   char* user_cred = nullptr;
   *name_to_resolve = get_http_proxy_server(&user_cred);
   *name_to_resolve = get_http_proxy_server(&user_cred);
   if (*name_to_resolve == nullptr) return false;
   if (*name_to_resolve == nullptr) return false;

+ 29 - 34
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc

@@ -21,6 +21,7 @@
 #if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER)
 #if GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER)
 
 
 #include <ares.h>
 #include <ares.h>
+#include <string.h>
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
 
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h"
@@ -55,8 +56,8 @@ typedef struct fd_node {
   bool readable_registered;
   bool readable_registered;
   /** if the writable closure has been registered */
   /** if the writable closure has been registered */
   bool writable_registered;
   bool writable_registered;
-  /** if the fd is being shut down */
-  bool shutting_down;
+  /** if the fd has been shutdown yet from grpc iomgr perspective */
+  bool already_shutdown;
 } fd_node;
 } fd_node;
 
 
 struct grpc_ares_ev_driver {
 struct grpc_ares_ev_driver {
@@ -101,25 +102,20 @@ static void fd_node_destroy(fd_node* fdn) {
   gpr_log(GPR_DEBUG, "delete fd: %d", grpc_fd_wrapped_fd(fdn->fd));
   gpr_log(GPR_DEBUG, "delete fd: %d", grpc_fd_wrapped_fd(fdn->fd));
   GPR_ASSERT(!fdn->readable_registered);
   GPR_ASSERT(!fdn->readable_registered);
   GPR_ASSERT(!fdn->writable_registered);
   GPR_ASSERT(!fdn->writable_registered);
+  GPR_ASSERT(fdn->already_shutdown);
   gpr_mu_destroy(&fdn->mu);
   gpr_mu_destroy(&fdn->mu);
   /* c-ares library has closed the fd inside grpc_fd. This fd may be picked up
   /* c-ares library has closed the fd inside grpc_fd. This fd may be picked up
      immediately by another thread, and should not be closed by the following
      immediately by another thread, and should not be closed by the following
      grpc_fd_orphan. */
      grpc_fd_orphan. */
-  grpc_fd_orphan(fdn->fd, nullptr, nullptr, true /* already_closed */,
-                 "c-ares query finished");
+  int dummy_release_fd;
+  grpc_fd_orphan(fdn->fd, nullptr, &dummy_release_fd, "c-ares query finished");
   gpr_free(fdn);
   gpr_free(fdn);
 }
 }
 
 
-static void fd_node_shutdown(fd_node* fdn) {
-  gpr_mu_lock(&fdn->mu);
-  fdn->shutting_down = true;
-  if (!fdn->readable_registered && !fdn->writable_registered) {
-    gpr_mu_unlock(&fdn->mu);
-    fd_node_destroy(fdn);
-  } else {
-    grpc_fd_shutdown(
-        fdn->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING("c-ares fd shutdown"));
-    gpr_mu_unlock(&fdn->mu);
+static void fd_node_shutdown_locked(fd_node* fdn, const char* reason) {
+  if (!fdn->already_shutdown) {
+    fdn->already_shutdown = true;
+    grpc_fd_shutdown(fdn->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING(reason));
   }
   }
 }
 }
 
 
@@ -127,7 +123,10 @@ grpc_error* grpc_ares_ev_driver_create(grpc_ares_ev_driver** ev_driver,
                                        grpc_pollset_set* pollset_set) {
                                        grpc_pollset_set* pollset_set) {
   *ev_driver = static_cast<grpc_ares_ev_driver*>(
   *ev_driver = static_cast<grpc_ares_ev_driver*>(
       gpr_malloc(sizeof(grpc_ares_ev_driver)));
       gpr_malloc(sizeof(grpc_ares_ev_driver)));
-  int status = ares_init(&(*ev_driver)->channel);
+  ares_options opts;
+  memset(&opts, 0, sizeof(opts));
+  opts.flags |= ARES_FLAG_STAYOPEN;
+  int status = ares_init_options(&(*ev_driver)->channel, &opts, ARES_OPT_FLAGS);
   gpr_log(GPR_DEBUG, "grpc_ares_ev_driver_create");
   gpr_log(GPR_DEBUG, "grpc_ares_ev_driver_create");
   if (status != ARES_SUCCESS) {
   if (status != ARES_SUCCESS) {
     char* err_msg;
     char* err_msg;
@@ -164,8 +163,9 @@ void grpc_ares_ev_driver_shutdown(grpc_ares_ev_driver* ev_driver) {
   ev_driver->shutting_down = true;
   ev_driver->shutting_down = true;
   fd_node* fn = ev_driver->fds;
   fd_node* fn = ev_driver->fds;
   while (fn != nullptr) {
   while (fn != nullptr) {
-    grpc_fd_shutdown(fn->fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-                                 "grpc_ares_ev_driver_shutdown"));
+    gpr_mu_lock(&fn->mu);
+    fd_node_shutdown_locked(fn, "grpc_ares_ev_driver_shutdown");
+    gpr_mu_unlock(&fn->mu);
     fn = fn->next;
     fn = fn->next;
   }
   }
   gpr_mu_unlock(&ev_driver->mu);
   gpr_mu_unlock(&ev_driver->mu);
@@ -202,14 +202,7 @@ static void on_readable_cb(void* arg, grpc_error* error) {
   gpr_mu_lock(&fdn->mu);
   gpr_mu_lock(&fdn->mu);
   const int fd = grpc_fd_wrapped_fd(fdn->fd);
   const int fd = grpc_fd_wrapped_fd(fdn->fd);
   fdn->readable_registered = false;
   fdn->readable_registered = false;
-  if (fdn->shutting_down && !fdn->writable_registered) {
-    gpr_mu_unlock(&fdn->mu);
-    fd_node_destroy(fdn);
-    grpc_ares_ev_driver_unref(ev_driver);
-    return;
-  }
   gpr_mu_unlock(&fdn->mu);
   gpr_mu_unlock(&fdn->mu);
-
   gpr_log(GPR_DEBUG, "readable on %d", fd);
   gpr_log(GPR_DEBUG, "readable on %d", fd);
   if (error == GRPC_ERROR_NONE) {
   if (error == GRPC_ERROR_NONE) {
     do {
     do {
@@ -236,14 +229,7 @@ static void on_writable_cb(void* arg, grpc_error* error) {
   gpr_mu_lock(&fdn->mu);
   gpr_mu_lock(&fdn->mu);
   const int fd = grpc_fd_wrapped_fd(fdn->fd);
   const int fd = grpc_fd_wrapped_fd(fdn->fd);
   fdn->writable_registered = false;
   fdn->writable_registered = false;
-  if (fdn->shutting_down && !fdn->readable_registered) {
-    gpr_mu_unlock(&fdn->mu);
-    fd_node_destroy(fdn);
-    grpc_ares_ev_driver_unref(ev_driver);
-    return;
-  }
   gpr_mu_unlock(&fdn->mu);
   gpr_mu_unlock(&fdn->mu);
-
   gpr_log(GPR_DEBUG, "writable on %d", fd);
   gpr_log(GPR_DEBUG, "writable on %d", fd);
   if (error == GRPC_ERROR_NONE) {
   if (error == GRPC_ERROR_NONE) {
     ares_process_fd(ev_driver->channel, ARES_SOCKET_BAD, fd);
     ares_process_fd(ev_driver->channel, ARES_SOCKET_BAD, fd);
@@ -284,11 +270,11 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) {
           gpr_asprintf(&fd_name, "ares_ev_driver-%" PRIuPTR, i);
           gpr_asprintf(&fd_name, "ares_ev_driver-%" PRIuPTR, i);
           fdn = static_cast<fd_node*>(gpr_malloc(sizeof(fd_node)));
           fdn = static_cast<fd_node*>(gpr_malloc(sizeof(fd_node)));
           gpr_log(GPR_DEBUG, "new fd: %d", socks[i]);
           gpr_log(GPR_DEBUG, "new fd: %d", socks[i]);
-          fdn->fd = grpc_fd_create(socks[i], fd_name);
+          fdn->fd = grpc_fd_create(socks[i], fd_name, false);
           fdn->ev_driver = ev_driver;
           fdn->ev_driver = ev_driver;
           fdn->readable_registered = false;
           fdn->readable_registered = false;
           fdn->writable_registered = false;
           fdn->writable_registered = false;
-          fdn->shutting_down = false;
+          fdn->already_shutdown = false;
           gpr_mu_init(&fdn->mu);
           gpr_mu_init(&fdn->mu);
           GRPC_CLOSURE_INIT(&fdn->read_closure, on_readable_cb, fdn,
           GRPC_CLOSURE_INIT(&fdn->read_closure, on_readable_cb, fdn,
                             grpc_schedule_on_exec_ctx);
                             grpc_schedule_on_exec_ctx);
@@ -329,7 +315,16 @@ static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver) {
   while (ev_driver->fds != nullptr) {
   while (ev_driver->fds != nullptr) {
     fd_node* cur = ev_driver->fds;
     fd_node* cur = ev_driver->fds;
     ev_driver->fds = ev_driver->fds->next;
     ev_driver->fds = ev_driver->fds->next;
-    fd_node_shutdown(cur);
+    gpr_mu_lock(&cur->mu);
+    fd_node_shutdown_locked(cur, "c-ares fd shutdown");
+    if (!cur->readable_registered && !cur->writable_registered) {
+      gpr_mu_unlock(&cur->mu);
+      fd_node_destroy(cur);
+    } else {
+      cur->next = new_list;
+      new_list = cur;
+      gpr_mu_unlock(&cur->mu);
+    }
   }
   }
   ev_driver->fds = new_list;
   ev_driver->fds = new_list;
   // If the ev driver has no working fd, all the tasks are done.
   // If the ev driver has no working fd, all the tasks are done.

+ 2 - 3
src/core/ext/filters/deadline/deadline_filter.cc

@@ -293,11 +293,10 @@ static void client_start_transport_stream_op_batch(
 static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
 static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
   server_call_data* calld = static_cast<server_call_data*>(elem->call_data);
   server_call_data* calld = static_cast<server_call_data*>(elem->call_data);
-  // Get deadline from metadata and start the timer if needed.
   start_timer_if_needed(elem, calld->recv_initial_metadata->deadline);
   start_timer_if_needed(elem, calld->recv_initial_metadata->deadline);
   // Invoke the next callback.
   // Invoke the next callback.
-  calld->next_recv_initial_metadata_ready->cb(
-      calld->next_recv_initial_metadata_ready->cb_arg, error);
+  GRPC_CLOSURE_RUN(calld->next_recv_initial_metadata_ready,
+                   GRPC_ERROR_REF(error));
 }
 }
 
 
 // Method for starting a call op for server filter.
 // Method for starting a call op for server filter.

+ 1 - 3
src/core/ext/filters/load_reporting/server_load_reporting_filter.cc

@@ -82,9 +82,7 @@ static void on_initial_md_ready(void* user_data, grpc_error* err) {
   } else {
   } else {
     GRPC_ERROR_REF(err);
     GRPC_ERROR_REF(err);
   }
   }
-  calld->ops_recv_initial_metadata_ready->cb(
-      calld->ops_recv_initial_metadata_ready->cb_arg, err);
-  GRPC_ERROR_UNREF(err);
+  GRPC_CLOSURE_RUN(calld->ops_recv_initial_metadata_ready, err);
 }
 }
 
 
 /* Constructor for call_data */
 /* Constructor for call_data */

+ 1 - 1
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc

@@ -50,7 +50,7 @@ grpc_channel* grpc_insecure_channel_create_from_fd(
   GPR_ASSERT(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
   GPR_ASSERT(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
 
 
   grpc_endpoint* client = grpc_tcp_client_create_from_fd(
   grpc_endpoint* client = grpc_tcp_client_create_from_fd(
-      grpc_fd_create(fd, "client"), args, "fd-client");
+      grpc_fd_create(fd, "client", false), args, "fd-client");
 
 
   grpc_transport* transport =
   grpc_transport* transport =
       grpc_create_chttp2_transport(final_args, client, true);
       grpc_create_chttp2_transport(final_args, client, true);

+ 3 - 2
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc

@@ -43,8 +43,9 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server* server,
   char* name;
   char* name;
   gpr_asprintf(&name, "fd:%d", fd);
   gpr_asprintf(&name, "fd:%d", fd);
 
 
-  grpc_endpoint* server_endpoint = grpc_tcp_create(
-      grpc_fd_create(fd, name), grpc_server_get_channel_args(server), name);
+  grpc_endpoint* server_endpoint =
+      grpc_tcp_create(grpc_fd_create(fd, name, false),
+                      grpc_server_get_channel_args(server), name);
 
 
   gpr_free(name);
   gpr_free(name);
 
 

+ 2 - 0
src/core/lib/gprpp/inlined_vector.h

@@ -99,6 +99,8 @@ class InlinedVector {
   void push_back(T&& value) { emplace_back(std::move(value)); }
   void push_back(T&& value) { emplace_back(std::move(value)); }
 
 
   size_t size() const { return size_; }
   size_t size() const { return size_; }
+  bool empty() const { return size_ == 0; }
+
   size_t capacity() const { return capacity_; }
   size_t capacity() const { return capacity_; }
 
 
   void clear() {
   void clear() {

+ 12 - 12
src/core/lib/iomgr/call_combiner.h

@@ -137,24 +137,24 @@ class CallCombinerClosureList {
   // yielding the call combiner.  If the list is empty, then the call
   // yielding the call combiner.  If the list is empty, then the call
   // combiner will be yielded immediately.
   // combiner will be yielded immediately.
   void RunClosures(grpc_call_combiner* call_combiner) {
   void RunClosures(grpc_call_combiner* call_combiner) {
+    if (closures_.empty()) {
+      GRPC_CALL_COMBINER_STOP(call_combiner, "no closures to schedule");
+      return;
+    }
     for (size_t i = 1; i < closures_.size(); ++i) {
     for (size_t i = 1; i < closures_.size(); ++i) {
       auto& closure = closures_[i];
       auto& closure = closures_[i];
       GRPC_CALL_COMBINER_START(call_combiner, closure.closure, closure.error,
       GRPC_CALL_COMBINER_START(call_combiner, closure.closure, closure.error,
                                closure.reason);
                                closure.reason);
     }
     }
-    if (closures_.size() > 0) {
-      if (grpc_call_combiner_trace.enabled()) {
-        gpr_log(GPR_INFO,
-                "CallCombinerClosureList executing closure while already "
-                "holding call_combiner %p: closure=%p error=%s reason=%s",
-                call_combiner, closures_[0].closure,
-                grpc_error_string(closures_[0].error), closures_[0].reason);
-      }
-      // This will release the call combiner.
-      GRPC_CLOSURE_SCHED(closures_[0].closure, closures_[0].error);
-    } else {
-      GRPC_CALL_COMBINER_STOP(call_combiner, "no closures to schedule");
+    if (grpc_call_combiner_trace.enabled()) {
+      gpr_log(GPR_INFO,
+              "CallCombinerClosureList executing closure while already "
+              "holding call_combiner %p: closure=%p error=%s reason=%s",
+              call_combiner, closures_[0].closure,
+              grpc_error_string(closures_[0].error), closures_[0].reason);
     }
     }
+    // This will release the call combiner.
+    GRPC_CLOSURE_SCHED(closures_[0].closure, closures_[0].error);
     closures_.clear();
     closures_.clear();
   }
   }
 
 

+ 3 - 1
src/core/lib/iomgr/cfstream_handle.cc

@@ -116,7 +116,9 @@ CFStreamHandle::CFStreamHandle(CFReadStreamRef read_stream,
   open_event_.InitEvent();
   open_event_.InitEvent();
   read_event_.InitEvent();
   read_event_.InitEvent();
   write_event_.InitEvent();
   write_event_.InitEvent();
-  CFStreamClientContext ctx = {0, static_cast<void*>(this), nil, nil, nil};
+  CFStreamClientContext ctx = {0, static_cast<void*>(this),
+                               CFStreamHandle::Retain, CFStreamHandle::Release,
+                               nil};
   CFReadStreamSetClient(
   CFReadStreamSetClient(
       read_stream,
       read_stream,
       kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable |
       kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable |

+ 2 - 2
src/core/lib/iomgr/endpoint_pair_posix.cc

@@ -59,11 +59,11 @@ grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char* name,
   grpc_core::ExecCtx exec_ctx;
   grpc_core::ExecCtx exec_ctx;
 
 
   gpr_asprintf(&final_name, "%s:client", name);
   gpr_asprintf(&final_name, "%s:client", name);
-  p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), args,
+  p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name, false), args,
                              "socketpair-server");
                              "socketpair-server");
   gpr_free(final_name);
   gpr_free(final_name);
   gpr_asprintf(&final_name, "%s:server", name);
   gpr_asprintf(&final_name, "%s:server", name);
-  p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), args,
+  p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name, false), args,
                              "socketpair-client");
                              "socketpair-client");
   gpr_free(final_name);
   gpr_free(final_name);
 
 

+ 12 - 0
src/core/lib/iomgr/error.cc

@@ -312,6 +312,12 @@ static void internal_add_error(grpc_error** err, grpc_error* new_err) {
 // It is very common to include and extra int and string in an error
 // It is very common to include and extra int and string in an error
 #define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
 #define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
 
 
+static bool g_error_creation_allowed = true;
+
+void grpc_disable_error_creation() { g_error_creation_allowed = false; }
+
+void grpc_enable_error_creation() { g_error_creation_allowed = true; }
+
 grpc_error* grpc_error_create(const char* file, int line, grpc_slice desc,
 grpc_error* grpc_error_create(const char* file, int line, grpc_slice desc,
                               grpc_error** referencing,
                               grpc_error** referencing,
                               size_t num_referencing) {
                               size_t num_referencing) {
@@ -326,6 +332,12 @@ grpc_error* grpc_error_create(const char* file, int line, grpc_slice desc,
     return GRPC_ERROR_OOM;
     return GRPC_ERROR_OOM;
   }
   }
 #ifndef NDEBUG
 #ifndef NDEBUG
+  if (!g_error_creation_allowed) {
+    gpr_log(GPR_ERROR,
+            "Error creation occurred when error creation was disabled [%s:%d]",
+            file, line);
+    abort();
+  }
   if (grpc_trace_error_refcount.enabled()) {
   if (grpc_trace_error_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
     gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
   }
   }

+ 5 - 0
src/core/lib/iomgr/error.h

@@ -123,6 +123,11 @@ typedef enum {
 #define GRPC_ERROR_OOM ((grpc_error*)2)
 #define GRPC_ERROR_OOM ((grpc_error*)2)
 #define GRPC_ERROR_CANCELLED ((grpc_error*)4)
 #define GRPC_ERROR_CANCELLED ((grpc_error*)4)
 
 
+// debug only toggles that allow for a sanity to check that ensures we will
+// never create any errors in the per-RPC hotpath.
+void grpc_disable_error_creation();
+void grpc_enable_error_creation();
+
 const char* grpc_error_string(grpc_error* error);
 const char* grpc_error_string(grpc_error* error);
 
 
 /// Create an error - but use GRPC_ERROR_CREATE instead
 /// Create an error - but use GRPC_ERROR_CREATE instead

+ 36 - 9
src/core/lib/iomgr/ev_epoll1_linux.cc

@@ -136,6 +136,7 @@ struct grpc_fd {
 
 
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
+  grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure;
 
 
   struct grpc_fd* freelist_next;
   struct grpc_fd* freelist_next;
 
 
@@ -272,7 +273,7 @@ static void fd_global_shutdown(void) {
   gpr_mu_destroy(&fd_freelist_mu);
   gpr_mu_destroy(&fd_freelist_mu);
 }
 }
 
 
-static grpc_fd* fd_create(int fd, const char* name) {
+static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
   grpc_fd* new_fd = nullptr;
   grpc_fd* new_fd = nullptr;
 
 
   gpr_mu_lock(&fd_freelist_mu);
   gpr_mu_lock(&fd_freelist_mu);
@@ -286,11 +287,12 @@ static grpc_fd* fd_create(int fd, const char* name) {
     new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
     new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
     new_fd->read_closure.Init();
     new_fd->read_closure.Init();
     new_fd->write_closure.Init();
     new_fd->write_closure.Init();
+    new_fd->error_closure.Init();
   }
   }
-
   new_fd->fd = fd;
   new_fd->fd = fd;
   new_fd->read_closure->InitEvent();
   new_fd->read_closure->InitEvent();
   new_fd->write_closure->InitEvent();
   new_fd->write_closure->InitEvent();
+  new_fd->error_closure->InitEvent();
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
 
   new_fd->freelist_next = nullptr;
   new_fd->freelist_next = nullptr;
@@ -307,7 +309,13 @@ static grpc_fd* fd_create(int fd, const char* name) {
 
 
   struct epoll_event ev;
   struct epoll_event ev;
   ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
   ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
-  ev.data.ptr = new_fd;
+  /* Use the least significant bit of ev.data.ptr to store track_err. We expect
+   * the addresses to be word aligned. We need to store track_err to avoid
+   * synchronization issues when accessing it after receiving an event.
+   * Accessing fd would be a data race there because the fd might have been
+   * returned to the free list at that point. */
+  ev.data.ptr = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(new_fd) |
+                                        (track_err ? 1 : 0));
   if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_ADD, fd, &ev) != 0) {
   if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_ADD, fd, &ev) != 0) {
     gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno));
     gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno));
   }
   }
@@ -327,6 +335,7 @@ static void fd_shutdown_internal(grpc_fd* fd, grpc_error* why,
       shutdown(fd->fd, SHUT_RDWR);
       shutdown(fd->fd, SHUT_RDWR);
     }
     }
     fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
     fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
+    fd->error_closure->SetShutdown(GRPC_ERROR_REF(why));
   }
   }
   GRPC_ERROR_UNREF(why);
   GRPC_ERROR_UNREF(why);
 }
 }
@@ -337,7 +346,7 @@ static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
 }
 }
 
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                      bool already_closed, const char* reason) {
+                      const char* reason) {
   grpc_error* error = GRPC_ERROR_NONE;
   grpc_error* error = GRPC_ERROR_NONE;
   bool is_release_fd = (release_fd != nullptr);
   bool is_release_fd = (release_fd != nullptr);
 
 
@@ -350,7 +359,7 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
      descriptor fd->fd (but we still own the grpc_fd structure). */
      descriptor fd->fd (but we still own the grpc_fd structure). */
   if (is_release_fd) {
   if (is_release_fd) {
     *release_fd = fd->fd;
     *release_fd = fd->fd;
-  } else if (!already_closed) {
+  } else {
     close(fd->fd);
     close(fd->fd);
   }
   }
 
 
@@ -359,6 +368,7 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
   grpc_iomgr_unregister_object(&fd->iomgr_object);
   grpc_iomgr_unregister_object(&fd->iomgr_object);
   fd->read_closure->DestroyEvent();
   fd->read_closure->DestroyEvent();
   fd->write_closure->DestroyEvent();
   fd->write_closure->DestroyEvent();
+  fd->error_closure->DestroyEvent();
 
 
   gpr_mu_lock(&fd_freelist_mu);
   gpr_mu_lock(&fd_freelist_mu);
   fd->freelist_next = fd_freelist;
   fd->freelist_next = fd_freelist;
@@ -383,6 +393,10 @@ static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   fd->write_closure->NotifyOn(closure);
   fd->write_closure->NotifyOn(closure);
 }
 }
 
 
+static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  fd->error_closure->NotifyOn(closure);
+}
+
 static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
 static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
   fd->read_closure->SetReady();
   fd->read_closure->SetReady();
   /* Use release store to match with acquire load in fd_get_read_notifier */
   /* Use release store to match with acquire load in fd_get_read_notifier */
@@ -391,6 +405,8 @@ static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
 
 
 static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
 static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
 
 
+static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
+
 /*******************************************************************************
 /*******************************************************************************
  * Pollset Definitions
  * Pollset Definitions
  */
  */
@@ -611,16 +627,25 @@ static grpc_error* process_epoll_events(grpc_pollset* pollset) {
       append_error(&error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
       append_error(&error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
                    err_desc);
                    err_desc);
     } else {
     } else {
-      grpc_fd* fd = static_cast<grpc_fd*>(data_ptr);
-      bool cancel = (ev->events & (EPOLLERR | EPOLLHUP)) != 0;
+      grpc_fd* fd = reinterpret_cast<grpc_fd*>(
+          reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1));
+      bool track_err =
+          reinterpret_cast<intptr_t>(data_ptr) & static_cast<intptr_t>(1);
+      bool cancel = (ev->events & EPOLLHUP) != 0;
+      bool error = (ev->events & EPOLLERR) != 0;
       bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0;
       bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0;
       bool write_ev = (ev->events & EPOLLOUT) != 0;
       bool write_ev = (ev->events & EPOLLOUT) != 0;
+      bool err_fallback = error && !track_err;
+
+      if (error && !err_fallback) {
+        fd_has_errors(fd);
+      }
 
 
-      if (read_ev || cancel) {
+      if (read_ev || cancel || err_fallback) {
         fd_become_readable(fd, pollset);
         fd_become_readable(fd, pollset);
       }
       }
 
 
-      if (write_ev || cancel) {
+      if (write_ev || cancel || err_fallback) {
         fd_become_writable(fd);
         fd_become_writable(fd);
       }
       }
     }
     }
@@ -1183,6 +1208,7 @@ static void shutdown_engine(void) {
 
 
 static const grpc_event_engine_vtable vtable = {
 static const grpc_event_engine_vtable vtable = {
     sizeof(grpc_pollset),
     sizeof(grpc_pollset),
+    true,
 
 
     fd_create,
     fd_create,
     fd_wrapped_fd,
     fd_wrapped_fd,
@@ -1190,6 +1216,7 @@ static const grpc_event_engine_vtable vtable = {
     fd_shutdown,
     fd_shutdown,
     fd_notify_on_read,
     fd_notify_on_read,
     fd_notify_on_write,
     fd_notify_on_write,
+    fd_notify_on_error,
     fd_is_shutdown,
     fd_is_shutdown,
     fd_get_read_notifier_pollset,
     fd_get_read_notifier_pollset,
 
 

+ 45 - 10
src/core/lib/iomgr/ev_epollex_linux.cc

@@ -175,6 +175,7 @@ struct grpc_fd {
 
 
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
+  grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure;
 
 
   struct grpc_fd* freelist_next;
   struct grpc_fd* freelist_next;
   grpc_closure* on_done_closure;
   grpc_closure* on_done_closure;
@@ -184,6 +185,9 @@ struct grpc_fd {
   gpr_atm read_notifier_pollset;
   gpr_atm read_notifier_pollset;
 
 
   grpc_iomgr_object iomgr_object;
   grpc_iomgr_object iomgr_object;
+
+  /* Do we need to track EPOLLERR events separately? */
+  bool track_err;
 };
 };
 
 
 static void fd_global_init(void);
 static void fd_global_init(void);
@@ -309,6 +313,7 @@ static void fd_destroy(void* arg, grpc_error* error) {
 
 
   fd->read_closure->DestroyEvent();
   fd->read_closure->DestroyEvent();
   fd->write_closure->DestroyEvent();
   fd->write_closure->DestroyEvent();
+  fd->error_closure->DestroyEvent();
 
 
   gpr_mu_unlock(&fd_freelist_mu);
   gpr_mu_unlock(&fd_freelist_mu);
 }
 }
@@ -348,7 +353,7 @@ static void fd_global_shutdown(void) {
   gpr_mu_destroy(&fd_freelist_mu);
   gpr_mu_destroy(&fd_freelist_mu);
 }
 }
 
 
-static grpc_fd* fd_create(int fd, const char* name) {
+static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
   grpc_fd* new_fd = nullptr;
   grpc_fd* new_fd = nullptr;
 
 
   gpr_mu_lock(&fd_freelist_mu);
   gpr_mu_lock(&fd_freelist_mu);
@@ -362,6 +367,7 @@ static grpc_fd* fd_create(int fd, const char* name) {
     new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
     new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
     new_fd->read_closure.Init();
     new_fd->read_closure.Init();
     new_fd->write_closure.Init();
     new_fd->write_closure.Init();
+    new_fd->error_closure.Init();
   }
   }
 
 
   gpr_mu_init(&new_fd->pollable_mu);
   gpr_mu_init(&new_fd->pollable_mu);
@@ -369,9 +375,11 @@ static grpc_fd* fd_create(int fd, const char* name) {
   new_fd->pollable_obj = nullptr;
   new_fd->pollable_obj = nullptr;
   gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
   gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
   new_fd->fd = fd;
   new_fd->fd = fd;
+  new_fd->track_err = track_err;
   new_fd->salt = gpr_atm_no_barrier_fetch_add(&g_fd_salt, 1);
   new_fd->salt = gpr_atm_no_barrier_fetch_add(&g_fd_salt, 1);
   new_fd->read_closure->InitEvent();
   new_fd->read_closure->InitEvent();
   new_fd->write_closure->InitEvent();
   new_fd->write_closure->InitEvent();
+  new_fd->error_closure->InitEvent();
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
 
   new_fd->freelist_next = nullptr;
   new_fd->freelist_next = nullptr;
@@ -395,8 +403,8 @@ static int fd_wrapped_fd(grpc_fd* fd) {
 }
 }
 
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                      bool already_closed, const char* reason) {
-  bool is_fd_closed = already_closed;
+                      const char* reason) {
+  bool is_fd_closed = false;
 
 
   gpr_mu_lock(&fd->orphan_mu);
   gpr_mu_lock(&fd->orphan_mu);
 
 
@@ -406,7 +414,7 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
      descriptor fd->fd (but we still own the grpc_fd structure). */
      descriptor fd->fd (but we still own the grpc_fd structure). */
   if (release_fd != nullptr) {
   if (release_fd != nullptr) {
     *release_fd = fd->fd;
     *release_fd = fd->fd;
-  } else if (!is_fd_closed) {
+  } else {
     close(fd->fd);
     close(fd->fd);
     is_fd_closed = true;
     is_fd_closed = true;
   }
   }
@@ -438,8 +446,14 @@ static bool fd_is_shutdown(grpc_fd* fd) {
 /* Might be called multiple times */
 /* Might be called multiple times */
 static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
 static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
   if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
   if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
-    shutdown(fd->fd, SHUT_RDWR);
+    if (shutdown(fd->fd, SHUT_RDWR)) {
+      if (errno != ENOTCONN) {
+        gpr_log(GPR_ERROR, "Error shutting down fd %d. errno: %d",
+                grpc_fd_wrapped_fd(fd), errno);
+      }
+    }
     fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
     fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
+    fd->error_closure->SetShutdown(GRPC_ERROR_REF(why));
   }
   }
   GRPC_ERROR_UNREF(why);
   GRPC_ERROR_UNREF(why);
 }
 }
@@ -452,6 +466,10 @@ static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   fd->write_closure->NotifyOn(closure);
   fd->write_closure->NotifyOn(closure);
 }
 }
 
 
+static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  fd->error_closure->NotifyOn(closure);
+}
+
 /*******************************************************************************
 /*******************************************************************************
  * Pollable Definitions
  * Pollable Definitions
  */
  */
@@ -579,7 +597,12 @@ static grpc_error* pollable_add_fd(pollable* p, grpc_fd* fd) {
   struct epoll_event ev_fd;
   struct epoll_event ev_fd;
   ev_fd.events =
   ev_fd.events =
       static_cast<uint32_t>(EPOLLET | EPOLLIN | EPOLLOUT | EPOLLEXCLUSIVE);
       static_cast<uint32_t>(EPOLLET | EPOLLIN | EPOLLOUT | EPOLLEXCLUSIVE);
-  ev_fd.data.ptr = fd;
+  /* Use the second least significant bit of ev_fd.data.ptr to store track_err
+   * to avoid synchronization issues when accessing it after receiving an event.
+   * Accessing fd would be a data race there because the fd might have been
+   * returned to the free list at that point. */
+  ev_fd.data.ptr = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(fd) |
+                                           (fd->track_err ? 2 : 0));
   GRPC_STATS_INC_SYSCALL_EPOLL_CTL();
   GRPC_STATS_INC_SYSCALL_EPOLL_CTL();
   if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd->fd, &ev_fd) != 0) {
   if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd->fd, &ev_fd) != 0) {
     switch (errno) {
     switch (errno) {
@@ -780,6 +803,8 @@ static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
 
 
 static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
 static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
 
 
+static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
+
 static grpc_error* fd_get_or_become_pollable(grpc_fd* fd, pollable** p) {
 static grpc_error* fd_get_or_become_pollable(grpc_fd* fd, pollable** p) {
   gpr_mu_lock(&fd->pollable_mu);
   gpr_mu_lock(&fd->pollable_mu);
   grpc_error* error = GRPC_ERROR_NONE;
   grpc_error* error = GRPC_ERROR_NONE;
@@ -848,20 +873,28 @@ static grpc_error* pollable_process_events(grpc_pollset* pollset,
                                          (intptr_t)data_ptr)),
                                          (intptr_t)data_ptr)),
                    err_desc);
                    err_desc);
     } else {
     } else {
-      grpc_fd* fd = static_cast<grpc_fd*>(data_ptr);
-      bool cancel = (ev->events & (EPOLLERR | EPOLLHUP)) != 0;
+      grpc_fd* fd =
+          reinterpret_cast<grpc_fd*>(reinterpret_cast<intptr_t>(data_ptr) & ~2);
+      bool track_err = reinterpret_cast<intptr_t>(data_ptr) & 2;
+      bool cancel = (ev->events & EPOLLHUP) != 0;
+      bool error = (ev->events & EPOLLERR) != 0;
       bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0;
       bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0;
       bool write_ev = (ev->events & EPOLLOUT) != 0;
       bool write_ev = (ev->events & EPOLLOUT) != 0;
+      bool err_fallback = error && !track_err;
+
       if (grpc_polling_trace.enabled()) {
       if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_INFO,
         gpr_log(GPR_INFO,
                 "PS:%p got fd %p: cancel=%d read=%d "
                 "PS:%p got fd %p: cancel=%d read=%d "
                 "write=%d",
                 "write=%d",
                 pollset, fd, cancel, read_ev, write_ev);
                 pollset, fd, cancel, read_ev, write_ev);
       }
       }
-      if (read_ev || cancel) {
+      if (error && !err_fallback) {
+        fd_has_errors(fd);
+      }
+      if (read_ev || cancel || err_fallback) {
         fd_become_readable(fd, pollset);
         fd_become_readable(fd, pollset);
       }
       }
-      if (write_ev || cancel) {
+      if (write_ev || cancel || err_fallback) {
         fd_become_writable(fd);
         fd_become_writable(fd);
       }
       }
     }
     }
@@ -1503,6 +1536,7 @@ static void shutdown_engine(void) {
 
 
 static const grpc_event_engine_vtable vtable = {
 static const grpc_event_engine_vtable vtable = {
     sizeof(grpc_pollset),
     sizeof(grpc_pollset),
+    true,
 
 
     fd_create,
     fd_create,
     fd_wrapped_fd,
     fd_wrapped_fd,
@@ -1510,6 +1544,7 @@ static const grpc_event_engine_vtable vtable = {
     fd_shutdown,
     fd_shutdown,
     fd_notify_on_read,
     fd_notify_on_read,
     fd_notify_on_write,
     fd_notify_on_write,
+    fd_notify_on_error,
     fd_is_shutdown,
     fd_is_shutdown,
     fd_get_read_notifier_pollset,
     fd_get_read_notifier_pollset,
 
 

+ 47 - 21
src/core/lib/iomgr/ev_epollsig_linux.cc

@@ -132,6 +132,7 @@ struct grpc_fd {
 
 
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
   grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
+  grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure;
 
 
   struct grpc_fd* freelist_next;
   struct grpc_fd* freelist_next;
   grpc_closure* on_done_closure;
   grpc_closure* on_done_closure;
@@ -141,6 +142,9 @@ struct grpc_fd {
   gpr_atm read_notifier_pollset;
   gpr_atm read_notifier_pollset;
 
 
   grpc_iomgr_object iomgr_object;
   grpc_iomgr_object iomgr_object;
+
+  /* Do we need to track EPOLLERR events separately? */
+  bool track_err;
 };
 };
 
 
 /* Reference counting for fds */
 /* Reference counting for fds */
@@ -352,7 +356,10 @@ static void polling_island_add_fds_locked(polling_island* pi, grpc_fd** fds,
 
 
   for (i = 0; i < fd_count; i++) {
   for (i = 0; i < fd_count; i++) {
     ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
     ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
-    ev.data.ptr = fds[i];
+    /* Use the least significant bit of ev.data.ptr to store track_err to avoid
+     * synchronization issues when accessing it after receiving an event */
+    ev.data.ptr = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(fds[i]) |
+                                          (fds[i]->track_err ? 1 : 0));
     err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, fds[i]->fd, &ev);
     err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, fds[i]->fd, &ev);
 
 
     if (err < 0) {
     if (err < 0) {
@@ -435,7 +442,6 @@ static void polling_island_remove_all_fds_locked(polling_island* pi,
 
 
 /* The caller is expected to hold pi->mu lock before calling this function */
 /* The caller is expected to hold pi->mu lock before calling this function */
 static void polling_island_remove_fd_locked(polling_island* pi, grpc_fd* fd,
 static void polling_island_remove_fd_locked(polling_island* pi, grpc_fd* fd,
-                                            bool is_fd_closed,
                                             grpc_error** error) {
                                             grpc_error** error) {
   int err;
   int err;
   size_t i;
   size_t i;
@@ -444,16 +450,14 @@ static void polling_island_remove_fd_locked(polling_island* pi, grpc_fd* fd,
 
 
   /* If fd is already closed, then it would have been automatically been removed
   /* If fd is already closed, then it would have been automatically been removed
      from the epoll set */
      from the epoll set */
-  if (!is_fd_closed) {
-    err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, fd->fd, nullptr);
-    if (err < 0 && errno != ENOENT) {
-      gpr_asprintf(
-          &err_msg,
-          "epoll_ctl (epoll_fd: %d) del fd: %d failed with error: %d (%s)",
-          pi->epoll_fd, fd->fd, errno, strerror(errno));
-      append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
-      gpr_free(err_msg);
-    }
+  err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, fd->fd, nullptr);
+  if (err < 0 && errno != ENOENT) {
+    gpr_asprintf(
+        &err_msg,
+        "epoll_ctl (epoll_fd: %d) del fd: %d failed with error: %d (%s)",
+        pi->epoll_fd, fd->fd, errno, strerror(errno));
+    append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
+    gpr_free(err_msg);
   }
   }
 
 
   for (i = 0; i < pi->fd_cnt; i++) {
   for (i = 0; i < pi->fd_cnt; i++) {
@@ -769,6 +773,7 @@ static void unref_by(grpc_fd* fd, int n) {
 
 
     fd->read_closure->DestroyEvent();
     fd->read_closure->DestroyEvent();
     fd->write_closure->DestroyEvent();
     fd->write_closure->DestroyEvent();
+    fd->error_closure->DestroyEvent();
 
 
     gpr_mu_unlock(&fd_freelist_mu);
     gpr_mu_unlock(&fd_freelist_mu);
   } else {
   } else {
@@ -806,7 +811,7 @@ static void fd_global_shutdown(void) {
   gpr_mu_destroy(&fd_freelist_mu);
   gpr_mu_destroy(&fd_freelist_mu);
 }
 }
 
 
-static grpc_fd* fd_create(int fd, const char* name) {
+static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
   grpc_fd* new_fd = nullptr;
   grpc_fd* new_fd = nullptr;
 
 
   gpr_mu_lock(&fd_freelist_mu);
   gpr_mu_lock(&fd_freelist_mu);
@@ -821,6 +826,7 @@ static grpc_fd* fd_create(int fd, const char* name) {
     gpr_mu_init(&new_fd->po.mu);
     gpr_mu_init(&new_fd->po.mu);
     new_fd->read_closure.Init();
     new_fd->read_closure.Init();
     new_fd->write_closure.Init();
     new_fd->write_closure.Init();
+    new_fd->error_closure.Init();
   }
   }
 
 
   /* Note: It is not really needed to get the new_fd->po.mu lock here. If this
   /* Note: It is not really needed to get the new_fd->po.mu lock here. If this
@@ -837,6 +843,8 @@ static grpc_fd* fd_create(int fd, const char* name) {
   new_fd->orphaned = false;
   new_fd->orphaned = false;
   new_fd->read_closure->InitEvent();
   new_fd->read_closure->InitEvent();
   new_fd->write_closure->InitEvent();
   new_fd->write_closure->InitEvent();
+  new_fd->error_closure->InitEvent();
+  new_fd->track_err = track_err;
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
 
   new_fd->freelist_next = nullptr;
   new_fd->freelist_next = nullptr;
@@ -863,7 +871,7 @@ static int fd_wrapped_fd(grpc_fd* fd) {
 }
 }
 
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                      bool already_closed, const char* reason) {
+                      const char* reason) {
   grpc_error* error = GRPC_ERROR_NONE;
   grpc_error* error = GRPC_ERROR_NONE;
   polling_island* unref_pi = nullptr;
   polling_island* unref_pi = nullptr;
 
 
@@ -884,7 +892,7 @@ static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
        before doing this.) */
        before doing this.) */
   if (fd->po.pi != nullptr) {
   if (fd->po.pi != nullptr) {
     polling_island* pi_latest = polling_island_lock(fd->po.pi);
     polling_island* pi_latest = polling_island_lock(fd->po.pi);
-    polling_island_remove_fd_locked(pi_latest, fd, already_closed, &error);
+    polling_island_remove_fd_locked(pi_latest, fd, &error);
     gpr_mu_unlock(&pi_latest->mu);
     gpr_mu_unlock(&pi_latest->mu);
 
 
     unref_pi = fd->po.pi;
     unref_pi = fd->po.pi;
@@ -933,6 +941,7 @@ static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
   if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
   if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
     shutdown(fd->fd, SHUT_RDWR);
     shutdown(fd->fd, SHUT_RDWR);
     fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
     fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
+    fd->error_closure->SetShutdown(GRPC_ERROR_REF(why));
   }
   }
   GRPC_ERROR_UNREF(why);
   GRPC_ERROR_UNREF(why);
 }
 }
@@ -945,6 +954,10 @@ static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   fd->write_closure->NotifyOn(closure);
   fd->write_closure->NotifyOn(closure);
 }
 }
 
 
+static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  fd->error_closure->NotifyOn(closure);
+}
+
 /*******************************************************************************
 /*******************************************************************************
  * Pollset Definitions
  * Pollset Definitions
  */
  */
@@ -1116,6 +1129,8 @@ static void fd_become_readable(grpc_fd* fd, grpc_pollset* notifier) {
 
 
 static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
 static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
 
 
+static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
+
 static void pollset_release_polling_island(grpc_pollset* ps,
 static void pollset_release_polling_island(grpc_pollset* ps,
                                            const char* reason) {
                                            const char* reason) {
   if (ps->po.pi != nullptr) {
   if (ps->po.pi != nullptr) {
@@ -1254,14 +1269,23 @@ static void pollset_work_and_unlock(grpc_pollset* pollset,
          to the function pollset_work_and_unlock() will pick up the correct
          to the function pollset_work_and_unlock() will pick up the correct
          epoll_fd */
          epoll_fd */
     } else {
     } else {
-      grpc_fd* fd = static_cast<grpc_fd*>(data_ptr);
-      int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP);
-      int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI);
-      int write_ev = ep_ev[i].events & EPOLLOUT;
-      if (read_ev || cancel) {
+      grpc_fd* fd = reinterpret_cast<grpc_fd*>(
+          reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1));
+      bool track_err =
+          reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1);
+      bool cancel = (ep_ev[i].events & EPOLLHUP) != 0;
+      bool error = (ep_ev[i].events & EPOLLERR) != 0;
+      bool read_ev = (ep_ev[i].events & (EPOLLIN | EPOLLPRI)) != 0;
+      bool write_ev = (ep_ev[i].events & EPOLLOUT) != 0;
+      bool err_fallback = error && !track_err;
+
+      if (error && !err_fallback) {
+        fd_has_errors(fd);
+      }
+      if (read_ev || cancel || err_fallback) {
         fd_become_readable(fd, pollset);
         fd_become_readable(fd, pollset);
       }
       }
-      if (write_ev || cancel) {
+      if (write_ev || cancel || err_fallback) {
         fd_become_writable(fd);
         fd_become_writable(fd);
       }
       }
     }
     }
@@ -1634,6 +1658,7 @@ static void shutdown_engine(void) {
 
 
 static const grpc_event_engine_vtable vtable = {
 static const grpc_event_engine_vtable vtable = {
     sizeof(grpc_pollset),
     sizeof(grpc_pollset),
+    true,
 
 
     fd_create,
     fd_create,
     fd_wrapped_fd,
     fd_wrapped_fd,
@@ -1641,6 +1666,7 @@ static const grpc_event_engine_vtable vtable = {
     fd_shutdown,
     fd_shutdown,
     fd_notify_on_read,
     fd_notify_on_read,
     fd_notify_on_write,
     fd_notify_on_write,
+    fd_notify_on_error,
     fd_is_shutdown,
     fd_is_shutdown,
     fd_get_read_notifier_pollset,
     fd_get_read_notifier_pollset,
 
 

+ 10 - 4
src/core/lib/iomgr/ev_poll_posix.cc

@@ -330,7 +330,8 @@ static void unref_by(grpc_fd* fd, int n) {
   }
   }
 }
 }
 
 
-static grpc_fd* fd_create(int fd, const char* name) {
+static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
+  GPR_DEBUG_ASSERT(track_err == false);
   grpc_fd* r = static_cast<grpc_fd*>(gpr_malloc(sizeof(*r)));
   grpc_fd* r = static_cast<grpc_fd*>(gpr_malloc(sizeof(*r)));
   gpr_mu_init(&r->mu);
   gpr_mu_init(&r->mu);
   gpr_atm_rel_store(&r->refst, 1);
   gpr_atm_rel_store(&r->refst, 1);
@@ -424,14 +425,12 @@ static int fd_wrapped_fd(grpc_fd* fd) {
 }
 }
 
 
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
 static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                      bool already_closed, const char* reason) {
+                      const char* reason) {
   fd->on_done_closure = on_done;
   fd->on_done_closure = on_done;
   fd->released = release_fd != nullptr;
   fd->released = release_fd != nullptr;
   if (release_fd != nullptr) {
   if (release_fd != nullptr) {
     *release_fd = fd->fd;
     *release_fd = fd->fd;
     fd->released = true;
     fd->released = true;
-  } else if (already_closed) {
-    fd->released = true;
   }
   }
   gpr_mu_lock(&fd->mu);
   gpr_mu_lock(&fd->mu);
   REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
   REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
@@ -553,6 +552,11 @@ static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   gpr_mu_unlock(&fd->mu);
   gpr_mu_unlock(&fd->mu);
 }
 }
 
 
+static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  gpr_log(GPR_ERROR, "Polling engine does not support tracking errors.");
+  abort();
+}
+
 static uint32_t fd_begin_poll(grpc_fd* fd, grpc_pollset* pollset,
 static uint32_t fd_begin_poll(grpc_fd* fd, grpc_pollset* pollset,
                               grpc_pollset_worker* worker, uint32_t read_mask,
                               grpc_pollset_worker* worker, uint32_t read_mask,
                               uint32_t write_mask, grpc_fd_watcher* watcher) {
                               uint32_t write_mask, grpc_fd_watcher* watcher) {
@@ -1710,6 +1714,7 @@ static void shutdown_engine(void) {
 
 
 static const grpc_event_engine_vtable vtable = {
 static const grpc_event_engine_vtable vtable = {
     sizeof(grpc_pollset),
     sizeof(grpc_pollset),
+    false,
 
 
     fd_create,
     fd_create,
     fd_wrapped_fd,
     fd_wrapped_fd,
@@ -1717,6 +1722,7 @@ static const grpc_event_engine_vtable vtable = {
     fd_shutdown,
     fd_shutdown,
     fd_notify_on_read,
     fd_notify_on_read,
     fd_notify_on_write,
     fd_notify_on_write,
+    fd_notify_on_error,
     fd_is_shutdown,
     fd_is_shutdown,
     fd_get_read_notifier_pollset,
     fd_get_read_notifier_pollset,
 
 

+ 17 - 9
src/core/lib/iomgr/ev_posix.cc

@@ -193,10 +193,15 @@ void grpc_event_engine_shutdown(void) {
   g_event_engine = nullptr;
   g_event_engine = nullptr;
 }
 }
 
 
-grpc_fd* grpc_fd_create(int fd, const char* name) {
-  GRPC_POLLING_API_TRACE("fd_create(%d, %s)", fd, name);
-  GRPC_FD_TRACE("fd_create(%d, %s)", fd, name);
-  return g_event_engine->fd_create(fd, name);
+bool grpc_event_engine_can_track_errors(void) {
+  return g_event_engine->can_track_err;
+}
+
+grpc_fd* grpc_fd_create(int fd, const char* name, bool track_err) {
+  GRPC_POLLING_API_TRACE("fd_create(%d, %s, %d)", fd, name, track_err);
+  GRPC_FD_TRACE("fd_create(%d, %s, %d)", fd, name, track_err);
+  GPR_DEBUG_ASSERT(!track_err || g_event_engine->can_track_err);
+  return g_event_engine->fd_create(fd, name, track_err);
 }
 }
 
 
 int grpc_fd_wrapped_fd(grpc_fd* fd) {
 int grpc_fd_wrapped_fd(grpc_fd* fd) {
@@ -204,13 +209,12 @@ int grpc_fd_wrapped_fd(grpc_fd* fd) {
 }
 }
 
 
 void grpc_fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
 void grpc_fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                    bool already_closed, const char* reason) {
-  GRPC_POLLING_API_TRACE("fd_orphan(%d, %p, %p, %d, %s)",
-                         grpc_fd_wrapped_fd(fd), on_done, release_fd,
-                         already_closed, reason);
+                    const char* reason) {
+  GRPC_POLLING_API_TRACE("fd_orphan(%d, %p, %p, %s)", grpc_fd_wrapped_fd(fd),
+                         on_done, release_fd, reason);
   GRPC_FD_TRACE("grpc_fd_orphan, fd:%d closed", grpc_fd_wrapped_fd(fd));
   GRPC_FD_TRACE("grpc_fd_orphan, fd:%d closed", grpc_fd_wrapped_fd(fd));
 
 
-  g_event_engine->fd_orphan(fd, on_done, release_fd, already_closed, reason);
+  g_event_engine->fd_orphan(fd, on_done, release_fd, reason);
 }
 }
 
 
 void grpc_fd_shutdown(grpc_fd* fd, grpc_error* why) {
 void grpc_fd_shutdown(grpc_fd* fd, grpc_error* why) {
@@ -231,6 +235,10 @@ void grpc_fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
   g_event_engine->fd_notify_on_write(fd, closure);
   g_event_engine->fd_notify_on_write(fd, closure);
 }
 }
 
 
+void grpc_fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
+  g_event_engine->fd_notify_on_error(fd, closure);
+}
+
 static size_t pollset_size(void) { return g_event_engine->pollset_size; }
 static size_t pollset_size(void) { return g_event_engine->pollset_size; }
 
 
 static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
 static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {

+ 20 - 4
src/core/lib/iomgr/ev_posix.h

@@ -41,14 +41,16 @@ typedef struct grpc_fd grpc_fd;
 
 
 typedef struct grpc_event_engine_vtable {
 typedef struct grpc_event_engine_vtable {
   size_t pollset_size;
   size_t pollset_size;
+  bool can_track_err;
 
 
-  grpc_fd* (*fd_create)(int fd, const char* name);
+  grpc_fd* (*fd_create)(int fd, const char* name, bool track_err);
   int (*fd_wrapped_fd)(grpc_fd* fd);
   int (*fd_wrapped_fd)(grpc_fd* fd);
   void (*fd_orphan)(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
   void (*fd_orphan)(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                    bool already_closed, const char* reason);
+                    const char* reason);
   void (*fd_shutdown)(grpc_fd* fd, grpc_error* why);
   void (*fd_shutdown)(grpc_fd* fd, grpc_error* why);
   void (*fd_notify_on_read)(grpc_fd* fd, grpc_closure* closure);
   void (*fd_notify_on_read)(grpc_fd* fd, grpc_closure* closure);
   void (*fd_notify_on_write)(grpc_fd* fd, grpc_closure* closure);
   void (*fd_notify_on_write)(grpc_fd* fd, grpc_closure* closure);
+  void (*fd_notify_on_error)(grpc_fd* fd, grpc_closure* closure);
   bool (*fd_is_shutdown)(grpc_fd* fd);
   bool (*fd_is_shutdown)(grpc_fd* fd);
   grpc_pollset* (*fd_get_read_notifier_pollset)(grpc_fd* fd);
   grpc_pollset* (*fd_get_read_notifier_pollset)(grpc_fd* fd);
 
 
@@ -84,10 +86,20 @@ void grpc_event_engine_shutdown(void);
 /* Return the name of the poll strategy */
 /* Return the name of the poll strategy */
 const char* grpc_get_poll_strategy_name();
 const char* grpc_get_poll_strategy_name();
 
 
+/* Returns true if polling engine can track errors separately, false otherwise.
+ * If this is true, fd can be created with track_err set. After this, error
+ * events will be reported using fd_notify_on_error. If it is not set, errors
+ * will continue to be reported through fd_notify_on_read and
+ * fd_notify_on_write.
+ */
+bool grpc_event_engine_can_track_errors();
+
 /* Create a wrapped file descriptor.
 /* Create a wrapped file descriptor.
    Requires fd is a non-blocking file descriptor.
    Requires fd is a non-blocking file descriptor.
+   \a track_err if true means that error events would be tracked separately
+   using grpc_fd_notify_on_error. Currently, valid only for linux systems.
    This takes ownership of closing fd. */
    This takes ownership of closing fd. */
-grpc_fd* grpc_fd_create(int fd, const char* name);
+grpc_fd* grpc_fd_create(int fd, const char* name, bool track_err);
 
 
 /* Return the wrapped fd, or -1 if it has been released or closed. */
 /* Return the wrapped fd, or -1 if it has been released or closed. */
 int grpc_fd_wrapped_fd(grpc_fd* fd);
 int grpc_fd_wrapped_fd(grpc_fd* fd);
@@ -100,7 +112,7 @@ int grpc_fd_wrapped_fd(grpc_fd* fd);
    notify_on_write.
    notify_on_write.
    MUST NOT be called with a pollset lock taken */
    MUST NOT be called with a pollset lock taken */
 void grpc_fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
 void grpc_fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
-                    bool already_closed, const char* reason);
+                    const char* reason);
 
 
 /* Has grpc_fd_shutdown been called on an fd? */
 /* Has grpc_fd_shutdown been called on an fd? */
 bool grpc_fd_is_shutdown(grpc_fd* fd);
 bool grpc_fd_is_shutdown(grpc_fd* fd);
@@ -126,6 +138,10 @@ void grpc_fd_notify_on_read(grpc_fd* fd, grpc_closure* closure);
 /* Exactly the same semantics as above, except based on writable events.  */
 /* Exactly the same semantics as above, except based on writable events.  */
 void grpc_fd_notify_on_write(grpc_fd* fd, grpc_closure* closure);
 void grpc_fd_notify_on_write(grpc_fd* fd, grpc_closure* closure);
 
 
+/* Exactly the same semantics as above, except based on error events. track_err
+ * needs to have been set on grpc_fd_create */
+void grpc_fd_notify_on_error(grpc_fd* fd, grpc_closure* closure);
+
 /* Return the read notifier pollset from the fd */
 /* Return the read notifier pollset from the fd */
 grpc_pollset* grpc_fd_get_read_notifier_pollset(grpc_fd* fd);
 grpc_pollset* grpc_fd_get_read_notifier_pollset(grpc_fd* fd);
 
 

+ 7 - 7
src/core/lib/iomgr/tcp_client_cfstream.cc

@@ -52,7 +52,7 @@ typedef struct CFStreamConnect {
 
 
   CFReadStreamRef read_stream;
   CFReadStreamRef read_stream;
   CFWriteStreamRef write_stream;
   CFWriteStreamRef write_stream;
-  CFStreamHandle* stream_sync;
+  CFStreamHandle* stream_handle;
 
 
   grpc_timer alarm;
   grpc_timer alarm;
   grpc_closure on_alarm;
   grpc_closure on_alarm;
@@ -71,7 +71,7 @@ typedef struct CFStreamConnect {
 
 
 static void CFStreamConnectCleanup(CFStreamConnect* connect) {
 static void CFStreamConnectCleanup(CFStreamConnect* connect) {
   grpc_resource_quota_unref_internal(connect->resource_quota);
   grpc_resource_quota_unref_internal(connect->resource_quota);
-  CFSTREAM_HANDLE_UNREF(connect->stream_sync, "async connect clean up");
+  CFSTREAM_HANDLE_UNREF(connect->stream_handle, "async connect clean up");
   CFRelease(connect->read_stream);
   CFRelease(connect->read_stream);
   CFRelease(connect->write_stream);
   CFRelease(connect->write_stream);
   gpr_mu_destroy(&connect->mu);
   gpr_mu_destroy(&connect->mu);
@@ -131,7 +131,7 @@ static void OnOpen(void* arg, grpc_error* error) {
       if (error == GRPC_ERROR_NONE) {
       if (error == GRPC_ERROR_NONE) {
         *endpoint = grpc_cfstream_endpoint_create(
         *endpoint = grpc_cfstream_endpoint_create(
             connect->read_stream, connect->write_stream, connect->addr_name,
             connect->read_stream, connect->write_stream, connect->addr_name,
-            connect->resource_quota, connect->stream_sync);
+            connect->resource_quota, connect->stream_handle);
       }
       }
     } else {
     } else {
       GRPC_ERROR_REF(error);
       GRPC_ERROR_REF(error);
@@ -170,8 +170,8 @@ static void CFStreamClientConnect(grpc_closure* closure, grpc_endpoint** ep,
   gpr_mu_init(&connect->mu);
   gpr_mu_init(&connect->mu);
 
 
   if (grpc_tcp_trace.enabled()) {
   if (grpc_tcp_trace.enabled()) {
-    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
-            connect->addr_name);
+    gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %p, %s: asynchronously connecting",
+            connect, connect->addr_name);
   }
   }
 
 
   grpc_resource_quota* resource_quota = grpc_resource_quota_create(NULL);
   grpc_resource_quota* resource_quota = grpc_resource_quota_create(NULL);
@@ -197,11 +197,11 @@ static void CFStreamClientConnect(grpc_closure* closure, grpc_endpoint** ep,
   CFRelease(host);
   CFRelease(host);
   connect->read_stream = read_stream;
   connect->read_stream = read_stream;
   connect->write_stream = write_stream;
   connect->write_stream = write_stream;
-  connect->stream_sync =
+  connect->stream_handle =
       CFStreamHandle::CreateStreamHandle(read_stream, write_stream);
       CFStreamHandle::CreateStreamHandle(read_stream, write_stream);
   GRPC_CLOSURE_INIT(&connect->on_open, OnOpen, static_cast<void*>(connect),
   GRPC_CLOSURE_INIT(&connect->on_open, OnOpen, static_cast<void*>(connect),
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
-  connect->stream_sync->NotifyOnOpen(&connect->on_open);
+  connect->stream_handle->NotifyOnOpen(&connect->on_open);
   GRPC_CLOSURE_INIT(&connect->on_alarm, OnAlarm, connect,
   GRPC_CLOSURE_INIT(&connect->on_alarm, OnAlarm, connect,
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
   gpr_mu_lock(&connect->mu);
   gpr_mu_lock(&connect->mu);

+ 3 - 5
src/core/lib/iomgr/tcp_client_posix.cc

@@ -211,8 +211,7 @@ static void on_writable(void* acp, grpc_error* error) {
 finish:
 finish:
   if (fd != nullptr) {
   if (fd != nullptr) {
     grpc_pollset_set_del_fd(ac->interested_parties, fd);
     grpc_pollset_set_del_fd(ac->interested_parties, fd);
-    grpc_fd_orphan(fd, nullptr, nullptr, false /* already_closed */,
-                   "tcp_client_orphan");
+    grpc_fd_orphan(fd, nullptr, nullptr, "tcp_client_orphan");
     fd = nullptr;
     fd = nullptr;
   }
   }
   done = (--ac->refs == 0);
   done = (--ac->refs == 0);
@@ -280,7 +279,7 @@ grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args,
   }
   }
   addr_str = grpc_sockaddr_to_uri(mapped_addr);
   addr_str = grpc_sockaddr_to_uri(mapped_addr);
   gpr_asprintf(&name, "tcp-client:%s", addr_str);
   gpr_asprintf(&name, "tcp-client:%s", addr_str);
-  *fdobj = grpc_fd_create(fd, name);
+  *fdobj = grpc_fd_create(fd, name, false);
   gpr_free(name);
   gpr_free(name);
   gpr_free(addr_str);
   gpr_free(addr_str);
   return GRPC_ERROR_NONE;
   return GRPC_ERROR_NONE;
@@ -305,8 +304,7 @@ void grpc_tcp_client_create_from_prepared_fd(
     return;
     return;
   }
   }
   if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
   if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
-    grpc_fd_orphan(fdobj, nullptr, nullptr, false /* already_closed */,
-                   "tcp_client_connect_error");
+    grpc_fd_orphan(fdobj, nullptr, nullptr, "tcp_client_connect_error");
     GRPC_CLOSURE_SCHED(closure, GRPC_OS_ERROR(errno, "connect"));
     GRPC_CLOSURE_SCHED(closure, GRPC_OS_ERROR(errno, "connect"));
     return;
     return;
   }
   }

+ 1 - 1
src/core/lib/iomgr/tcp_posix.cc

@@ -297,7 +297,7 @@ static void tcp_shutdown(grpc_endpoint* ep, grpc_error* why) {
 
 
 static void tcp_free(grpc_tcp* tcp) {
 static void tcp_free(grpc_tcp* tcp) {
   grpc_fd_orphan(tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
   grpc_fd_orphan(tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
-                 false /* already_closed */, "tcp_unref_orphan");
+                 "tcp_unref_orphan");
   grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer);
   grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer);
   grpc_resource_user_unref(tcp->resource_user);
   grpc_resource_user_unref(tcp->resource_user);
   gpr_free(tcp->peer_string);
   gpr_free(tcp->peer_string);

+ 3 - 3
src/core/lib/iomgr/tcp_server_posix.cc

@@ -150,7 +150,7 @@ static void deactivated_all_ports(grpc_tcp_server* s) {
       GRPC_CLOSURE_INIT(&sp->destroyed_closure, destroyed_port, s,
       GRPC_CLOSURE_INIT(&sp->destroyed_closure, destroyed_port, s,
                         grpc_schedule_on_exec_ctx);
                         grpc_schedule_on_exec_ctx);
       grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, nullptr,
       grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, nullptr,
-                     false /* already_closed */, "tcp_listener_shutdown");
+                     "tcp_listener_shutdown");
     }
     }
     gpr_mu_unlock(&s->mu);
     gpr_mu_unlock(&s->mu);
   } else {
   } else {
@@ -226,7 +226,7 @@ static void on_read(void* arg, grpc_error* err) {
       gpr_log(GPR_INFO, "SERVER_CONNECT: incoming connection: %s", addr_str);
       gpr_log(GPR_INFO, "SERVER_CONNECT: incoming connection: %s", addr_str);
     }
     }
 
 
-    grpc_fd* fdobj = grpc_fd_create(fd, name);
+    grpc_fd* fdobj = grpc_fd_create(fd, name, false);
 
 
     read_notifier_pollset =
     read_notifier_pollset =
         sp->server->pollsets[static_cast<size_t>(gpr_atm_no_barrier_fetch_add(
         sp->server->pollsets[static_cast<size_t>(gpr_atm_no_barrier_fetch_add(
@@ -362,7 +362,7 @@ static grpc_error* clone_port(grpc_tcp_listener* listener, unsigned count) {
     listener->sibling = sp;
     listener->sibling = sp;
     sp->server = listener->server;
     sp->server = listener->server;
     sp->fd = fd;
     sp->fd = fd;
-    sp->emfd = grpc_fd_create(fd, name);
+    sp->emfd = grpc_fd_create(fd, name, false);
     memcpy(&sp->addr, &listener->addr, sizeof(grpc_resolved_address));
     memcpy(&sp->addr, &listener->addr, sizeof(grpc_resolved_address));
     sp->port = port;
     sp->port = port;
     sp->port_index = listener->port_index;
     sp->port_index = listener->port_index;

+ 1 - 1
src/core/lib/iomgr/tcp_server_utils_posix_common.cc

@@ -105,7 +105,7 @@ static grpc_error* add_socket_to_server(grpc_tcp_server* s, int fd,
     s->tail = sp;
     s->tail = sp;
     sp->server = s;
     sp->server = s;
     sp->fd = fd;
     sp->fd = fd;
-    sp->emfd = grpc_fd_create(fd, name);
+    sp->emfd = grpc_fd_create(fd, name, false);
     memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
     memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
     sp->port = port;
     sp->port = port;
     sp->port_index = port_index;
     sp->port_index = port_index;

+ 2 - 3
src/core/lib/iomgr/udp_server.cc

@@ -152,7 +152,7 @@ GrpcUdpListener::GrpcUdpListener(grpc_udp_server* server, int fd,
   grpc_sockaddr_to_string(&addr_str, addr, 1);
   grpc_sockaddr_to_string(&addr_str, addr, 1);
   gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
   gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
   gpr_free(addr_str);
   gpr_free(addr_str);
-  emfd_ = grpc_fd_create(fd, name);
+  emfd_ = grpc_fd_create(fd, name, false);
   memcpy(&addr_, addr, sizeof(grpc_resolved_address));
   memcpy(&addr_, addr, sizeof(grpc_resolved_address));
   GPR_ASSERT(emfd_);
   GPR_ASSERT(emfd_);
   gpr_free(name);
   gpr_free(name);
@@ -300,8 +300,7 @@ void GrpcUdpListener::OrphanFd() {
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
   /* Because at this point, all listening sockets have been shutdown already, no
   /* Because at this point, all listening sockets have been shutdown already, no
    * need to call OnFdAboutToOrphan() to notify the handler again. */
    * need to call OnFdAboutToOrphan() to notify the handler again. */
-  grpc_fd_orphan(emfd_, &destroyed_closure_, nullptr,
-                 false /* already_closed */, "udp_listener_shutdown");
+  grpc_fd_orphan(emfd_, &destroyed_closure_, nullptr, "udp_listener_shutdown");
 }
 }
 
 
 void grpc_udp_server_destroy(grpc_udp_server* s, grpc_closure* on_done) {
 void grpc_udp_server_destroy(grpc_udp_server* s, grpc_closure* on_done) {

+ 14 - 4
src/core/lib/surface/call.cc

@@ -227,8 +227,17 @@ struct grpc_call {
 grpc_core::TraceFlag grpc_call_error_trace(false, "call_error");
 grpc_core::TraceFlag grpc_call_error_trace(false, "call_error");
 grpc_core::TraceFlag grpc_compression_trace(false, "compression");
 grpc_core::TraceFlag grpc_compression_trace(false, "compression");
 
 
-#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack*)((call) + 1))
-#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call*)(call_stack)) - 1)
+/* Given a size, round up to the next multiple of sizeof(void*) */
+#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \
+  (((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u))
+
+#define CALL_STACK_FROM_CALL(call)   \
+  (grpc_call_stack*)((char*)(call) + \
+                     ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)))
+#define CALL_FROM_CALL_STACK(call_stack) \
+  (grpc_call*)(((char*)(call_stack)) -   \
+               ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)))
+
 #define CALL_ELEM_FROM_CALL(call, idx) \
 #define CALL_ELEM_FROM_CALL(call, idx) \
   grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
   grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
 #define CALL_FROM_TOP_ELEM(top_elem) \
 #define CALL_FROM_TOP_ELEM(top_elem) \
@@ -291,8 +300,9 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
   size_t initial_size = grpc_channel_get_call_size_estimate(args->channel);
   size_t initial_size = grpc_channel_get_call_size_estimate(args->channel);
   GRPC_STATS_INC_CALL_INITIAL_SIZE(initial_size);
   GRPC_STATS_INC_CALL_INITIAL_SIZE(initial_size);
   gpr_arena* arena = gpr_arena_create(initial_size);
   gpr_arena* arena = gpr_arena_create(initial_size);
-  call = static_cast<grpc_call*>(gpr_arena_alloc(
-      arena, sizeof(grpc_call) + channel_stack->call_stack_size));
+  call = static_cast<grpc_call*>(
+      gpr_arena_alloc(arena, ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) +
+                                 channel_stack->call_stack_size));
   gpr_ref_init(&call->ext_ref, 1);
   gpr_ref_init(&call->ext_ref, 1);
   call->arena = arena;
   call->arena = arena;
   grpc_call_combiner_init(&call->call_combiner);
   grpc_call_combiner_init(&call->call_combiner);

+ 1 - 1
src/csharp/Grpc.Core.Testing/TestCalls.cs

@@ -65,7 +65,7 @@ namespace Grpc.Core.Testing
         /// Creates a test double for <c>AsyncDuplexStreamingCall</c>. Only for testing.
         /// Creates a test double for <c>AsyncDuplexStreamingCall</c>. Only for testing.
         /// Note: experimental API that can change or be removed without any prior notice.
         /// Note: experimental API that can change or be removed without any prior notice.
         /// </summary>
         /// </summary>
-        public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TResponse, TRequest>(
+        public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(
             IClientStreamWriter<TRequest> requestStream, IAsyncStreamReader<TResponse> responseStream,
             IClientStreamWriter<TRequest> requestStream, IAsyncStreamReader<TResponse> responseStream,
             Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc,
             Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc,
             Func<Metadata> getTrailersFunc, Action disposeAction)
             Func<Metadata> getTrailersFunc, Action disposeAction)

+ 2 - 0
src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj

@@ -13,11 +13,13 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <ProjectReference Include="../Grpc.Examples/Grpc.Examples.csproj" />
     <ProjectReference Include="../Grpc.Examples/Grpc.Examples.csproj" />
+    <ProjectReference Include="../Grpc.Core.Testing/Grpc.Core.Testing.csproj" />
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="NUnit" Version="3.6.0" />
     <PackageReference Include="NUnit" Version="3.6.0" />
     <PackageReference Include="NUnitLite" Version="3.6.0" />
     <PackageReference Include="NUnitLite" Version="3.6.0" />
+    <PackageReference Include="Moq" Version="4.8.2" />
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
   <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">

+ 101 - 0
src/csharp/Grpc.Examples.Tests/MathClientMockableTest.cs

@@ -0,0 +1,101 @@
+#region Copyright notice and license
+
+// Copyright 2018 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Testing;
+using NUnit.Framework;
+
+namespace Math.Tests
+{
+    /// <summary>
+    /// Demonstrates how to mock method stubs for all method types in a generated client.
+    /// </summary>
+    public class MathClientMockableTest
+    {
+        [Test]
+        public void ClientBaseBlockingUnaryCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+            
+            var expected = new DivReply();
+            mockClient.Setup(m => m.Div(Moq.It.IsAny<DivArgs>(), null, null, CancellationToken.None)).Returns(expected);
+            Assert.AreSame(expected, mockClient.Object.Div(new DivArgs()));
+        }
+
+        [Test]
+        public void ClientBaseBlockingUnaryCallWithCallOptionsCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+
+            var expected = new DivReply();
+            mockClient.Setup(m => m.Div(Moq.It.IsAny<DivArgs>(), Moq.It.IsAny<CallOptions>())).Returns(expected);
+            Assert.AreSame(expected, mockClient.Object.Div(new DivArgs(), new CallOptions()));
+        }
+
+        [Test]
+        public void ClientBaseAsyncUnaryCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestCalls to create an instance of a call.
+            var fakeCall = TestCalls.AsyncUnaryCall<DivReply>(Task.FromResult(new DivReply()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+            mockClient.Setup(m => m.DivAsync(Moq.It.IsAny<DivArgs>(), null, null, CancellationToken.None)).Returns(fakeCall);
+            Assert.AreSame(fakeCall, mockClient.Object.DivAsync(new DivArgs()));
+        }
+
+        [Test]
+        public void ClientBaseClientStreamingCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+            var mockRequestStream = new Moq.Mock<IClientStreamWriter<Num>>();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestCalls to create an instance of a call.
+            var fakeCall = TestCalls.AsyncClientStreamingCall<Num, Num>(mockRequestStream.Object, Task.FromResult(new Num()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+            mockClient.Setup(m => m.Sum(null, null, CancellationToken.None)).Returns(fakeCall);
+            Assert.AreSame(fakeCall, mockClient.Object.Sum());
+        }
+
+        [Test]
+        public void ClientBaseServerStreamingCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+            var mockResponseStream = new Moq.Mock<IAsyncStreamReader<Num>>();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestCalls to create an instance of a call.
+            var fakeCall = TestCalls.AsyncServerStreamingCall<Num>(mockResponseStream.Object, Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+            mockClient.Setup(m => m.Fib(Moq.It.IsAny<FibArgs>(), null, null, CancellationToken.None)).Returns(fakeCall);
+            Assert.AreSame(fakeCall, mockClient.Object.Fib(new FibArgs()));
+        }
+
+        [Test]
+        public void ClientBaseDuplexStreamingCallCanBeMocked()
+        {
+            var mockClient = new Moq.Mock<Math.MathClient>();
+            var mockRequestStream = new Moq.Mock<IClientStreamWriter<DivArgs>>();
+            var mockResponseStream = new Moq.Mock<IAsyncStreamReader<DivReply>>();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestCalls to create an instance of a call.
+            var fakeCall = TestCalls.AsyncDuplexStreamingCall<DivArgs, DivReply>(mockRequestStream.Object, mockResponseStream.Object, Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+            mockClient.Setup(m => m.DivMany(null, null, CancellationToken.None)).Returns(fakeCall);
+            Assert.AreSame(fakeCall, mockClient.Object.DivMany());
+        }
+    }
+}

+ 47 - 0
src/csharp/Grpc.Examples.Tests/MathServiceImplTestabilityTest.cs

@@ -0,0 +1,47 @@
+#region Copyright notice and license
+
+// Copyright 2018 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Testing;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Math.Tests
+{
+    /// <summary>
+    /// Demonstrates how to unit test implementations of generated server stubs.
+    /// </summary>
+    public class MathServiceImplTestabilityTest
+    {
+        [Test]
+        public async Task ServerCallImplIsTestable()
+        {
+            var mathImpl = new MathServiceImpl();
+
+            // Use a factory method provided by Grpc.Core.Testing.TestServerCallContext to create an instance of server call context.
+            // This allows testing even those server-side implementations that rely on the contents of ServerCallContext.
+            var fakeServerCallContext = TestServerCallContext.Create("fooMethod", null, DateTime.UtcNow.AddHours(1), new Metadata(), CancellationToken.None, "127.0.0.1", null, null, (metadata) => TaskUtils.CompletedTask, () => new WriteOptions(), (writeOptions) => { });
+            var response = await mathImpl.Div(new DivArgs { Dividend = 10, Divisor = 2 }, fakeServerCallContext);
+            Assert.AreEqual(5, response.Quotient);
+            Assert.AreEqual(0, response.Remainder);
+        }
+    }
+}

+ 12 - 12
src/csharp/Grpc.Examples/MathGrpc.cs

@@ -27,38 +27,38 @@ namespace Math {
   {
   {
     static readonly string __ServiceName = "math.Math";
     static readonly string __ServiceName = "math.Math";
 
 
-    static readonly grpc::Marshaller<global::Math.DivArgs> __Marshaller_DivArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivArgs.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Math.DivReply> __Marshaller_DivReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivReply.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Math.FibArgs> __Marshaller_FibArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.FibArgs.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Math.Num> __Marshaller_Num = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.Num.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Math.DivArgs> __Marshaller_math_DivArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Math.DivReply> __Marshaller_math_DivReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivReply.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Math.FibArgs> __Marshaller_math_FibArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.FibArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Math.Num> __Marshaller_math_Num = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.Num.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Math.DivArgs, global::Math.DivReply> __Method_Div = new grpc::Method<global::Math.DivArgs, global::Math.DivReply>(
     static readonly grpc::Method<global::Math.DivArgs, global::Math.DivReply> __Method_Div = new grpc::Method<global::Math.DivArgs, global::Math.DivReply>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "Div",
         "Div",
-        __Marshaller_DivArgs,
-        __Marshaller_DivReply);
+        __Marshaller_math_DivArgs,
+        __Marshaller_math_DivReply);
 
 
     static readonly grpc::Method<global::Math.DivArgs, global::Math.DivReply> __Method_DivMany = new grpc::Method<global::Math.DivArgs, global::Math.DivReply>(
     static readonly grpc::Method<global::Math.DivArgs, global::Math.DivReply> __Method_DivMany = new grpc::Method<global::Math.DivArgs, global::Math.DivReply>(
         grpc::MethodType.DuplexStreaming,
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         __ServiceName,
         "DivMany",
         "DivMany",
-        __Marshaller_DivArgs,
-        __Marshaller_DivReply);
+        __Marshaller_math_DivArgs,
+        __Marshaller_math_DivReply);
 
 
     static readonly grpc::Method<global::Math.FibArgs, global::Math.Num> __Method_Fib = new grpc::Method<global::Math.FibArgs, global::Math.Num>(
     static readonly grpc::Method<global::Math.FibArgs, global::Math.Num> __Method_Fib = new grpc::Method<global::Math.FibArgs, global::Math.Num>(
         grpc::MethodType.ServerStreaming,
         grpc::MethodType.ServerStreaming,
         __ServiceName,
         __ServiceName,
         "Fib",
         "Fib",
-        __Marshaller_FibArgs,
-        __Marshaller_Num);
+        __Marshaller_math_FibArgs,
+        __Marshaller_math_Num);
 
 
     static readonly grpc::Method<global::Math.Num, global::Math.Num> __Method_Sum = new grpc::Method<global::Math.Num, global::Math.Num>(
     static readonly grpc::Method<global::Math.Num, global::Math.Num> __Method_Sum = new grpc::Method<global::Math.Num, global::Math.Num>(
         grpc::MethodType.ClientStreaming,
         grpc::MethodType.ClientStreaming,
         __ServiceName,
         __ServiceName,
         "Sum",
         "Sum",
-        __Marshaller_Num,
-        __Marshaller_Num);
+        __Marshaller_math_Num,
+        __Marshaller_math_Num);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 4 - 4
src/csharp/Grpc.HealthCheck/HealthGrpc.cs

@@ -30,15 +30,15 @@ namespace Grpc.Health.V1 {
   {
   {
     static readonly string __ServiceName = "grpc.health.v1.Health";
     static readonly string __ServiceName = "grpc.health.v1.Health";
 
 
-    static readonly grpc::Marshaller<global::Grpc.Health.V1.HealthCheckRequest> __Marshaller_HealthCheckRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Health.V1.HealthCheckResponse> __Marshaller_HealthCheckResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Health.V1.HealthCheckRequest> __Marshaller_grpc_health_v1_HealthCheckRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Health.V1.HealthCheckResponse> __Marshaller_grpc_health_v1_HealthCheckResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckResponse.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse> __Method_Check = new grpc::Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse>(
     static readonly grpc::Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse> __Method_Check = new grpc::Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "Check",
         "Check",
-        __Marshaller_HealthCheckRequest,
-        __Marshaller_HealthCheckResponse);
+        __Marshaller_grpc_health_v1_HealthCheckRequest,
+        __Marshaller_grpc_health_v1_HealthCheckResponse);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 12 - 12
src/csharp/Grpc.IntegrationTesting/BenchmarkServiceGrpc.cs

@@ -29,43 +29,43 @@ namespace Grpc.Testing {
   {
   {
     static readonly string __ServiceName = "grpc.testing.BenchmarkService";
     static readonly string __ServiceName = "grpc.testing.BenchmarkService";
 
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_SimpleRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_SimpleResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_grpc_testing_SimpleRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_grpc_testing_SimpleResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "UnaryCall",
         "UnaryCall",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.DuplexStreaming,
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         __ServiceName,
         "StreamingCall",
         "StreamingCall",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingFromClient = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingFromClient = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.ClientStreaming,
         grpc::MethodType.ClientStreaming,
         __ServiceName,
         __ServiceName,
         "StreamingFromClient",
         "StreamingFromClient",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingFromServer = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingFromServer = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.ServerStreaming,
         grpc::MethodType.ServerStreaming,
         __ServiceName,
         __ServiceName,
         "StreamingFromServer",
         "StreamingFromServer",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingBothWays = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_StreamingBothWays = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.DuplexStreaming,
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         __ServiceName,
         "StreamingBothWays",
         "StreamingBothWays",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 0 - 23
src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs

@@ -33,29 +33,6 @@ namespace Grpc.IntegrationTesting
     {
     {
         TestService.TestServiceClient unimplementedClient = new UnimplementedTestServiceClient();
         TestService.TestServiceClient unimplementedClient = new UnimplementedTestServiceClient();
 
 
-        [Test]
-        public void ExpandedParamOverloadCanBeMocked()
-        {
-            var expected = new SimpleResponse();
-
-            var mockClient = new Moq.Mock<TestService.TestServiceClient>();
-            // mocking is relatively clumsy because one needs to specify value for all the optional params.
-            mockClient.Setup(m => m.UnaryCall(Moq.It.IsAny<SimpleRequest>(), null, null, CancellationToken.None)).Returns(expected);
-
-            Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest()));
-        }
-
-        [Test]
-        public void CallOptionsOverloadCanBeMocked()
-        {
-            var expected = new SimpleResponse();
-
-            var mockClient = new Moq.Mock<TestService.TestServiceClient>();
-            mockClient.Setup(m => m.UnaryCall(Moq.It.IsAny<SimpleRequest>(), Moq.It.IsAny<CallOptions>())).Returns(expected);
-
-            Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest(), new CallOptions()));
-        }
-
         [Test]
         [Test]
         public void DefaultMethodStubThrows_UnaryCall()
         public void DefaultMethodStubThrows_UnaryCall()
         {
         {

+ 0 - 1
src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj

@@ -19,7 +19,6 @@
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
     <PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
     <PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
     <PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
-    <PackageReference Include="Moq" Version="4.8.2" />
     <PackageReference Include="NUnit" Version="3.6.0" />
     <PackageReference Include="NUnit" Version="3.6.0" />
     <PackageReference Include="NUnitLite" Version="3.6.0" />
     <PackageReference Include="NUnitLite" Version="3.6.0" />
   </ItemGroup>
   </ItemGroup>

+ 7 - 7
src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs

@@ -33,23 +33,23 @@ namespace Grpc.Testing {
   {
   {
     static readonly string __ServiceName = "grpc.testing.MetricsService";
     static readonly string __ServiceName = "grpc.testing.MetricsService";
 
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.EmptyMessage> __Marshaller_EmptyMessage = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.EmptyMessage.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.GaugeResponse> __Marshaller_GaugeResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeResponse.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.GaugeRequest> __Marshaller_GaugeRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.EmptyMessage> __Marshaller_grpc_testing_EmptyMessage = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.EmptyMessage.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.GaugeResponse> __Marshaller_grpc_testing_GaugeResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.GaugeRequest> __Marshaller_grpc_testing_GaugeRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.GaugeRequest.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Grpc.Testing.EmptyMessage, global::Grpc.Testing.GaugeResponse> __Method_GetAllGauges = new grpc::Method<global::Grpc.Testing.EmptyMessage, global::Grpc.Testing.GaugeResponse>(
     static readonly grpc::Method<global::Grpc.Testing.EmptyMessage, global::Grpc.Testing.GaugeResponse> __Method_GetAllGauges = new grpc::Method<global::Grpc.Testing.EmptyMessage, global::Grpc.Testing.GaugeResponse>(
         grpc::MethodType.ServerStreaming,
         grpc::MethodType.ServerStreaming,
         __ServiceName,
         __ServiceName,
         "GetAllGauges",
         "GetAllGauges",
-        __Marshaller_EmptyMessage,
-        __Marshaller_GaugeResponse);
+        __Marshaller_grpc_testing_EmptyMessage,
+        __Marshaller_grpc_testing_GaugeResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.GaugeRequest, global::Grpc.Testing.GaugeResponse> __Method_GetGauge = new grpc::Method<global::Grpc.Testing.GaugeRequest, global::Grpc.Testing.GaugeResponse>(
     static readonly grpc::Method<global::Grpc.Testing.GaugeRequest, global::Grpc.Testing.GaugeResponse> __Method_GetGauge = new grpc::Method<global::Grpc.Testing.GaugeRequest, global::Grpc.Testing.GaugeResponse>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "GetGauge",
         "GetGauge",
-        __Marshaller_GaugeRequest,
-        __Marshaller_GaugeResponse);
+        __Marshaller_grpc_testing_GaugeRequest,
+        __Marshaller_grpc_testing_GaugeResponse);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 4 - 4
src/csharp/Grpc.IntegrationTesting/ReportQpsScenarioServiceGrpc.cs

@@ -29,15 +29,15 @@ namespace Grpc.Testing {
   {
   {
     static readonly string __ServiceName = "grpc.testing.ReportQpsScenarioService";
     static readonly string __ServiceName = "grpc.testing.ReportQpsScenarioService";
 
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.ScenarioResult> __Marshaller_ScenarioResult = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ScenarioResult.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.Void> __Marshaller_Void = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Void.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ScenarioResult> __Marshaller_grpc_testing_ScenarioResult = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ScenarioResult.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Void> __Marshaller_grpc_testing_Void = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Void.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Grpc.Testing.ScenarioResult, global::Grpc.Testing.Void> __Method_ReportScenario = new grpc::Method<global::Grpc.Testing.ScenarioResult, global::Grpc.Testing.Void>(
     static readonly grpc::Method<global::Grpc.Testing.ScenarioResult, global::Grpc.Testing.Void> __Method_ReportScenario = new grpc::Method<global::Grpc.Testing.ScenarioResult, global::Grpc.Testing.Void>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "ReportScenario",
         "ReportScenario",
-        __Marshaller_ScenarioResult,
-        __Marshaller_Void);
+        __Marshaller_grpc_testing_ScenarioResult,
+        __Marshaller_grpc_testing_Void);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 33 - 33
src/csharp/Grpc.IntegrationTesting/TestGrpc.cs

@@ -34,69 +34,69 @@ namespace Grpc.Testing {
   {
   {
     static readonly string __ServiceName = "grpc.testing.TestService";
     static readonly string __ServiceName = "grpc.testing.TestService";
 
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_SimpleRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_SimpleResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingOutputCallRequest> __Marshaller_StreamingOutputCallRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingOutputCallResponse> __Marshaller_StreamingOutputCallResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallResponse.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingInputCallRequest> __Marshaller_StreamingInputCallRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingInputCallResponse> __Marshaller_StreamingInputCallResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_grpc_testing_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_grpc_testing_SimpleRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_grpc_testing_SimpleResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingOutputCallRequest> __Marshaller_grpc_testing_StreamingOutputCallRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingOutputCallResponse> __Marshaller_grpc_testing_StreamingOutputCallResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingInputCallRequest> __Marshaller_grpc_testing_StreamingInputCallRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.StreamingInputCallResponse> __Marshaller_grpc_testing_StreamingInputCallResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallResponse.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_EmptyCall = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_EmptyCall = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "EmptyCall",
         "EmptyCall",
-        __Marshaller_Empty,
-        __Marshaller_Empty);
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_Empty);
 
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "UnaryCall",
         "UnaryCall",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_CacheableUnaryCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
     static readonly grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_CacheableUnaryCall = new grpc::Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "CacheableUnaryCall",
         "CacheableUnaryCall",
-        __Marshaller_SimpleRequest,
-        __Marshaller_SimpleResponse);
+        __Marshaller_grpc_testing_SimpleRequest,
+        __Marshaller_grpc_testing_SimpleResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_StreamingOutputCall = new grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
     static readonly grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_StreamingOutputCall = new grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
         grpc::MethodType.ServerStreaming,
         grpc::MethodType.ServerStreaming,
         __ServiceName,
         __ServiceName,
         "StreamingOutputCall",
         "StreamingOutputCall",
-        __Marshaller_StreamingOutputCallRequest,
-        __Marshaller_StreamingOutputCallResponse);
+        __Marshaller_grpc_testing_StreamingOutputCallRequest,
+        __Marshaller_grpc_testing_StreamingOutputCallResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> __Method_StreamingInputCall = new grpc::Method<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse>(
     static readonly grpc::Method<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> __Method_StreamingInputCall = new grpc::Method<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse>(
         grpc::MethodType.ClientStreaming,
         grpc::MethodType.ClientStreaming,
         __ServiceName,
         __ServiceName,
         "StreamingInputCall",
         "StreamingInputCall",
-        __Marshaller_StreamingInputCallRequest,
-        __Marshaller_StreamingInputCallResponse);
+        __Marshaller_grpc_testing_StreamingInputCallRequest,
+        __Marshaller_grpc_testing_StreamingInputCallResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_FullDuplexCall = new grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
     static readonly grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_FullDuplexCall = new grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
         grpc::MethodType.DuplexStreaming,
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         __ServiceName,
         "FullDuplexCall",
         "FullDuplexCall",
-        __Marshaller_StreamingOutputCallRequest,
-        __Marshaller_StreamingOutputCallResponse);
+        __Marshaller_grpc_testing_StreamingOutputCallRequest,
+        __Marshaller_grpc_testing_StreamingOutputCallResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_HalfDuplexCall = new grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
     static readonly grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_HalfDuplexCall = new grpc::Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
         grpc::MethodType.DuplexStreaming,
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         __ServiceName,
         "HalfDuplexCall",
         "HalfDuplexCall",
-        __Marshaller_StreamingOutputCallRequest,
-        __Marshaller_StreamingOutputCallResponse);
+        __Marshaller_grpc_testing_StreamingOutputCallRequest,
+        __Marshaller_grpc_testing_StreamingOutputCallResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_UnimplementedCall = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_UnimplementedCall = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "UnimplementedCall",
         "UnimplementedCall",
-        __Marshaller_Empty,
-        __Marshaller_Empty);
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_Empty);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
@@ -548,14 +548,14 @@ namespace Grpc.Testing {
   {
   {
     static readonly string __ServiceName = "grpc.testing.UnimplementedService";
     static readonly string __ServiceName = "grpc.testing.UnimplementedService";
 
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_grpc_testing_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_UnimplementedCall = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_UnimplementedCall = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "UnimplementedCall",
         "UnimplementedCall",
-        __Marshaller_Empty,
-        __Marshaller_Empty);
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_Empty);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
@@ -669,23 +669,23 @@ namespace Grpc.Testing {
   {
   {
     static readonly string __ServiceName = "grpc.testing.ReconnectService";
     static readonly string __ServiceName = "grpc.testing.ReconnectService";
 
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.ReconnectParams> __Marshaller_ReconnectParams = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectParams.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.ReconnectInfo> __Marshaller_ReconnectInfo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectInfo.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ReconnectParams> __Marshaller_grpc_testing_ReconnectParams = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectParams.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Empty> __Marshaller_grpc_testing_Empty = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ReconnectInfo> __Marshaller_grpc_testing_ReconnectInfo = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectInfo.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Grpc.Testing.ReconnectParams, global::Grpc.Testing.Empty> __Method_Start = new grpc::Method<global::Grpc.Testing.ReconnectParams, global::Grpc.Testing.Empty>(
     static readonly grpc::Method<global::Grpc.Testing.ReconnectParams, global::Grpc.Testing.Empty> __Method_Start = new grpc::Method<global::Grpc.Testing.ReconnectParams, global::Grpc.Testing.Empty>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "Start",
         "Start",
-        __Marshaller_ReconnectParams,
-        __Marshaller_Empty);
+        __Marshaller_grpc_testing_ReconnectParams,
+        __Marshaller_grpc_testing_Empty);
 
 
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo> __Method_Stop = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo>(
     static readonly grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo> __Method_Stop = new grpc::Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "Stop",
         "Stop",
-        __Marshaller_Empty,
-        __Marshaller_ReconnectInfo);
+        __Marshaller_grpc_testing_Empty,
+        __Marshaller_grpc_testing_ReconnectInfo);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 15 - 15
src/csharp/Grpc.IntegrationTesting/WorkerServiceGrpc.cs

@@ -29,41 +29,41 @@ namespace Grpc.Testing {
   {
   {
     static readonly string __ServiceName = "grpc.testing.WorkerService";
     static readonly string __ServiceName = "grpc.testing.WorkerService";
 
 
-    static readonly grpc::Marshaller<global::Grpc.Testing.ServerArgs> __Marshaller_ServerArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerArgs.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.ServerStatus> __Marshaller_ServerStatus = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerStatus.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.ClientArgs> __Marshaller_ClientArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientArgs.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.ClientStatus> __Marshaller_ClientStatus = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientStatus.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.CoreRequest> __Marshaller_CoreRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.CoreRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.CoreResponse> __Marshaller_CoreResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.CoreResponse.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Testing.Void> __Marshaller_Void = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Void.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ServerArgs> __Marshaller_grpc_testing_ServerArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ServerStatus> __Marshaller_grpc_testing_ServerStatus = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ServerStatus.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ClientArgs> __Marshaller_grpc_testing_ClientArgs = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientArgs.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.ClientStatus> __Marshaller_grpc_testing_ClientStatus = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ClientStatus.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.CoreRequest> __Marshaller_grpc_testing_CoreRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.CoreRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.CoreResponse> __Marshaller_grpc_testing_CoreResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.CoreResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Testing.Void> __Marshaller_grpc_testing_Void = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Void.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> __Method_RunServer = new grpc::Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus>(
     static readonly grpc::Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> __Method_RunServer = new grpc::Method<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus>(
         grpc::MethodType.DuplexStreaming,
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         __ServiceName,
         "RunServer",
         "RunServer",
-        __Marshaller_ServerArgs,
-        __Marshaller_ServerStatus);
+        __Marshaller_grpc_testing_ServerArgs,
+        __Marshaller_grpc_testing_ServerStatus);
 
 
     static readonly grpc::Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> __Method_RunClient = new grpc::Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus>(
     static readonly grpc::Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> __Method_RunClient = new grpc::Method<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus>(
         grpc::MethodType.DuplexStreaming,
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         __ServiceName,
         "RunClient",
         "RunClient",
-        __Marshaller_ClientArgs,
-        __Marshaller_ClientStatus);
+        __Marshaller_grpc_testing_ClientArgs,
+        __Marshaller_grpc_testing_ClientStatus);
 
 
     static readonly grpc::Method<global::Grpc.Testing.CoreRequest, global::Grpc.Testing.CoreResponse> __Method_CoreCount = new grpc::Method<global::Grpc.Testing.CoreRequest, global::Grpc.Testing.CoreResponse>(
     static readonly grpc::Method<global::Grpc.Testing.CoreRequest, global::Grpc.Testing.CoreResponse> __Method_CoreCount = new grpc::Method<global::Grpc.Testing.CoreRequest, global::Grpc.Testing.CoreResponse>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "CoreCount",
         "CoreCount",
-        __Marshaller_CoreRequest,
-        __Marshaller_CoreResponse);
+        __Marshaller_grpc_testing_CoreRequest,
+        __Marshaller_grpc_testing_CoreResponse);
 
 
     static readonly grpc::Method<global::Grpc.Testing.Void, global::Grpc.Testing.Void> __Method_QuitWorker = new grpc::Method<global::Grpc.Testing.Void, global::Grpc.Testing.Void>(
     static readonly grpc::Method<global::Grpc.Testing.Void, global::Grpc.Testing.Void> __Method_QuitWorker = new grpc::Method<global::Grpc.Testing.Void, global::Grpc.Testing.Void>(
         grpc::MethodType.Unary,
         grpc::MethodType.Unary,
         __ServiceName,
         __ServiceName,
         "QuitWorker",
         "QuitWorker",
-        __Marshaller_Void,
-        __Marshaller_Void);
+        __Marshaller_grpc_testing_Void,
+        __Marshaller_grpc_testing_Void);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 4 - 4
src/csharp/Grpc.Reflection/ReflectionGrpc.cs

@@ -29,15 +29,15 @@ namespace Grpc.Reflection.V1Alpha {
   {
   {
     static readonly string __ServiceName = "grpc.reflection.v1alpha.ServerReflection";
     static readonly string __ServiceName = "grpc.reflection.v1alpha.ServerReflection";
 
 
-    static readonly grpc::Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest> __Marshaller_ServerReflectionRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionRequest.Parser.ParseFrom);
-    static readonly grpc::Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> __Marshaller_ServerReflectionResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionResponse.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest> __Marshaller_grpc_reflection_v1alpha_ServerReflectionRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionRequest.Parser.ParseFrom);
+    static readonly grpc::Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> __Marshaller_grpc_reflection_v1alpha_ServerReflectionResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionResponse.Parser.ParseFrom);
 
 
     static readonly grpc::Method<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> __Method_ServerReflectionInfo = new grpc::Method<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse>(
     static readonly grpc::Method<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> __Method_ServerReflectionInfo = new grpc::Method<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse>(
         grpc::MethodType.DuplexStreaming,
         grpc::MethodType.DuplexStreaming,
         __ServiceName,
         __ServiceName,
         "ServerReflectionInfo",
         "ServerReflectionInfo",
-        __Marshaller_ServerReflectionRequest,
-        __Marshaller_ServerReflectionResponse);
+        __Marshaller_grpc_reflection_v1alpha_ServerReflectionRequest,
+        __Marshaller_grpc_reflection_v1alpha_ServerReflectionResponse);
 
 
     /// <summary>Service descriptor</summary>
     /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor

+ 3 - 1
src/csharp/tests.json

@@ -41,7 +41,9 @@
     "Grpc.Core.Tests.UserAgentStringTest"
     "Grpc.Core.Tests.UserAgentStringTest"
   ],
   ],
   "Grpc.Examples.Tests": [
   "Grpc.Examples.Tests": [
-    "Math.Tests.MathClientServerTest"
+    "Math.Tests.MathClientMockableTest",
+    "Math.Tests.MathClientServerTest",
+    "Math.Tests.MathServiceImplTestabilityTest"
   ],
   ],
   "Grpc.HealthCheck.Tests": [
   "Grpc.HealthCheck.Tests": [
     "Grpc.HealthCheck.Tests.HealthClientServerTest",
     "Grpc.HealthCheck.Tests.HealthClientServerTest",

+ 4 - 1
src/objective-c/GRPCClient/GRPCCall.m

@@ -206,8 +206,9 @@ static NSString *const kBearerPrefix = @"Bearer ";
   } else {
   } else {
     [_responseWriteable enqueueSuccessfulCompletion];
     [_responseWriteable enqueueSuccessfulCompletion];
   }
   }
-
+#ifndef GRPC_CFSTREAM
   [GRPCConnectivityMonitor unregisterObserver:self];
   [GRPCConnectivityMonitor unregisterObserver:self];
+#endif
 
 
   // If the call isn't retained anywhere else, it can be deallocated now.
   // If the call isn't retained anywhere else, it can be deallocated now.
   _retainSelf = nil;
   _retainSelf = nil;
@@ -462,7 +463,9 @@ static NSString *const kBearerPrefix = @"Bearer ";
   [self sendHeaders:_requestHeaders];
   [self sendHeaders:_requestHeaders];
   [self invokeCall];
   [self invokeCall];
 
 
+#ifndef GRPC_CFSTREAM
   [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)];
   [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)];
+#endif
 }
 }
 
 
 - (void)startWithWriteable:(id<GRXWriteable>)writeable {
 - (void)startWithWriteable:(id<GRXWriteable>)writeable {

+ 16 - 7
src/objective-c/GRPCClient/private/GRPCHost.m

@@ -49,7 +49,9 @@ static NSMutableDictionary *kHostCache;
   if (_channelCreds != nil) {
   if (_channelCreds != nil) {
     grpc_channel_credentials_release(_channelCreds);
     grpc_channel_credentials_release(_channelCreds);
   }
   }
+#ifndef GRPC_CFSTREAM
   [GRPCConnectivityMonitor unregisterObserver:self];
   [GRPCConnectivityMonitor unregisterObserver:self];
+#endif
 }
 }
 
 
 // Default initializer.
 // Default initializer.
@@ -84,7 +86,9 @@ static NSMutableDictionary *kHostCache;
       kHostCache[address] = self;
       kHostCache[address] = self;
       _compressAlgorithm = GRPC_COMPRESS_NONE;
       _compressAlgorithm = GRPC_COMPRESS_NONE;
     }
     }
+#ifndef GRPC_CFSTREAM
     [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)];
     [GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)];
+#endif
   }
   }
   return self;
   return self;
 }
 }
@@ -125,6 +129,14 @@ static NSMutableDictionary *kHostCache;
                         completionQueue:queue];
                         completionQueue:queue];
 }
 }
 
 
+- (NSData *)nullTerminatedDataWithString:(NSString *)string {
+  // dataUsingEncoding: does not return a null-terminated string.
+  NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
+  NSMutableData *nullTerminated = [NSMutableData dataWithData:data];
+  [nullTerminated appendBytes:"\0" length:1];
+  return nullTerminated;
+}
+
 - (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
 - (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
             withPrivateKey:(nullable NSString *)pemPrivateKey
             withPrivateKey:(nullable NSString *)pemPrivateKey
              withCertChain:(nullable NSString *)pemCertChain
              withCertChain:(nullable NSString *)pemCertChain
@@ -146,13 +158,12 @@ static NSMutableDictionary *kHostCache;
       kDefaultRootsError = error;
       kDefaultRootsError = error;
       return;
       return;
     }
     }
-    kDefaultRootsASCII =
-        [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
+    kDefaultRootsASCII = [self nullTerminatedDataWithString:contentInUTF8];
   });
   });
 
 
   NSData *rootsASCII;
   NSData *rootsASCII;
   if (pemRootCerts != nil) {
   if (pemRootCerts != nil) {
-    rootsASCII = [pemRootCerts dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
+    rootsASCII = [self nullTerminatedDataWithString:pemRootCerts];
   } else {
   } else {
     if (kDefaultRootsASCII == nil) {
     if (kDefaultRootsASCII == nil) {
       if (errorPtr) {
       if (errorPtr) {
@@ -175,10 +186,8 @@ static NSMutableDictionary *kHostCache;
     creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL);
     creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL);
   } else {
   } else {
     grpc_ssl_pem_key_cert_pair key_cert_pair;
     grpc_ssl_pem_key_cert_pair key_cert_pair;
-    NSData *privateKeyASCII =
-        [pemPrivateKey dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
-    NSData *certChainASCII =
-        [pemCertChain dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
+    NSData *privateKeyASCII = [self nullTerminatedDataWithString:pemPrivateKey];
+    NSData *certChainASCII = [self nullTerminatedDataWithString:pemCertChain];
     key_cert_pair.private_key = privateKeyASCII.bytes;
     key_cert_pair.private_key = privateKeyASCII.bytes;
     key_cert_pair.cert_chain = certChainASCII.bytes;
     key_cert_pair.cert_chain = certChainASCII.bytes;
     creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL);
     creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL);

+ 1 - 16
src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj

@@ -99,7 +99,6 @@
 				5EC49F8D2043E46B00ED189A /* Sources */,
 				5EC49F8D2043E46B00ED189A /* Sources */,
 				5EC49F8E2043E46B00ED189A /* Frameworks */,
 				5EC49F8E2043E46B00ED189A /* Frameworks */,
 				5EC49F8F2043E46B00ED189A /* Resources */,
 				5EC49F8F2043E46B00ED189A /* Resources */,
-				9F67C72B6B6BAF2781078886 /* [CP] Embed Pods Frameworks */,
 				735516C793AF7394FBB83B7F /* [CP] Copy Pods Resources */,
 				735516C793AF7394FBB83B7F /* [CP] Copy Pods Resources */,
 			);
 			);
 			buildRules = (
 			buildRules = (
@@ -194,21 +193,6 @@
 			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 			showEnvVarsInLog = 0;
 		};
 		};
-		9F67C72B6B6BAF2781078886 /* [CP] Embed Pods Frameworks */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputPaths = (
-			);
-			name = "[CP] Embed Pods Frameworks";
-			outputPaths = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp-frameworks.sh\"\n";
-			showEnvVarsInLog = 0;
-		};
 /* End PBXShellScriptBuildPhase section */
 /* End PBXShellScriptBuildPhase section */
 
 
 /* Begin PBXSourcesBuildPhase section */
 /* Begin PBXSourcesBuildPhase section */
@@ -284,6 +268,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = (
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
 					"DEBUG=1",
 					"$(inherited)",
 					"$(inherited)",
+					"GRPC_CFSTREAM=1",
 				);
 				);
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;

+ 2 - 0
src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m

@@ -35,7 +35,9 @@ NSString *host = @"grpc-test.sandbox.googleapis.com";
 - (void)viewDidLoad {
 - (void)viewDidLoad {
   [super viewDidLoad];
   [super viewDidLoad];
 
 
+#ifndef GRPC_CFSTREAM
   [GRPCConnectivityMonitor registerObserver:self selector:@selector(reachabilityChanged:)];
   [GRPCConnectivityMonitor registerObserver:self selector:@selector(reachabilityChanged:)];
+#endif
 }
 }
 
 
 - (void)reachabilityChanged:(NSNotification *)note {
 - (void)reachabilityChanged:(NSNotification *)note {

+ 3 - 3
src/objective-c/tests/Connectivity/Podfile

@@ -5,9 +5,9 @@ platform :ios, '8.0'
 GRPC_LOCAL_SRC = '../../../..'
 GRPC_LOCAL_SRC = '../../../..'
 
 
 target 'ConnectivityTestingApp' do
 target 'ConnectivityTestingApp' do
-  pod 'gRPC', :path => GRPC_LOCAL_SRC
-  pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
-  pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC
+  pod 'gRPC/CFStream', :path => GRPC_LOCAL_SRC
+  pod 'gRPC-Core/CFStream-Implementation', :path => GRPC_LOCAL_SRC
+  pod 'gRPC-ProtoRPC/CFStream', :path => GRPC_LOCAL_SRC
   pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
   pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
   pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf"
   pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf"
   pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
   pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"

+ 2 - 1
src/objective-c/tests/GRPCClientTests.m

@@ -525,7 +525,8 @@ static GRPCProtoMethod *kFullDuplexCallMethod;
 - (void)testErrorCode {
 - (void)testErrorCode {
   int port = [self findFreePort];
   int port = [self findFreePort];
   NSString *const kDummyAddress = [NSString stringWithFormat:@"localhost:%d", port];
   NSString *const kDummyAddress = [NSString stringWithFormat:@"localhost:%d", port];
-  __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
+  __weak XCTestExpectation *completion =
+      [self expectationWithDescription:@"Received correct error code."];
 
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kDummyAddress
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kDummyAddress
                                              path:kEmptyCallMethod.HTTPPath
                                              path:kEmptyCallMethod.HTTPPath

+ 2 - 1
src/php/README.md

@@ -9,7 +9,8 @@ gRPC PHP installation instructions for Google Cloud Platform is in
 
 
 ## Environment
 ## Environment
 
 
-###Prerequisite:
+### Prerequisite:
+
 * `php` 5.5 or above, 7.0 or above
 * `php` 5.5 or above, 7.0 or above
 * `pecl`
 * `pecl`
 * `composer`
 * `composer`

+ 0 - 4
src/proto/grpc/testing/messages.proto

@@ -27,7 +27,6 @@ message BoolValue {
   bool value = 1;
   bool value = 1;
 }
 }
 
 
-// DEPRECATED, don't use. To be removed shortly.
 // The type of payload that should be returned.
 // The type of payload that should be returned.
 enum PayloadType {
 enum PayloadType {
   // Compressable text format.
   // Compressable text format.
@@ -36,7 +35,6 @@ enum PayloadType {
 
 
 // A block of data, to simply increase gRPC message size.
 // A block of data, to simply increase gRPC message size.
 message Payload {
 message Payload {
-  // DEPRECATED, don't use. To be removed shortly.
   // The type of data in body.
   // The type of data in body.
   PayloadType type = 1;
   PayloadType type = 1;
   // Primary contents of payload.
   // Primary contents of payload.
@@ -52,7 +50,6 @@ message EchoStatus {
 
 
 // Unary request.
 // Unary request.
 message SimpleRequest {
 message SimpleRequest {
-  // DEPRECATED, don't use. To be removed shortly.
   // Desired payload type in the response from the server.
   // Desired payload type in the response from the server.
   // If response_type is RANDOM, server randomly chooses one from other formats.
   // If response_type is RANDOM, server randomly chooses one from other formats.
   PayloadType response_type = 1;
   PayloadType response_type = 1;
@@ -131,7 +128,6 @@ message ResponseParameters {
 
 
 // Server-streaming request.
 // Server-streaming request.
 message StreamingOutputCallRequest {
 message StreamingOutputCallRequest {
-  // DEPRECATED, don't use. To be removed shortly.
   // Desired payload type in the response from the server.
   // Desired payload type in the response from the server.
   // If response_type is RANDOM, the payload from each response in the stream
   // If response_type is RANDOM, the payload from each response in the stream
   // might be of different types. This is to simulate a mixed type of payload
   // might be of different types. This is to simulate a mixed type of payload

+ 10 - 8
src/python/grpcio/grpc/__init__.py

@@ -1482,7 +1482,7 @@ def ssl_server_credentials(private_key_certificate_chain_pairs,
       A ServerCredentials for use with an SSL-enabled Server. Typically, this
       A ServerCredentials for use with an SSL-enabled Server. Typically, this
       object is an argument to add_secure_port() method during server setup.
       object is an argument to add_secure_port() method during server setup.
     """
     """
-    if len(private_key_certificate_chain_pairs) == 0:
+    if not private_key_certificate_chain_pairs:
         raise ValueError(
         raise ValueError(
             'At least one private key-certificate chain pair is required!')
             'At least one private key-certificate chain pair is required!')
     elif require_client_auth and root_certificates is None:
     elif require_client_auth and root_certificates is None:
@@ -1512,15 +1512,15 @@ def ssl_server_certificate_configuration(private_key_certificate_chain_pairs,
       A ServerCertificateConfiguration that can be returned in the certificate
       A ServerCertificateConfiguration that can be returned in the certificate
         configuration fetching callback.
         configuration fetching callback.
     """
     """
-    if len(private_key_certificate_chain_pairs) == 0:
-        raise ValueError(
-            'At least one private key-certificate chain pair is required!')
-    else:
+    if private_key_certificate_chain_pairs:
         return ServerCertificateConfiguration(
         return ServerCertificateConfiguration(
             _cygrpc.server_certificate_config_ssl(root_certificates, [
             _cygrpc.server_certificate_config_ssl(root_certificates, [
                 _cygrpc.SslPemKeyCertPair(key, pem)
                 _cygrpc.SslPemKeyCertPair(key, pem)
                 for key, pem in private_key_certificate_chain_pairs
                 for key, pem in private_key_certificate_chain_pairs
             ]))
             ]))
+    else:
+        raise ValueError(
+            'At least one private key-certificate chain pair is required!')
 
 
 
 
 def dynamic_ssl_server_credentials(initial_certificate_configuration,
 def dynamic_ssl_server_credentials(initial_certificate_configuration,
@@ -1656,9 +1656,11 @@ def server(thread_pool,
       A Server object.
       A Server object.
     """
     """
     from grpc import _server  # pylint: disable=cyclic-import
     from grpc import _server  # pylint: disable=cyclic-import
-    return _server.Server(thread_pool, () if handlers is None else handlers, ()
-                          if interceptors is None else interceptors, () if
-                          options is None else options, maximum_concurrent_rpcs)
+    return _server.create_server(thread_pool, ()
+                                 if handlers is None else handlers, ()
+                                 if interceptors is None else interceptors, ()
+                                 if options is None else options,
+                                 maximum_concurrent_rpcs)
 
 
 
 
 ###################################  __all__  #################################
 ###################################  __all__  #################################

+ 2 - 5
src/python/grpcio/grpc/_channel.py

@@ -192,7 +192,7 @@ def _consume_request_iterator(request_iterator, state, call, request_serializer,
             with state.condition:
             with state.condition:
                 if state.code is None and not state.cancelled:
                 if state.code is None and not state.cancelled:
                     if serialized_request is None:
                     if serialized_request is None:
-                        code = grpc.StatusCode.INTERNAL  # pylint: disable=redefined-variable-type
+                        code = grpc.StatusCode.INTERNAL
                         details = 'Exception serializing request!'
                         details = 'Exception serializing request!'
                         call.cancel(
                         call.cancel(
                             _common.STATUS_CODE_TO_CYGRPC_STATUS_CODE[code],
                             _common.STATUS_CODE_TO_CYGRPC_STATUS_CODE[code],
@@ -813,10 +813,7 @@ def _poll_connectivity(state, channel, initial_try_to_connect):
                     _common.CYGRPC_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[
                     _common.CYGRPC_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[
                         connectivity])
                         connectivity])
                 if not state.delivering:
                 if not state.delivering:
-                    # NOTE(nathaniel): The field is only ever used as a
-                    # sequence so it's fine that both lists and tuples are
-                    # assigned to it.
-                    callbacks = _deliveries(state)  # pylint: disable=redefined-variable-type
+                    callbacks = _deliveries(state)
                     if callbacks:
                     if callbacks:
                         _spawn_delivery(state, callbacks)
                         _spawn_delivery(state, callbacks)
 
 

+ 0 - 0
src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pxd → src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pxd.pxi


+ 0 - 0
src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx → src/python/grpcio/grpc/_cython/_cygrpc/grpc_gevent.pyx.pxi


+ 1 - 1
src/python/grpcio/grpc/_cython/cygrpc.pxd

@@ -29,4 +29,4 @@ include "_cygrpc/server.pxd.pxi"
 include "_cygrpc/tag.pxd.pxi"
 include "_cygrpc/tag.pxd.pxi"
 include "_cygrpc/time.pxd.pxi"
 include "_cygrpc/time.pxd.pxi"
 
 
-include "_cygrpc/grpc_gevent.pxd"
+include "_cygrpc/grpc_gevent.pxd.pxi"

+ 1 - 1
src/python/grpcio/grpc/_cython/cygrpc.pyx

@@ -36,7 +36,7 @@ include "_cygrpc/server.pyx.pxi"
 include "_cygrpc/tag.pyx.pxi"
 include "_cygrpc/tag.pyx.pxi"
 include "_cygrpc/time.pyx.pxi"
 include "_cygrpc/time.pyx.pxi"
 
 
-include "_cygrpc/grpc_gevent.pyx"
+include "_cygrpc/grpc_gevent.pyx.pxi"
 
 
 #
 #
 # initialize gRPC
 # initialize gRPC

+ 13 - 4
src/python/grpcio/grpc/_interceptor.py

@@ -100,6 +100,12 @@ class _LocalFailure(grpc.RpcError, grpc.Future, grpc.Call):
     def cancelled(self):
     def cancelled(self):
         return False
         return False
 
 
+    def is_active(self):
+        return False
+
+    def time_remaining(self):
+        return None
+
     def running(self):
     def running(self):
         return False
         return False
 
 
@@ -115,6 +121,9 @@ class _LocalFailure(grpc.RpcError, grpc.Future, grpc.Call):
     def traceback(self, ignored_timeout=None):
     def traceback(self, ignored_timeout=None):
         return self._traceback
         return self._traceback
 
 
+    def add_callback(self, callback):
+        return False
+
     def add_done_callback(self, fn):
     def add_done_callback(self, fn):
         fn(self)
         fn(self)
 
 
@@ -288,11 +297,11 @@ class _Channel(grpc.Channel):
         self._channel = channel
         self._channel = channel
         self._interceptor = interceptor
         self._interceptor = interceptor
 
 
-    def subscribe(self, *args, **kwargs):
-        self._channel.subscribe(*args, **kwargs)
+    def subscribe(self, callback, try_to_connect=False):
+        self._channel.subscribe(callback, try_to_connect=try_to_connect)
 
 
-    def unsubscribe(self, *args, **kwargs):
-        self._channel.unsubscribe(*args, **kwargs)
+    def unsubscribe(self, callback):
+        self._channel.unsubscribe(callback)
 
 
     def unary_unary(self,
     def unary_unary(self,
                     method,
                     method,

+ 20 - 1
src/python/grpcio/grpc/_server.py

@@ -330,6 +330,8 @@ class _RequestIterator(object):
             self._state.request = None
             self._state.request = None
             return request
             return request
 
 
+        raise AssertionError()  # should never run
+
     def _next(self):
     def _next(self):
         with self._state.condition:
         with self._state.condition:
             self._raise_or_start_receive_message()
             self._raise_or_start_receive_message()
@@ -787,7 +789,16 @@ def _start(state):
         thread.start()
         thread.start()
 
 
 
 
-class Server(grpc.Server):
+def _validate_generic_rpc_handlers(generic_rpc_handlers):
+    for generic_rpc_handler in generic_rpc_handlers:
+        service_attribute = getattr(generic_rpc_handler, 'service', None)
+        if service_attribute is None:
+            raise AttributeError(
+                '"{}" must conform to grpc.GenericRpcHandler type but does '
+                'not have "service" method!'.format(generic_rpc_handler))
+
+
+class _Server(grpc.Server):
 
 
     # pylint: disable=too-many-arguments
     # pylint: disable=too-many-arguments
     def __init__(self, thread_pool, generic_handlers, interceptors, options,
     def __init__(self, thread_pool, generic_handlers, interceptors, options,
@@ -800,6 +811,7 @@ class Server(grpc.Server):
                                    thread_pool, maximum_concurrent_rpcs)
                                    thread_pool, maximum_concurrent_rpcs)
 
 
     def add_generic_rpc_handlers(self, generic_rpc_handlers):
     def add_generic_rpc_handlers(self, generic_rpc_handlers):
+        _validate_generic_rpc_handlers(generic_rpc_handlers)
         _add_generic_handlers(self._state, generic_rpc_handlers)
         _add_generic_handlers(self._state, generic_rpc_handlers)
 
 
     def add_insecure_port(self, address):
     def add_insecure_port(self, address):
@@ -817,3 +829,10 @@ class Server(grpc.Server):
 
 
     def __del__(self):
     def __del__(self):
         _stop(self._state, None)
         _stop(self._state, None)
+
+
+def create_server(thread_pool, generic_rpc_handlers, interceptors, options,
+                  maximum_concurrent_rpcs):
+    _validate_generic_rpc_handlers(generic_rpc_handlers)
+    return _Server(thread_pool, generic_rpc_handlers, interceptors, options,
+                   maximum_concurrent_rpcs)

+ 2 - 0
src/python/grpcio/grpc/_utilities.py

@@ -116,6 +116,8 @@ class _ChannelReadyFuture(grpc.Future):
             callable_util.call_logging_exceptions(
             callable_util.call_logging_exceptions(
                 done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
                 done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
 
 
+        return True
+
     def cancelled(self):
     def cancelled(self):
         with self._condition:
         with self._condition:
             return self._cancelled
             return self._cancelled

+ 1 - 0
src/python/grpcio/grpc/beta/_server_adaptations.py

@@ -305,6 +305,7 @@ def _simple_method_handler(implementation, request_deserializer,
                                         response_serializer, None, None, None,
                                         response_serializer, None, None, None,
                                         _adapt_stream_stream_event(
                                         _adapt_stream_stream_event(
                                             implementation.stream_stream_event))
                                             implementation.stream_stream_event))
+    raise ValueError()
 
 
 
 
 def _flatten_method_pair_map(method_pair_map):
 def _flatten_method_pair_map(method_pair_map):

+ 2 - 0
src/python/grpcio/grpc/beta/utilities.py

@@ -85,6 +85,8 @@ class _ChannelReadyFuture(future.Future):
             callable_util.call_logging_exceptions(
             callable_util.call_logging_exceptions(
                 done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
                 done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
 
 
+        return True
+
     def cancelled(self):
     def cancelled(self):
         with self._condition:
         with self._condition:
             return self._cancelled
             return self._cancelled

+ 4 - 4
src/python/grpcio/grpc/framework/foundation/stream_util.py

@@ -47,10 +47,10 @@ class IterableConsumer(stream.Consumer):
         self._values = []
         self._values = []
         self._active = True
         self._active = True
 
 
-    def consume(self, stock_reply):
+    def consume(self, value):
         with self._condition:
         with self._condition:
             if self._active:
             if self._active:
-                self._values.append(stock_reply)
+                self._values.append(value)
                 self._condition.notify()
                 self._condition.notify()
 
 
     def terminate(self):
     def terminate(self):
@@ -58,10 +58,10 @@ class IterableConsumer(stream.Consumer):
             self._active = False
             self._active = False
             self._condition.notify()
             self._condition.notify()
 
 
-    def consume_and_terminate(self, stock_reply):
+    def consume_and_terminate(self, value):
         with self._condition:
         with self._condition:
             if self._active:
             if self._active:
-                self._values.append(stock_reply)
+                self._values.append(value)
                 self._active = False
                 self._active = False
                 self._condition.notify()
                 self._condition.notify()
 
 

+ 1 - 1
src/python/grpcio_testing/grpc_testing/__init__.py

@@ -14,9 +14,9 @@
 """Objects for use in testing gRPC Python-using application code."""
 """Objects for use in testing gRPC Python-using application code."""
 
 
 import abc
 import abc
+import six
 
 
 from google.protobuf import descriptor
 from google.protobuf import descriptor
-import six
 
 
 import grpc
 import grpc
 
 

+ 2 - 2
src/python/grpcio_testing/grpc_testing/_server/_handler.py

@@ -105,10 +105,10 @@ class _Handler(Handler):
                 self._expiration_future.cancel()
                 self._expiration_future.cancel()
             self._condition.notify_all()
             self._condition.notify_all()
 
 
-    def add_termination_callback(self, termination_callback):
+    def add_termination_callback(self, callback):
         with self._condition:
         with self._condition:
             if self._code is None:
             if self._code is None:
-                self._termination_callbacks.append(termination_callback)
+                self._termination_callbacks.append(callback)
                 return True
                 return True
             else:
             else:
                 return False
                 return False

+ 6 - 5
src/python/grpcio_tests/tests/_loader.py

@@ -48,12 +48,13 @@ class Loader(object):
         # measure unnecessarily suffers)
         # measure unnecessarily suffers)
         coverage_context = coverage.Coverage(data_suffix=True)
         coverage_context = coverage.Coverage(data_suffix=True)
         coverage_context.start()
         coverage_context.start()
-        modules = [importlib.import_module(name) for name in names]
-        for module in modules:
-            self.visit_module(module)
-        for module in modules:
+        imported_modules = tuple(
+            importlib.import_module(name) for name in names)
+        for imported_module in imported_modules:
+            self.visit_module(imported_module)
+        for imported_module in imported_modules:
             try:
             try:
-                package_paths = module.__path__
+                package_paths = imported_module.__path__
             except AttributeError:
             except AttributeError:
                 continue
                 continue
             self.walk_packages(package_paths)
             self.walk_packages(package_paths)

+ 15 - 26
src/python/grpcio_tests/tests/_result.py

@@ -144,10 +144,6 @@ class AugmentedResult(unittest.TestResult):
         super(AugmentedResult, self).startTestRun()
         super(AugmentedResult, self).startTestRun()
         self.cases = dict()
         self.cases = dict()
 
 
-    def stopTestRun(self):
-        """See unittest.TestResult.stopTestRun."""
-        super(AugmentedResult, self).stopTestRun()
-
     def startTest(self, test):
     def startTest(self, test):
         """See unittest.TestResult.startTest."""
         """See unittest.TestResult.startTest."""
         super(AugmentedResult, self).startTest(test)
         super(AugmentedResult, self).startTest(test)
@@ -155,19 +151,19 @@ class AugmentedResult(unittest.TestResult):
         self.cases[case_id] = CaseResult(
         self.cases[case_id] = CaseResult(
             id=case_id, name=test.id(), kind=CaseResult.Kind.RUNNING)
             id=case_id, name=test.id(), kind=CaseResult.Kind.RUNNING)
 
 
-    def addError(self, test, error):
+    def addError(self, test, err):
         """See unittest.TestResult.addError."""
         """See unittest.TestResult.addError."""
-        super(AugmentedResult, self).addError(test, error)
+        super(AugmentedResult, self).addError(test, err)
         case_id = self.id_map(test)
         case_id = self.id_map(test)
         self.cases[case_id] = self.cases[case_id].updated(
         self.cases[case_id] = self.cases[case_id].updated(
-            kind=CaseResult.Kind.ERROR, traceback=error)
+            kind=CaseResult.Kind.ERROR, traceback=err)
 
 
-    def addFailure(self, test, error):
+    def addFailure(self, test, err):
         """See unittest.TestResult.addFailure."""
         """See unittest.TestResult.addFailure."""
-        super(AugmentedResult, self).addFailure(test, error)
+        super(AugmentedResult, self).addFailure(test, err)
         case_id = self.id_map(test)
         case_id = self.id_map(test)
         self.cases[case_id] = self.cases[case_id].updated(
         self.cases[case_id] = self.cases[case_id].updated(
-            kind=CaseResult.Kind.FAILURE, traceback=error)
+            kind=CaseResult.Kind.FAILURE, traceback=err)
 
 
     def addSuccess(self, test):
     def addSuccess(self, test):
         """See unittest.TestResult.addSuccess."""
         """See unittest.TestResult.addSuccess."""
@@ -183,12 +179,12 @@ class AugmentedResult(unittest.TestResult):
         self.cases[case_id] = self.cases[case_id].updated(
         self.cases[case_id] = self.cases[case_id].updated(
             kind=CaseResult.Kind.SKIP, skip_reason=reason)
             kind=CaseResult.Kind.SKIP, skip_reason=reason)
 
 
-    def addExpectedFailure(self, test, error):
+    def addExpectedFailure(self, test, err):
         """See unittest.TestResult.addExpectedFailure."""
         """See unittest.TestResult.addExpectedFailure."""
-        super(AugmentedResult, self).addExpectedFailure(test, error)
+        super(AugmentedResult, self).addExpectedFailure(test, err)
         case_id = self.id_map(test)
         case_id = self.id_map(test)
         self.cases[case_id] = self.cases[case_id].updated(
         self.cases[case_id] = self.cases[case_id].updated(
-            kind=CaseResult.Kind.EXPECTED_FAILURE, traceback=error)
+            kind=CaseResult.Kind.EXPECTED_FAILURE, traceback=err)
 
 
     def addUnexpectedSuccess(self, test):
     def addUnexpectedSuccess(self, test):
         """See unittest.TestResult.addUnexpectedSuccess."""
         """See unittest.TestResult.addUnexpectedSuccess."""
@@ -249,13 +245,6 @@ class CoverageResult(AugmentedResult):
         self.coverage_context.save()
         self.coverage_context.save()
         self.coverage_context = None
         self.coverage_context = None
 
 
-    def stopTestRun(self):
-        """See unittest.TestResult.stopTestRun."""
-        super(CoverageResult, self).stopTestRun()
-        # TODO(atash): Dig deeper into why the following line fails to properly
-        # combine coverage data from the Cython plugin.
-        #coverage.Coverage().combine()
-
 
 
 class _Colors(object):
 class _Colors(object):
     """Namespaced constants for terminal color magic numbers."""
     """Namespaced constants for terminal color magic numbers."""
@@ -295,16 +284,16 @@ class TerminalResult(CoverageResult):
         self.out.write(summary(self))
         self.out.write(summary(self))
         self.out.flush()
         self.out.flush()
 
 
-    def addError(self, test, error):
+    def addError(self, test, err):
         """See unittest.TestResult.addError."""
         """See unittest.TestResult.addError."""
-        super(TerminalResult, self).addError(test, error)
+        super(TerminalResult, self).addError(test, err)
         self.out.write(
         self.out.write(
             _Colors.FAIL + 'ERROR         {}\n'.format(test.id()) + _Colors.END)
             _Colors.FAIL + 'ERROR         {}\n'.format(test.id()) + _Colors.END)
         self.out.flush()
         self.out.flush()
 
 
-    def addFailure(self, test, error):
+    def addFailure(self, test, err):
         """See unittest.TestResult.addFailure."""
         """See unittest.TestResult.addFailure."""
-        super(TerminalResult, self).addFailure(test, error)
+        super(TerminalResult, self).addFailure(test, err)
         self.out.write(
         self.out.write(
             _Colors.FAIL + 'FAILURE       {}\n'.format(test.id()) + _Colors.END)
             _Colors.FAIL + 'FAILURE       {}\n'.format(test.id()) + _Colors.END)
         self.out.flush()
         self.out.flush()
@@ -323,9 +312,9 @@ class TerminalResult(CoverageResult):
             _Colors.INFO + 'SKIP          {}\n'.format(test.id()) + _Colors.END)
             _Colors.INFO + 'SKIP          {}\n'.format(test.id()) + _Colors.END)
         self.out.flush()
         self.out.flush()
 
 
-    def addExpectedFailure(self, test, error):
+    def addExpectedFailure(self, test, err):
         """See unittest.TestResult.addExpectedFailure."""
         """See unittest.TestResult.addExpectedFailure."""
-        super(TerminalResult, self).addExpectedFailure(test, error)
+        super(TerminalResult, self).addExpectedFailure(test, err)
         self.out.write(
         self.out.write(
             _Colors.INFO + 'FAILURE_OK    {}\n'.format(test.id()) + _Colors.END)
             _Colors.INFO + 'FAILURE_OK    {}\n'.format(test.id()) + _Colors.END)
         self.out.flush()
         self.out.flush()

+ 2 - 2
src/python/grpcio_tests/tests/interop/methods.py

@@ -144,8 +144,8 @@ def _large_unary_common_behavior(stub, fill_username, fill_oauth_scope,
 def _empty_unary(stub):
 def _empty_unary(stub):
     response = stub.EmptyCall(empty_pb2.Empty())
     response = stub.EmptyCall(empty_pb2.Empty())
     if not isinstance(response, empty_pb2.Empty):
     if not isinstance(response, empty_pb2.Empty):
-        raise TypeError('response is of type "%s", not empty_pb2.Empty!',
-                        type(response))
+        raise TypeError(
+            'response is of type "%s", not empty_pb2.Empty!' % type(response))
 
 
 
 
 def _large_unary(stub):
 def _large_unary(stub):

+ 1 - 0
src/python/grpcio_tests/tests/tests.json

@@ -53,6 +53,7 @@
   "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestCertConfigReuse",
   "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestCertConfigReuse",
   "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestWithClientAuth",
   "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestWithClientAuth",
   "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestWithoutClientAuth",
   "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestWithoutClientAuth",
+  "unit._server_test.ServerTest",
   "unit._session_cache_test.SSLSessionCacheTest",
   "unit._session_cache_test.SSLSessionCacheTest",
   "unit.beta._beta_features_test.BetaFeaturesTest",
   "unit.beta._beta_features_test.BetaFeaturesTest",
   "unit.beta._beta_features_test.ContextManagementAndLifecycleTest",
   "unit.beta._beta_features_test.ContextManagementAndLifecycleTest",

+ 0 - 13
src/python/grpcio_tests/tests/unit/_junkdrawer/__init__.py

@@ -1,13 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.

+ 0 - 164
src/python/grpcio_tests/tests/unit/_junkdrawer/stock_pb2.py

@@ -1,164 +0,0 @@
-# Copyright 2015 gRPC authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# TODO(nathaniel): Remove this from source control after having made
-# generation from the stock.proto source part of GRPC's build-and-test
-# process.
-
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: stock.proto
-
-import sys
-_b = sys.version_info[0] < 3 and (lambda x: x) or (lambda x: x.encode('latin1'))
-from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
-from google.protobuf import symbol_database as _symbol_database
-from google.protobuf import descriptor_pb2
-# @@protoc_insertion_point(imports)
-
-_sym_db = _symbol_database.Default()
-
-DESCRIPTOR = _descriptor.FileDescriptor(
-    name='stock.proto',
-    package='stock',
-    serialized_pb=_b(
-        '\n\x0bstock.proto\x12\x05stock\">\n\x0cStockRequest\x12\x0e\n\x06symbol\x18\x01 \x01(\t\x12\x1e\n\x13num_trades_to_watch\x18\x02 \x01(\x05:\x01\x30\"+\n\nStockReply\x12\r\n\x05price\x18\x01 \x01(\x02\x12\x0e\n\x06symbol\x18\x02 \x01(\t2\x96\x02\n\x05Stock\x12=\n\x11GetLastTradePrice\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00\x12I\n\x19GetLastTradePriceMultiple\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00(\x01\x30\x01\x12?\n\x11WatchFutureTrades\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00\x30\x01\x12\x42\n\x14GetHighestTradePrice\x12\x13.stock.StockRequest\x1a\x11.stock.StockReply\"\x00(\x01'
-    ))
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-_STOCKREQUEST = _descriptor.Descriptor(
-    name='StockRequest',
-    full_name='stock.StockRequest',
-    filename=None,
-    file=DESCRIPTOR,
-    containing_type=None,
-    fields=[
-        _descriptor.FieldDescriptor(
-            name='symbol',
-            full_name='stock.StockRequest.symbol',
-            index=0,
-            number=1,
-            type=9,
-            cpp_type=9,
-            label=1,
-            has_default_value=False,
-            default_value=_b("").decode('utf-8'),
-            message_type=None,
-            enum_type=None,
-            containing_type=None,
-            is_extension=False,
-            extension_scope=None,
-            options=None),
-        _descriptor.FieldDescriptor(
-            name='num_trades_to_watch',
-            full_name='stock.StockRequest.num_trades_to_watch',
-            index=1,
-            number=2,
-            type=5,
-            cpp_type=1,
-            label=1,
-            has_default_value=True,
-            default_value=0,
-            message_type=None,
-            enum_type=None,
-            containing_type=None,
-            is_extension=False,
-            extension_scope=None,
-            options=None),
-    ],
-    extensions=[],
-    nested_types=[],
-    enum_types=[],
-    options=None,
-    is_extendable=False,
-    extension_ranges=[],
-    oneofs=[],
-    serialized_start=22,
-    serialized_end=84,)
-
-_STOCKREPLY = _descriptor.Descriptor(
-    name='StockReply',
-    full_name='stock.StockReply',
-    filename=None,
-    file=DESCRIPTOR,
-    containing_type=None,
-    fields=[
-        _descriptor.FieldDescriptor(
-            name='price',
-            full_name='stock.StockReply.price',
-            index=0,
-            number=1,
-            type=2,
-            cpp_type=6,
-            label=1,
-            has_default_value=False,
-            default_value=0,
-            message_type=None,
-            enum_type=None,
-            containing_type=None,
-            is_extension=False,
-            extension_scope=None,
-            options=None),
-        _descriptor.FieldDescriptor(
-            name='symbol',
-            full_name='stock.StockReply.symbol',
-            index=1,
-            number=2,
-            type=9,
-            cpp_type=9,
-            label=1,
-            has_default_value=False,
-            default_value=_b("").decode('utf-8'),
-            message_type=None,
-            enum_type=None,
-            containing_type=None,
-            is_extension=False,
-            extension_scope=None,
-            options=None),
-    ],
-    extensions=[],
-    nested_types=[],
-    enum_types=[],
-    options=None,
-    is_extendable=False,
-    extension_ranges=[],
-    oneofs=[],
-    serialized_start=86,
-    serialized_end=129,)
-
-DESCRIPTOR.message_types_by_name['StockRequest'] = _STOCKREQUEST
-DESCRIPTOR.message_types_by_name['StockReply'] = _STOCKREPLY
-
-StockRequest = _reflection.GeneratedProtocolMessageType(
-    'StockRequest',
-    (_message.Message,),
-    dict(
-        DESCRIPTOR=_STOCKREQUEST,
-        __module__='stock_pb2'
-        # @@protoc_insertion_point(class_scope:stock.StockRequest)
-    ))
-_sym_db.RegisterMessage(StockRequest)
-
-StockReply = _reflection.GeneratedProtocolMessageType(
-    'StockReply',
-    (_message.Message,),
-    dict(
-        DESCRIPTOR=_STOCKREPLY,
-        __module__='stock_pb2'
-        # @@protoc_insertion_point(class_scope:stock.StockReply)
-    ))
-_sym_db.RegisterMessage(StockReply)
-
-# @@protoc_insertion_point(module_scope)

+ 52 - 0
src/python/grpcio_tests/tests/unit/_server_test.py

@@ -0,0 +1,52 @@
+# Copyright 2018 The gRPC Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from concurrent import futures
+import unittest
+
+import grpc
+
+
+class _ActualGenericRpcHandler(grpc.GenericRpcHandler):
+
+    def service(self, handler_call_details):
+        return None
+
+
+class ServerTest(unittest.TestCase):
+
+    def test_not_a_generic_rpc_handler_at_construction(self):
+        with self.assertRaises(AttributeError) as exception_context:
+            grpc.server(
+                futures.ThreadPoolExecutor(max_workers=5),
+                handlers=[
+                    _ActualGenericRpcHandler(),
+                    object(),
+                ])
+        self.assertIn('grpc.GenericRpcHandler',
+                      str(exception_context.exception))
+
+    def test_not_a_generic_rpc_handler_after_construction(self):
+        server = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
+        with self.assertRaises(AttributeError) as exception_context:
+            server.add_generic_rpc_handlers([
+                _ActualGenericRpcHandler(),
+                object(),
+            ])
+        self.assertIn('grpc.GenericRpcHandler',
+                      str(exception_context.exception))
+
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)

+ 3 - 3
templates/test/cpp/naming/resolver_component_tests_defs.include

@@ -58,7 +58,7 @@ def wait_until_dns_server_is_up(args,
     test_runner_log('Health check: attempt to connect to DNS server over TCP.')
     test_runner_log('Health check: attempt to connect to DNS server over TCP.')
     tcp_connect_subprocess = subprocess.Popen([
     tcp_connect_subprocess = subprocess.Popen([
         args.tcp_connect_bin_path,
         args.tcp_connect_bin_path,
-        '--server_host', '::1',
+        '--server_host', '127.0.0.1',
         '--server_port', str(args.dns_server_port),
         '--server_port', str(args.dns_server_port),
         '--timeout', str(1)])
         '--timeout', str(1)])
     tcp_connect_subprocess.communicate()
     tcp_connect_subprocess.communicate()
@@ -68,7 +68,7 @@ def wait_until_dns_server_is_up(args,
       dns_resolver_subprocess = subprocess.Popen([
       dns_resolver_subprocess = subprocess.Popen([
           args.dns_resolver_bin_path,
           args.dns_resolver_bin_path,
           '--qname', 'health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp',
           '--qname', 'health-check-local-dns-server-is-alive.resolver-tests.grpctestingexp',
-          '--server_host', '::1',
+          '--server_host', '127.0.0.1',
           '--server_port', str(args.dns_server_port)],
           '--server_port', str(args.dns_server_port)],
           stdout=subprocess.PIPE)
           stdout=subprocess.PIPE)
       dns_resolver_stdout, _ = dns_resolver_subprocess.communicate()
       dns_resolver_stdout, _ = dns_resolver_subprocess.communicate()
@@ -125,7 +125,7 @@ current_test_subprocess = subprocess.Popen([\
 
 
 \
 \
   % endfor
   % endfor
-  '--local_dns_server_address', '[::1]:%d' % args.dns_server_port])\
+  '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port])\
 
 
 current_test_subprocess.communicate()\
 current_test_subprocess.communicate()\
 
 

File diff suppressed because it is too large
+ 0 - 3359
test/core/avl/avl_test.cc


+ 8 - 0
test/core/end2end/end2end_nosec_tests.cc

@@ -100,6 +100,8 @@ extern void negative_deadline(grpc_end2end_test_config config);
 extern void negative_deadline_pre_init(void);
 extern void negative_deadline_pre_init(void);
 extern void network_status_change(grpc_end2end_test_config config);
 extern void network_status_change(grpc_end2end_test_config config);
 extern void network_status_change_pre_init(void);
 extern void network_status_change_pre_init(void);
+extern void no_error_on_hotpath(grpc_end2end_test_config config);
+extern void no_error_on_hotpath_pre_init(void);
 extern void no_logging(grpc_end2end_test_config config);
 extern void no_logging(grpc_end2end_test_config config);
 extern void no_logging_pre_init(void);
 extern void no_logging_pre_init(void);
 extern void no_op(grpc_end2end_test_config config);
 extern void no_op(grpc_end2end_test_config config);
@@ -222,6 +224,7 @@ void grpc_end2end_tests_pre_init(void) {
   max_message_length_pre_init();
   max_message_length_pre_init();
   negative_deadline_pre_init();
   negative_deadline_pre_init();
   network_status_change_pre_init();
   network_status_change_pre_init();
+  no_error_on_hotpath_pre_init();
   no_logging_pre_init();
   no_logging_pre_init();
   no_op_pre_init();
   no_op_pre_init();
   payload_pre_init();
   payload_pre_init();
@@ -307,6 +310,7 @@ void grpc_end2end_tests(int argc, char **argv,
     max_message_length(config);
     max_message_length(config);
     negative_deadline(config);
     negative_deadline(config);
     network_status_change(config);
     network_status_change(config);
+    no_error_on_hotpath(config);
     no_logging(config);
     no_logging(config);
     no_op(config);
     no_op(config);
     payload(config);
     payload(config);
@@ -492,6 +496,10 @@ void grpc_end2end_tests(int argc, char **argv,
       network_status_change(config);
       network_status_change(config);
       continue;
       continue;
     }
     }
+    if (0 == strcmp("no_error_on_hotpath", argv[i])) {
+      no_error_on_hotpath(config);
+      continue;
+    }
     if (0 == strcmp("no_logging", argv[i])) {
     if (0 == strcmp("no_logging", argv[i])) {
       no_logging(config);
       no_logging(config);
       continue;
       continue;

+ 8 - 0
test/core/end2end/end2end_tests.cc

@@ -102,6 +102,8 @@ extern void negative_deadline(grpc_end2end_test_config config);
 extern void negative_deadline_pre_init(void);
 extern void negative_deadline_pre_init(void);
 extern void network_status_change(grpc_end2end_test_config config);
 extern void network_status_change(grpc_end2end_test_config config);
 extern void network_status_change_pre_init(void);
 extern void network_status_change_pre_init(void);
+extern void no_error_on_hotpath(grpc_end2end_test_config config);
+extern void no_error_on_hotpath_pre_init(void);
 extern void no_logging(grpc_end2end_test_config config);
 extern void no_logging(grpc_end2end_test_config config);
 extern void no_logging_pre_init(void);
 extern void no_logging_pre_init(void);
 extern void no_op(grpc_end2end_test_config config);
 extern void no_op(grpc_end2end_test_config config);
@@ -225,6 +227,7 @@ void grpc_end2end_tests_pre_init(void) {
   max_message_length_pre_init();
   max_message_length_pre_init();
   negative_deadline_pre_init();
   negative_deadline_pre_init();
   network_status_change_pre_init();
   network_status_change_pre_init();
+  no_error_on_hotpath_pre_init();
   no_logging_pre_init();
   no_logging_pre_init();
   no_op_pre_init();
   no_op_pre_init();
   payload_pre_init();
   payload_pre_init();
@@ -311,6 +314,7 @@ void grpc_end2end_tests(int argc, char **argv,
     max_message_length(config);
     max_message_length(config);
     negative_deadline(config);
     negative_deadline(config);
     network_status_change(config);
     network_status_change(config);
+    no_error_on_hotpath(config);
     no_logging(config);
     no_logging(config);
     no_op(config);
     no_op(config);
     payload(config);
     payload(config);
@@ -500,6 +504,10 @@ void grpc_end2end_tests(int argc, char **argv,
       network_status_change(config);
       network_status_change(config);
       continue;
       continue;
     }
     }
+    if (0 == strcmp("no_error_on_hotpath", argv[i])) {
+      no_error_on_hotpath(config);
+      continue;
+    }
     if (0 == strcmp("no_logging", argv[i])) {
     if (0 == strcmp("no_logging", argv[i])) {
       no_logging(config);
       no_logging(config);
       continue;
       continue;

+ 1 - 0
test/core/end2end/gen_build_yaml.py

@@ -138,6 +138,7 @@ END2END_TESTS = {
     'max_message_length': default_test_options._replace(cpu_cost=LOWCPU),
     'max_message_length': default_test_options._replace(cpu_cost=LOWCPU),
     'negative_deadline': default_test_options,
     'negative_deadline': default_test_options,
     'network_status_change': default_test_options._replace(cpu_cost=LOWCPU),
     'network_status_change': default_test_options._replace(cpu_cost=LOWCPU),
+    'no_error_on_hotpath': default_test_options._replace(proxyable=False),
     'no_logging': default_test_options._replace(traceable=False),
     'no_logging': default_test_options._replace(traceable=False),
     'no_op': default_test_options,
     'no_op': default_test_options,
     'payload': default_test_options,
     'payload': default_test_options,

+ 1 - 0
test/core/end2end/generate_tests.bzl

@@ -134,6 +134,7 @@ END2END_TESTS = {
     'max_message_length': test_options(),
     'max_message_length': test_options(),
     'negative_deadline': test_options(),
     'negative_deadline': test_options(),
     'network_status_change': test_options(),
     'network_status_change': test_options(),
+    'no_error_on_hotpath': test_options(proxyable=False),
     'no_logging': test_options(traceable=False),
     'no_logging': test_options(traceable=False),
     'no_op': test_options(),
     'no_op': test_options(),
     'payload': test_options(),
     'payload': test_options(),

+ 246 - 0
test/core/end2end/tests/no_error_on_hotpath.cc

@@ -0,0 +1,246 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/error.h"
+#include "test/core/end2end/cq_verifier.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture f) {
+  grpc_call* c;
+  grpc_call* s;
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+                               grpc_slice_from_static_string("/foo"), nullptr,
+                               deadline, nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_OK;
+  op->data.send_status_from_server.status_details = nullptr;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = nullptr;
+  op++;
+  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
+                                nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(GRPC_SLICE_LENGTH(details) == 0);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 0);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+}
+
+static void test_no_error_on_hotpath_one_request(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+
+  f = begin_test(config, "test_invoke_simple_request_with_no_error_logging",
+                 nullptr, nullptr);
+  // First RPC is not considered the hotpath, since there are lots of things to
+  // set up.
+  simple_request_body(config, f);
+  grpc_disable_error_creation();
+  simple_request_body(config, f);
+  grpc_enable_error_creation();
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_no_error_on_hotpath_10_requests(
+    grpc_end2end_test_config config) {
+  int i;
+  grpc_end2end_test_fixture f = begin_test(
+      config, "test_no_error_on_hotpath_in_one_request", nullptr, nullptr);
+  // First RPC is not considered the hotpath, since there are lots of things to
+  // set up.
+  simple_request_body(config, f);
+  grpc_disable_error_creation();
+  for (i = 0; i < 10; i++) {
+    simple_request_body(config, f);
+  }
+  grpc_enable_error_creation();
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void no_error_on_hotpath(grpc_end2end_test_config config) {
+  test_no_error_on_hotpath_one_request(config);
+  test_no_error_on_hotpath_10_requests(config);
+}
+
+void no_error_on_hotpath_pre_init(void) {}

+ 2 - 0
test/core/gprpp/inlined_vector_test.cc

@@ -27,10 +27,12 @@ namespace testing {
 TEST(InlinedVectorTest, CreateAndIterate) {
 TEST(InlinedVectorTest, CreateAndIterate) {
   const int kNumElements = 9;
   const int kNumElements = 9;
   InlinedVector<int, 2> v;
   InlinedVector<int, 2> v;
+  EXPECT_TRUE(v.empty());
   for (int i = 0; i < kNumElements; ++i) {
   for (int i = 0; i < kNumElements; ++i) {
     v.push_back(i);
     v.push_back(i);
   }
   }
   EXPECT_EQ(static_cast<size_t>(kNumElements), v.size());
   EXPECT_EQ(static_cast<size_t>(kNumElements), v.size());
+  EXPECT_FALSE(v.empty());
   for (int i = 0; i < kNumElements; ++i) {
   for (int i = 0; i < kNumElements; ++i) {
     EXPECT_EQ(i, v[i]);
     EXPECT_EQ(i, v[i]);
     EXPECT_EQ(i, &v[i] - &v[0]);  // Ensure contiguous allocation.
     EXPECT_EQ(i, &v[i] - &v[0]);  // Ensure contiguous allocation.

+ 1 - 0
test/core/iomgr/BUILD

@@ -227,6 +227,7 @@ grpc_cc_test(
         "//test/core/util:gpr_test_util",
         "//test/core/util:gpr_test_util",
         "//test/core/util:grpc_test_util",
         "//test/core/util:grpc_test_util",
     ],
     ],
+    tags = ["manual"],    # TODO(adelez): Remove once this works on Foundry.
 )
 )
 
 
 grpc_cc_test(
 grpc_cc_test(

+ 4 - 6
test/core/iomgr/ev_epollsig_linux_test.cc

@@ -66,7 +66,7 @@ static void test_fd_init(test_fd* tfds, int* fds, int num_fds) {
 
 
   for (i = 0; i < num_fds; i++) {
   for (i = 0; i < num_fds; i++) {
     tfds[i].inner_fd = fds[i];
     tfds[i].inner_fd = fds[i];
-    tfds[i].fd = grpc_fd_create(fds[i], "test_fd");
+    tfds[i].fd = grpc_fd_create(fds[i], "test_fd", false);
   }
   }
 }
 }
 
 
@@ -79,8 +79,7 @@ static void test_fd_cleanup(test_fd* tfds, int num_fds) {
                      GRPC_ERROR_CREATE_FROM_STATIC_STRING("test_fd_cleanup"));
                      GRPC_ERROR_CREATE_FROM_STATIC_STRING("test_fd_cleanup"));
     grpc_core::ExecCtx::Get()->Flush();
     grpc_core::ExecCtx::Get()->Flush();
 
 
-    grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, false /* already_closed */,
-                   "test_fd_cleanup");
+    grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup");
     grpc_core::ExecCtx::Get()->Flush();
     grpc_core::ExecCtx::Get()->Flush();
 
 
     GPR_ASSERT(release_fd == tfds[i].inner_fd);
     GPR_ASSERT(release_fd == tfds[i].inner_fd);
@@ -267,7 +266,7 @@ static void test_threading(void) {
   grpc_wakeup_fd fd;
   grpc_wakeup_fd fd;
   GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&fd)));
   GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&fd)));
   shared.wakeup_fd = &fd;
   shared.wakeup_fd = &fd;
-  shared.wakeup_desc = grpc_fd_create(fd.read_fd, "wakeup");
+  shared.wakeup_desc = grpc_fd_create(fd.read_fd, "wakeup", false);
   shared.wakeups = 0;
   shared.wakeups = 0;
   {
   {
     grpc_core::ExecCtx exec_ctx;
     grpc_core::ExecCtx exec_ctx;
@@ -287,8 +286,7 @@ static void test_threading(void) {
   {
   {
     grpc_core::ExecCtx exec_ctx;
     grpc_core::ExecCtx exec_ctx;
     grpc_fd_shutdown(shared.wakeup_desc, GRPC_ERROR_CANCELLED);
     grpc_fd_shutdown(shared.wakeup_desc, GRPC_ERROR_CANCELLED);
-    grpc_fd_orphan(shared.wakeup_desc, nullptr, nullptr,
-                   false /* already_closed */, "done");
+    grpc_fd_orphan(shared.wakeup_desc, nullptr, nullptr, "done");
     grpc_pollset_shutdown(shared.pollset,
     grpc_pollset_shutdown(shared.pollset,
                           GRPC_CLOSURE_CREATE(destroy_pollset, shared.pollset,
                           GRPC_CLOSURE_CREATE(destroy_pollset, shared.pollset,
                                               grpc_schedule_on_exec_ctx));
                                               grpc_schedule_on_exec_ctx));

+ 8 - 8
test/core/iomgr/fd_posix_test.cc

@@ -115,7 +115,7 @@ static void session_shutdown_cb(void* arg, /*session */
                                 bool success) {
                                 bool success) {
   session* se = static_cast<session*>(arg);
   session* se = static_cast<session*>(arg);
   server* sv = se->sv;
   server* sv = se->sv;
-  grpc_fd_orphan(se->em_fd, nullptr, nullptr, false /* already_closed */, "a");
+  grpc_fd_orphan(se->em_fd, nullptr, nullptr, "a");
   gpr_free(se);
   gpr_free(se);
   /* Start to shutdown listen fd. */
   /* Start to shutdown listen fd. */
   grpc_fd_shutdown(sv->em_fd,
   grpc_fd_shutdown(sv->em_fd,
@@ -171,7 +171,7 @@ static void session_read_cb(void* arg, /*session */
 static void listen_shutdown_cb(void* arg /*server */, int success) {
 static void listen_shutdown_cb(void* arg /*server */, int success) {
   server* sv = static_cast<server*>(arg);
   server* sv = static_cast<server*>(arg);
 
 
-  grpc_fd_orphan(sv->em_fd, nullptr, nullptr, false /* already_closed */, "b");
+  grpc_fd_orphan(sv->em_fd, nullptr, nullptr, "b");
 
 
   gpr_mu_lock(g_mu);
   gpr_mu_lock(g_mu);
   sv->done = 1;
   sv->done = 1;
@@ -204,7 +204,7 @@ static void listen_cb(void* arg, /*=sv_arg*/
   fcntl(fd, F_SETFL, flags | O_NONBLOCK);
   fcntl(fd, F_SETFL, flags | O_NONBLOCK);
   se = static_cast<session*>(gpr_malloc(sizeof(*se)));
   se = static_cast<session*>(gpr_malloc(sizeof(*se)));
   se->sv = sv;
   se->sv = sv;
-  se->em_fd = grpc_fd_create(fd, "listener");
+  se->em_fd = grpc_fd_create(fd, "listener", false);
   grpc_pollset_add_fd(g_pollset, se->em_fd);
   grpc_pollset_add_fd(g_pollset, se->em_fd);
   GRPC_CLOSURE_INIT(&se->session_read_closure, session_read_cb, se,
   GRPC_CLOSURE_INIT(&se->session_read_closure, session_read_cb, se,
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
@@ -233,7 +233,7 @@ static int server_start(server* sv) {
   port = ntohs(sin.sin_port);
   port = ntohs(sin.sin_port);
   GPR_ASSERT(listen(fd, MAX_NUM_FD) == 0);
   GPR_ASSERT(listen(fd, MAX_NUM_FD) == 0);
 
 
-  sv->em_fd = grpc_fd_create(fd, "server");
+  sv->em_fd = grpc_fd_create(fd, "server", false);
   grpc_pollset_add_fd(g_pollset, sv->em_fd);
   grpc_pollset_add_fd(g_pollset, sv->em_fd);
   /* Register to be interested in reading from listen_fd. */
   /* Register to be interested in reading from listen_fd. */
   GRPC_CLOSURE_INIT(&sv->listen_closure, listen_cb, sv,
   GRPC_CLOSURE_INIT(&sv->listen_closure, listen_cb, sv,
@@ -289,7 +289,7 @@ static void client_init(client* cl) {
 /* Called when a client upload session is ready to shutdown. */
 /* Called when a client upload session is ready to shutdown. */
 static void client_session_shutdown_cb(void* arg /*client */, int success) {
 static void client_session_shutdown_cb(void* arg /*client */, int success) {
   client* cl = static_cast<client*>(arg);
   client* cl = static_cast<client*>(arg);
-  grpc_fd_orphan(cl->em_fd, nullptr, nullptr, false /* already_closed */, "c");
+  grpc_fd_orphan(cl->em_fd, nullptr, nullptr, "c");
   cl->done = 1;
   cl->done = 1;
   GPR_ASSERT(
   GPR_ASSERT(
       GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, nullptr)));
       GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, nullptr)));
@@ -353,7 +353,7 @@ static void client_start(client* cl, int port) {
     }
     }
   }
   }
 
 
-  cl->em_fd = grpc_fd_create(fd, "client");
+  cl->em_fd = grpc_fd_create(fd, "client", false);
   grpc_pollset_add_fd(g_pollset, cl->em_fd);
   grpc_pollset_add_fd(g_pollset, cl->em_fd);
 
 
   client_session_write(cl, GRPC_ERROR_NONE);
   client_session_write(cl, GRPC_ERROR_NONE);
@@ -454,7 +454,7 @@ static void test_grpc_fd_change(void) {
   flags = fcntl(sv[1], F_GETFL, 0);
   flags = fcntl(sv[1], F_GETFL, 0);
   GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
   GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
 
 
-  em_fd = grpc_fd_create(sv[0], "test_grpc_fd_change");
+  em_fd = grpc_fd_create(sv[0], "test_grpc_fd_change", false);
   grpc_pollset_add_fd(g_pollset, em_fd);
   grpc_pollset_add_fd(g_pollset, em_fd);
 
 
   /* Register the first callback, then make its FD readable */
   /* Register the first callback, then make its FD readable */
@@ -502,7 +502,7 @@ static void test_grpc_fd_change(void) {
   GPR_ASSERT(b.cb_that_ran == second_read_callback);
   GPR_ASSERT(b.cb_that_ran == second_read_callback);
   gpr_mu_unlock(g_mu);
   gpr_mu_unlock(g_mu);
 
 
-  grpc_fd_orphan(em_fd, nullptr, nullptr, false /* already_closed */, "d");
+  grpc_fd_orphan(em_fd, nullptr, nullptr, "d");
 
 
   destroy_change_data(&a);
   destroy_change_data(&a);
   destroy_change_data(&b);
   destroy_change_data(&b);

+ 2 - 3
test/core/iomgr/pollset_set_test.cc

@@ -118,7 +118,7 @@ static void init_test_fds(test_fd* tfds, const int num_fds) {
   for (int i = 0; i < num_fds; i++) {
   for (int i = 0; i < num_fds; i++) {
     GPR_ASSERT(GRPC_ERROR_NONE == grpc_wakeup_fd_init(&tfds[i].wakeup_fd));
     GPR_ASSERT(GRPC_ERROR_NONE == grpc_wakeup_fd_init(&tfds[i].wakeup_fd));
     tfds[i].fd = grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&tfds[i].wakeup_fd),
     tfds[i].fd = grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&tfds[i].wakeup_fd),
-                                "test_fd");
+                                "test_fd", false);
     reset_test_fd(&tfds[i]);
     reset_test_fd(&tfds[i]);
   }
   }
 }
 }
@@ -136,8 +136,7 @@ static void cleanup_test_fds(test_fd* tfds, const int num_fds) {
      * grpc_wakeup_fd and we would like to destroy it ourselves (by calling
      * grpc_wakeup_fd and we would like to destroy it ourselves (by calling
      * grpc_wakeup_fd_destroy). To prevent grpc_fd from calling close() on the
      * grpc_wakeup_fd_destroy). To prevent grpc_fd from calling close() on the
      * underlying fd, call it with a non-NULL 'release_fd' parameter */
      * underlying fd, call it with a non-NULL 'release_fd' parameter */
-    grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, false /* already_closed */,
-                   "test_fd_cleanup");
+    grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup");
     grpc_core::ExecCtx::Get()->Flush();
     grpc_core::ExecCtx::Get()->Flush();
 
 
     grpc_wakeup_fd_destroy(&tfds[i].wakeup_fd);
     grpc_wakeup_fd_destroy(&tfds[i].wakeup_fd);

+ 12 - 8
test/core/iomgr/tcp_posix_test.cc

@@ -176,7 +176,8 @@ static void read_test(size_t num_bytes, size_t slice_size) {
   a[0].type = GRPC_ARG_INTEGER,
   a[0].type = GRPC_ARG_INTEGER,
   a[0].value.integer = static_cast<int>(slice_size);
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), &args, "test");
+  ep =
+      grpc_tcp_create(grpc_fd_create(sv[1], "read_test", false), &args, "test");
   grpc_endpoint_add_to_pollset(ep, g_pollset);
   grpc_endpoint_add_to_pollset(ep, g_pollset);
 
 
   written_bytes = fill_socket_partial(sv[0], num_bytes);
   written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -226,7 +227,8 @@ static void large_read_test(size_t slice_size) {
   a[0].type = GRPC_ARG_INTEGER;
   a[0].type = GRPC_ARG_INTEGER;
   a[0].value.integer = static_cast<int>(slice_size);
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), &args, "test");
+  ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test", false), &args,
+                       "test");
   grpc_endpoint_add_to_pollset(ep, g_pollset);
   grpc_endpoint_add_to_pollset(ep, g_pollset);
 
 
   written_bytes = fill_socket(sv[0]);
   written_bytes = fill_socket(sv[0]);
@@ -365,7 +367,8 @@ static void write_test(size_t num_bytes, size_t slice_size) {
   a[0].type = GRPC_ARG_INTEGER,
   a[0].type = GRPC_ARG_INTEGER,
   a[0].value.integer = static_cast<int>(slice_size);
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"), &args, "test");
+  ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test", false), &args,
+                       "test");
   grpc_endpoint_add_to_pollset(ep, g_pollset);
   grpc_endpoint_add_to_pollset(ep, g_pollset);
 
 
   state.ep = ep;
   state.ep = ep;
@@ -433,7 +436,8 @@ static void release_fd_test(size_t num_bytes, size_t slice_size) {
   a[0].type = GRPC_ARG_INTEGER;
   a[0].type = GRPC_ARG_INTEGER;
   a[0].value.integer = static_cast<int>(slice_size);
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), &args, "test");
+  ep =
+      grpc_tcp_create(grpc_fd_create(sv[1], "read_test", false), &args, "test");
   GPR_ASSERT(grpc_tcp_fd(ep) == sv[1] && sv[1] >= 0);
   GPR_ASSERT(grpc_tcp_fd(ep) == sv[1] && sv[1] >= 0);
   grpc_endpoint_add_to_pollset(ep, g_pollset);
   grpc_endpoint_add_to_pollset(ep, g_pollset);
 
 
@@ -522,10 +526,10 @@ static grpc_endpoint_test_fixture create_fixture_tcp_socketpair(
   a[0].type = GRPC_ARG_INTEGER;
   a[0].type = GRPC_ARG_INTEGER;
   a[0].value.integer = static_cast<int>(slice_size);
   a[0].value.integer = static_cast<int>(slice_size);
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
   grpc_channel_args args = {GPR_ARRAY_SIZE(a), a};
-  f.client_ep =
-      grpc_tcp_create(grpc_fd_create(sv[0], "fixture:client"), &args, "test");
-  f.server_ep =
-      grpc_tcp_create(grpc_fd_create(sv[1], "fixture:server"), &args, "test");
+  f.client_ep = grpc_tcp_create(grpc_fd_create(sv[0], "fixture:client", false),
+                                &args, "test");
+  f.server_ep = grpc_tcp_create(grpc_fd_create(sv[1], "fixture:server", false),
+                                &args, "test");
   grpc_resource_quota_unref_internal(resource_quota);
   grpc_resource_quota_unref_internal(resource_quota);
   grpc_endpoint_add_to_pollset(f.client_ep, g_pollset);
   grpc_endpoint_add_to_pollset(f.client_ep, g_pollset);
   grpc_endpoint_add_to_pollset(f.server_ep, g_pollset);
   grpc_endpoint_add_to_pollset(f.server_ep, g_pollset);

+ 19 - 6
test/core/transport/status_conversion_test.cc

@@ -33,12 +33,7 @@
 #define HTTP2_STATUS_TO_GRPC_STATUS(a, b) \
 #define HTTP2_STATUS_TO_GRPC_STATUS(a, b) \
   GPR_ASSERT(grpc_http2_status_to_grpc_status(a) == (b))
   GPR_ASSERT(grpc_http2_status_to_grpc_status(a) == (b))
 
 
-int main(int argc, char** argv) {
-  int i;
-
-  grpc_test_init(argc, argv);
-  grpc_init();
-
+static void test_grpc_status_to_http2_error() {
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_OK, GRPC_HTTP2_NO_ERROR);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_OK, GRPC_HTTP2_NO_ERROR);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_CANCELLED, GRPC_HTTP2_CANCEL);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_CANCELLED, GRPC_HTTP2_CANCEL);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNKNOWN, GRPC_HTTP2_INTERNAL_ERROR);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNKNOWN, GRPC_HTTP2_INTERNAL_ERROR);
@@ -65,7 +60,9 @@ int main(int argc, char** argv) {
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNAVAILABLE,
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_UNAVAILABLE,
                              GRPC_HTTP2_REFUSED_STREAM);
                              GRPC_HTTP2_REFUSED_STREAM);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_DATA_LOSS, GRPC_HTTP2_INTERNAL_ERROR);
   GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_DATA_LOSS, GRPC_HTTP2_INTERNAL_ERROR);
+}
 
 
+static void test_grpc_status_to_http2_status() {
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_OK, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_OK, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_CANCELLED, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_CANCELLED, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNKNOWN, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNKNOWN, 200);
@@ -83,7 +80,9 @@ int main(int argc, char** argv) {
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_INTERNAL, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_INTERNAL, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNAVAILABLE, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_UNAVAILABLE, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_DATA_LOSS, 200);
   GRPC_STATUS_TO_HTTP2_STATUS(GRPC_STATUS_DATA_LOSS, 200);
+}
 
 
+static void test_http2_error_to_grpc_status() {
   const grpc_millis before_deadline = GRPC_MILLIS_INF_FUTURE;
   const grpc_millis before_deadline = GRPC_MILLIS_INF_FUTURE;
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_NO_ERROR, before_deadline,
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_NO_ERROR, before_deadline,
                              GRPC_STATUS_INTERNAL);
                              GRPC_STATUS_INTERNAL);
@@ -144,7 +143,9 @@ int main(int argc, char** argv) {
                              GRPC_STATUS_RESOURCE_EXHAUSTED);
                              GRPC_STATUS_RESOURCE_EXHAUSTED);
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_INADEQUATE_SECURITY, after_deadline,
   HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_INADEQUATE_SECURITY, after_deadline,
                              GRPC_STATUS_PERMISSION_DENIED);
                              GRPC_STATUS_PERMISSION_DENIED);
+}
 
 
+static void test_http2_status_to_grpc_status() {
   HTTP2_STATUS_TO_GRPC_STATUS(200, GRPC_STATUS_OK);
   HTTP2_STATUS_TO_GRPC_STATUS(200, GRPC_STATUS_OK);
   HTTP2_STATUS_TO_GRPC_STATUS(400, GRPC_STATUS_INVALID_ARGUMENT);
   HTTP2_STATUS_TO_GRPC_STATUS(400, GRPC_STATUS_INVALID_ARGUMENT);
   HTTP2_STATUS_TO_GRPC_STATUS(401, GRPC_STATUS_UNAUTHENTICATED);
   HTTP2_STATUS_TO_GRPC_STATUS(401, GRPC_STATUS_UNAUTHENTICATED);
@@ -157,6 +158,18 @@ int main(int argc, char** argv) {
   HTTP2_STATUS_TO_GRPC_STATUS(500, GRPC_STATUS_UNKNOWN);
   HTTP2_STATUS_TO_GRPC_STATUS(500, GRPC_STATUS_UNKNOWN);
   HTTP2_STATUS_TO_GRPC_STATUS(503, GRPC_STATUS_UNAVAILABLE);
   HTTP2_STATUS_TO_GRPC_STATUS(503, GRPC_STATUS_UNAVAILABLE);
   HTTP2_STATUS_TO_GRPC_STATUS(504, GRPC_STATUS_DEADLINE_EXCEEDED);
   HTTP2_STATUS_TO_GRPC_STATUS(504, GRPC_STATUS_DEADLINE_EXCEEDED);
+}
+
+int main(int argc, char** argv) {
+  int i;
+
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  test_grpc_status_to_http2_error();
+  test_grpc_status_to_http2_status();
+  test_http2_error_to_grpc_status();
+  test_http2_status_to_grpc_status();
 
 
   /* check all status values can be converted */
   /* check all status values can be converted */
   for (i = 0; i <= 999; i++) {
   for (i = 0; i <= 999; i++) {

+ 5 - 0
test/cpp/end2end/end2end_test.cc

@@ -1207,10 +1207,15 @@ TEST_P(End2endTest, ExpectErrorTest) {
   ResetStub();
   ResetStub();
 
 
   std::vector<ErrorStatus> expected_status;
   std::vector<ErrorStatus> expected_status;
+  expected_status.emplace_back();
+  expected_status.back().set_code(13);  // INTERNAL
+  // No Error message or details
+
   expected_status.emplace_back();
   expected_status.emplace_back();
   expected_status.back().set_code(13);  // INTERNAL
   expected_status.back().set_code(13);  // INTERNAL
   expected_status.back().set_error_message("text error message");
   expected_status.back().set_error_message("text error message");
   expected_status.back().set_binary_error_details("text error details");
   expected_status.back().set_binary_error_details("text error details");
+
   expected_status.emplace_back();
   expected_status.emplace_back();
   expected_status.back().set_code(13);  // INTERNAL
   expected_status.back().set_code(13);  // INTERNAL
   expected_status.back().set_error_message("text error message");
   expected_status.back().set_error_message("text error message");

+ 4 - 4
test/cpp/microbenchmarks/bm_pollset.cc

@@ -141,12 +141,12 @@ static void BM_PollAddFd(benchmark::State& state) {
   grpc_wakeup_fd wakeup_fd;
   grpc_wakeup_fd wakeup_fd;
   GPR_ASSERT(
   GPR_ASSERT(
       GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&wakeup_fd)));
       GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&wakeup_fd)));
-  grpc_fd* fd = grpc_fd_create(wakeup_fd.read_fd, "xxx");
+  grpc_fd* fd = grpc_fd_create(wakeup_fd.read_fd, "xxx", false);
   while (state.KeepRunning()) {
   while (state.KeepRunning()) {
     grpc_pollset_add_fd(ps, fd);
     grpc_pollset_add_fd(ps, fd);
     grpc_core::ExecCtx::Get()->Flush();
     grpc_core::ExecCtx::Get()->Flush();
   }
   }
-  grpc_fd_orphan(fd, nullptr, nullptr, false /* already_closed */, "xxx");
+  grpc_fd_orphan(fd, nullptr, nullptr, "xxx");
   grpc_closure shutdown_ps_closure;
   grpc_closure shutdown_ps_closure;
   GRPC_CLOSURE_INIT(&shutdown_ps_closure, shutdown_ps, ps,
   GRPC_CLOSURE_INIT(&shutdown_ps_closure, shutdown_ps, ps,
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
@@ -222,7 +222,7 @@ static void BM_SingleThreadPollOneFd(benchmark::State& state) {
   grpc_core::ExecCtx exec_ctx;
   grpc_core::ExecCtx exec_ctx;
   grpc_wakeup_fd wakeup_fd;
   grpc_wakeup_fd wakeup_fd;
   GRPC_ERROR_UNREF(grpc_wakeup_fd_init(&wakeup_fd));
   GRPC_ERROR_UNREF(grpc_wakeup_fd_init(&wakeup_fd));
-  grpc_fd* wakeup = grpc_fd_create(wakeup_fd.read_fd, "wakeup_read");
+  grpc_fd* wakeup = grpc_fd_create(wakeup_fd.read_fd, "wakeup_read", false);
   grpc_pollset_add_fd(ps, wakeup);
   grpc_pollset_add_fd(ps, wakeup);
   bool done = false;
   bool done = false;
   Closure* continue_closure = MakeClosure(
   Closure* continue_closure = MakeClosure(
@@ -242,7 +242,7 @@ static void BM_SingleThreadPollOneFd(benchmark::State& state) {
   while (!done) {
   while (!done) {
     GRPC_ERROR_UNREF(grpc_pollset_work(ps, nullptr, GRPC_MILLIS_INF_FUTURE));
     GRPC_ERROR_UNREF(grpc_pollset_work(ps, nullptr, GRPC_MILLIS_INF_FUTURE));
   }
   }
-  grpc_fd_orphan(wakeup, nullptr, nullptr, false /* already_closed */, "done");
+  grpc_fd_orphan(wakeup, nullptr, nullptr, "done");
   wakeup_fd.read_fd = 0;
   wakeup_fd.read_fd = 0;
   grpc_closure shutdown_ps_closure;
   grpc_closure shutdown_ps_closure;
   GRPC_CLOSURE_INIT(&shutdown_ps_closure, shutdown_ps, ps,
   GRPC_CLOSURE_INIT(&shutdown_ps_closure, shutdown_ps, ps,

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