Merge with head and resolve conflict

pull/18909/head
yang-g 6 years ago
commit 218e290074
  1. 1
      .gitignore
  2. 9
      BUILD
  3. 13
      BUILD.gn
  4. 83
      CMakeLists.txt
  5. 103
      Makefile
  6. 7
      WORKSPACE
  7. 202
      bazel/generate_cc.bzl
  8. 14
      bazel/grpc_python_deps.bzl
  9. 84
      bazel/protobuf.bzl
  10. 203
      bazel/python_rules.bzl
  11. 27
      build.yaml
  12. 4
      config.m4
  13. 4
      config.w32
  14. 2
      doc/statuscodes.md
  15. 12
      examples/BUILD
  16. 4
      examples/python/errors/client.py
  17. 4
      examples/python/errors/server.py
  18. 2
      examples/python/errors/test/_error_handling_example_test.py
  19. 17
      examples/python/multiprocessing/BUILD
  20. 11
      examples/python/wait_for_ready/wait_for_ready_example.py
  21. 9
      gRPC-C++.podspec
  22. 14
      gRPC-Core.podspec
  23. 9
      grpc.gemspec
  24. 7
      grpc.gyp
  25. 3
      include/grpc/impl/codegen/port_platform.h
  26. 3
      include/grpc/impl/codegen/status.h
  27. 2
      include/grpc/support/alloc.h
  28. 3
      include/grpcpp/impl/codegen/status_code_enum.h
  29. 9
      package.xml
  30. 27
      src/core/ext/filters/client_channel/backup_poller.cc
  31. 3
      src/core/ext/filters/client_channel/backup_poller.h
  32. 14
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  33. 6
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
  34. 179
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
  35. 4
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
  36. 4
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
  37. 52
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
  38. 83
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc
  39. 34
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h
  40. 51
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
  41. 22
      src/core/ext/filters/client_channel/subchannel.cc
  42. 13
      src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
  43. 79
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  44. 6
      src/core/ext/transport/chttp2/transport/hpack_parser.cc
  45. 35
      src/core/ext/transport/chttp2/transport/internal.h
  46. 63
      src/core/ext/transport/chttp2/transport/writing.cc
  47. 43
      src/core/lib/channel/channel_stack.cc
  48. 73
      src/core/lib/gpr/alloc.cc
  49. 10
      src/core/lib/gpr/alloc.h
  50. 3
      src/core/lib/gpr/env.h
  51. 5
      src/core/lib/gpr/env_linux.cc
  52. 5
      src/core/lib/gpr/env_posix.cc
  53. 7
      src/core/lib/gpr/env_windows.cc
  54. 18
      src/core/lib/gpr/string.cc
  55. 6
      src/core/lib/gpr/string.h
  56. 8
      src/core/lib/gprpp/arena.cc
  57. 6
      src/core/lib/gprpp/arena.h
  58. 87
      src/core/lib/gprpp/global_config.h
  59. 29
      src/core/lib/gprpp/global_config_custom.h
  60. 135
      src/core/lib/gprpp/global_config_env.cc
  61. 131
      src/core/lib/gprpp/global_config_env.h
  62. 44
      src/core/lib/gprpp/global_config_generic.h
  63. 2
      src/core/lib/iomgr/combiner.h
  64. 5
      src/core/lib/iomgr/ev_epoll1_linux.cc
  65. 10
      src/core/lib/iomgr/iomgr.cc
  66. 12
      src/core/lib/security/security_connector/ssl_utils.cc
  67. 5
      src/core/lib/slice/slice_buffer.cc
  68. 2
      src/core/lib/slice/slice_internal.h
  69. 6
      src/core/lib/surface/call.cc
  70. 12
      src/core/lib/transport/error_utils.cc
  71. 2
      src/core/lib/transport/transport.cc
  72. 19
      src/csharp/Grpc.Core.Api/DeserializationContext.cs
  73. 8
      src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj
  74. 0
      src/csharp/Grpc.Core.Api/Interceptors/ClientInterceptorContext.cs
  75. 0
      src/csharp/Grpc.Core.Api/Interceptors/Interceptor.cs
  76. 3
      src/csharp/Grpc.Core.Api/StatusCode.cs
  77. 4
      src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
  78. 12
      src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
  79. 49
      src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
  80. 240
      src/csharp/Grpc.Core.Tests/Internal/DefaultDeserializationContextTest.cs
  81. 118
      src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManager.cs
  82. 121
      src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManagerTest.cs
  83. 151
      src/csharp/Grpc.Core.Tests/Internal/ReusableSliceBufferTest.cs
  84. 83
      src/csharp/Grpc.Core.Tests/Internal/SliceTest.cs
  85. 11
      src/csharp/Grpc.Core/ForwardedTypes.cs
  86. 9
      src/csharp/Grpc.Core/Grpc.Core.csproj
  87. 10
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  88. 17
      src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
  89. 44
      src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
  90. 4
      src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
  91. 61
      src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs
  92. 4
      src/csharp/Grpc.Core/Internal/INativeCall.cs
  93. 14
      src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
  94. 148
      src/csharp/Grpc.Core/Internal/ReusableSliceBuffer.cs
  95. 68
      src/csharp/Grpc.Core/Internal/Slice.cs
  96. 1
      src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets
  97. 54
      src/csharp/ext/grpc_csharp_ext.c
  98. 4
      src/csharp/tests.json
  99. 2
      src/csharp/unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/grpc_csharp_ext_dummy_stubs.c
  100. 3
      src/objective-c/GRPCClient/GRPCCall.h
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -115,6 +115,7 @@ bazel-genfiles
bazel-grpc
bazel-out
bazel-testlogs
bazel_format_virtual_environment/
# Debug output
gdb.txt

@ -580,6 +580,7 @@ grpc_cc_library(
"src/core/lib/gpr/wrap_memcpy.cc",
"src/core/lib/gprpp/arena.cc",
"src/core/lib/gprpp/fork.cc",
"src/core/lib/gprpp/global_config_env.cc",
"src/core/lib/gprpp/thd_posix.cc",
"src/core/lib/gprpp/thd_windows.cc",
"src/core/lib/profiling/basic_timers.cc",
@ -606,6 +607,10 @@ grpc_cc_library(
"src/core/lib/gprpp/arena.h",
"src/core/lib/gprpp/atomic.h",
"src/core/lib/gprpp/fork.h",
"src/core/lib/gprpp/global_config_custom.h",
"src/core/lib/gprpp/global_config_env.h",
"src/core/lib/gprpp/global_config_generic.h",
"src/core/lib/gprpp/global_config.h",
"src/core/lib/gprpp/manual_constructor.h",
"src/core/lib/gprpp/map.h",
"src/core/lib/gprpp/memory.h",
@ -1573,16 +1578,20 @@ grpc_cc_library(
srcs = [
"src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc",
],
hdrs = [
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h",
],
external_deps = [
"cares",

@ -184,6 +184,11 @@ config("grpc_config") {
"src/core/lib/gprpp/atomic.h",
"src/core/lib/gprpp/fork.cc",
"src/core/lib/gprpp/fork.h",
"src/core/lib/gprpp/global_config.h",
"src/core/lib/gprpp/global_config_custom.h",
"src/core/lib/gprpp/global_config_env.cc",
"src/core/lib/gprpp/global_config_env.h",
"src/core/lib/gprpp/global_config_generic.h",
"src/core/lib/gprpp/manual_constructor.h",
"src/core/lib/gprpp/map.h",
"src/core/lib/gprpp/memory.h",
@ -310,11 +315,15 @@ config("grpc_config") {
"src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc",
@ -1173,6 +1182,10 @@ config("grpc_config") {
"src/core/lib/gprpp/atomic.h",
"src/core/lib/gprpp/debug_location.h",
"src/core/lib/gprpp/fork.h",
"src/core/lib/gprpp/global_config.h",
"src/core/lib/gprpp/global_config_custom.h",
"src/core/lib/gprpp/global_config_env.h",
"src/core/lib/gprpp/global_config_generic.h",
"src/core/lib/gprpp/inlined_vector.h",
"src/core/lib/gprpp/manual_constructor.h",
"src/core/lib/gprpp/map.h",

@ -629,6 +629,8 @@ add_dependencies(buildtests_cxx error_details_test)
add_dependencies(buildtests_cxx exception_test)
add_dependencies(buildtests_cxx filter_end2end_test)
add_dependencies(buildtests_cxx generic_end2end_test)
add_dependencies(buildtests_cxx global_config_env_test)
add_dependencies(buildtests_cxx global_config_test)
add_dependencies(buildtests_cxx golden_file_test)
add_dependencies(buildtests_cxx grpc_alts_credentials_options_test)
add_dependencies(buildtests_cxx grpc_cli)
@ -874,6 +876,7 @@ add_library(gpr
src/core/lib/gpr/wrap_memcpy.cc
src/core/lib/gprpp/arena.cc
src/core/lib/gprpp/fork.cc
src/core/lib/gprpp/global_config_env.cc
src/core/lib/gprpp/thd_posix.cc
src/core/lib/gprpp/thd_windows.cc
src/core/lib/profiling/basic_timers.cc
@ -1290,10 +1293,13 @@ add_library(grpc
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@ -2683,10 +2689,13 @@ add_library(grpc_unsecure
src/core/ext/transport/inproc/inproc_transport.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@ -13435,6 +13444,80 @@ target_link_libraries(generic_end2end_test
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(global_config_env_test
test/core/gprpp/global_config_env_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(global_config_env_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 ${_gRPC_NANOPB_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(global_config_env_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
gpr
grpc_test_util_unsecure
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(global_config_test
test/core/gprpp/global_config_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(global_config_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 ${_gRPC_NANOPB_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(global_config_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
gpr
grpc_test_util_unsecure
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)

@ -1206,6 +1206,8 @@ error_details_test: $(BINDIR)/$(CONFIG)/error_details_test
exception_test: $(BINDIR)/$(CONFIG)/exception_test
filter_end2end_test: $(BINDIR)/$(CONFIG)/filter_end2end_test
generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
global_config_env_test: $(BINDIR)/$(CONFIG)/global_config_env_test
global_config_test: $(BINDIR)/$(CONFIG)/global_config_test
golden_file_test: $(BINDIR)/$(CONFIG)/golden_file_test
grpc_alts_credentials_options_test: $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test
grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli
@ -1683,6 +1685,8 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/exception_test \
$(BINDIR)/$(CONFIG)/filter_end2end_test \
$(BINDIR)/$(CONFIG)/generic_end2end_test \
$(BINDIR)/$(CONFIG)/global_config_env_test \
$(BINDIR)/$(CONFIG)/global_config_test \
$(BINDIR)/$(CONFIG)/golden_file_test \
$(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \
$(BINDIR)/$(CONFIG)/grpc_cli \
@ -1828,6 +1832,8 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/exception_test \
$(BINDIR)/$(CONFIG)/filter_end2end_test \
$(BINDIR)/$(CONFIG)/generic_end2end_test \
$(BINDIR)/$(CONFIG)/global_config_env_test \
$(BINDIR)/$(CONFIG)/global_config_test \
$(BINDIR)/$(CONFIG)/golden_file_test \
$(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \
$(BINDIR)/$(CONFIG)/grpc_cli \
@ -2321,6 +2327,10 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/filter_end2end_test || ( echo test filter_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing generic_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing global_config_env_test"
$(Q) $(BINDIR)/$(CONFIG)/global_config_env_test || ( echo test global_config_env_test failed ; exit 1 )
$(E) "[RUN] Testing global_config_test"
$(Q) $(BINDIR)/$(CONFIG)/global_config_test || ( echo test global_config_test failed ; exit 1 )
$(E) "[RUN] Testing golden_file_test"
$(Q) $(BINDIR)/$(CONFIG)/golden_file_test || ( echo test golden_file_test failed ; exit 1 )
$(E) "[RUN] Testing grpc_alts_credentials_options_test"
@ -3359,6 +3369,7 @@ LIBGPR_SRC = \
src/core/lib/gpr/wrap_memcpy.cc \
src/core/lib/gprpp/arena.cc \
src/core/lib/gprpp/fork.cc \
src/core/lib/gprpp/global_config_env.cc \
src/core/lib/gprpp/thd_posix.cc \
src/core/lib/gprpp/thd_windows.cc \
src/core/lib/profiling/basic_timers.cc \
@ -3754,10 +3765,13 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \
@ -5095,10 +5109,13 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/transport/inproc/inproc_transport.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \
@ -16407,6 +16424,92 @@ endif
endif
GLOBAL_CONFIG_ENV_TEST_SRC = \
test/core/gprpp/global_config_env_test.cc \
GLOBAL_CONFIG_ENV_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GLOBAL_CONFIG_ENV_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/global_config_env_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)/global_config_env_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/global_config_env_test: $(PROTOBUF_DEP) $(GLOBAL_CONFIG_ENV_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(GLOBAL_CONFIG_ENV_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/global_config_env_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/gprpp/global_config_env_test.o: $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
deps_global_config_env_test: $(GLOBAL_CONFIG_ENV_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GLOBAL_CONFIG_ENV_TEST_OBJS:.o=.dep)
endif
endif
GLOBAL_CONFIG_TEST_SRC = \
test/core/gprpp/global_config_test.cc \
GLOBAL_CONFIG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GLOBAL_CONFIG_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/global_config_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)/global_config_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/global_config_test: $(PROTOBUF_DEP) $(GLOBAL_CONFIG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(GLOBAL_CONFIG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/global_config_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/gprpp/global_config_test.o: $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
deps_global_config_test: $(GLOBAL_CONFIG_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GLOBAL_CONFIG_TEST_OBJS:.o=.dep)
endif
endif
GOLDEN_FILE_TEST_SRC = \
$(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc \
test/cpp/codegen/golden_file_test.cc \

@ -18,13 +18,6 @@ register_toolchains(
"//third_party/toolchains/bazel_0.23.2_rbe_windows:cc-toolchain-x64_windows",
)
# TODO(https://github.com/grpc/grpc/issues/18331): Move off of this dependency.
git_repository(
name = "org_pubref_rules_protobuf",
remote = "https://github.com/ghostwriternr/rules_protobuf",
tag = "v0.8.2.1-alpha",
)
git_repository(
name = "io_bazel_rules_python",
commit = "8b5d0683a7d878b28fffe464779c8a53659fc645",

@ -4,81 +4,132 @@ This is an internal rule used by cc_grpc_library, and shouldn't be used
directly.
"""
def generate_cc_impl(ctx):
"""Implementation of the generate_cc rule."""
protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources]
includes = [f for src in ctx.attr.srcs for f in src.proto.transitive_imports]
outs = []
# label_len is length of the path from WORKSPACE root to the location of this build file
label_len = 0
# proto_root is the directory relative to which generated include paths should be
proto_root = ""
if ctx.label.package:
# The +1 is for the trailing slash.
label_len += len(ctx.label.package) + 1
if ctx.label.workspace_root:
label_len += len(ctx.label.workspace_root) + 1
proto_root = "/" + ctx.label.workspace_root
load(
"//bazel:protobuf.bzl",
"get_include_protoc_args",
"get_plugin_args",
"get_proto_root",
"proto_path_to_generated_filename",
)
_GRPC_PROTO_HEADER_FMT = "{}.grpc.pb.h"
_GRPC_PROTO_SRC_FMT = "{}.grpc.pb.cc"
_GRPC_PROTO_MOCK_HEADER_FMT = "{}_mock.grpc.pb.h"
_PROTO_HEADER_FMT = "{}.pb.h"
_PROTO_SRC_FMT = "{}.pb.cc"
if ctx.executable.plugin:
outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.h" for proto in protos]
outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.cc" for proto in protos]
if ctx.attr.generate_mocks:
outs += [proto.path[label_len:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos]
else:
outs += [proto.path[label_len:-len(".proto")] + ".pb.h" for proto in protos]
outs += [proto.path[label_len:-len(".proto")] + ".pb.cc" for proto in protos]
out_files = [ctx.actions.declare_file(out) for out in outs]
dir_out = str(ctx.genfiles_dir.path + proto_root)
def _strip_package_from_path(label_package, path):
if len(label_package) == 0:
return path
if not path.startswith(label_package + "/"):
fail("'{}' does not lie within '{}'.".format(path, label_package))
return path[len(label_package + "/"):]
arguments = []
if ctx.executable.plugin:
arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path]
flags = list(ctx.attr.flags)
if ctx.attr.generate_mocks:
flags.append("generate_mock_code=true")
arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out]
tools = [ctx.executable.plugin]
else:
arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
tools = []
def _join_directories(directories):
massaged_directories = [directory for directory in directories if len(directory) != 0]
return "/".join(massaged_directories)
# Import protos relative to their workspace root so that protoc prints the
# right include paths.
for include in includes:
directory = include.path
if directory.startswith("external"):
external_sep = directory.find("/")
repository_sep = directory.find("/", external_sep + 1)
arguments += ["--proto_path=" + directory[:repository_sep]]
def generate_cc_impl(ctx):
"""Implementation of the generate_cc rule."""
protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources]
includes = [
f
for src in ctx.attr.srcs
for f in src.proto.transitive_imports
]
outs = []
proto_root = get_proto_root(
ctx.label.workspace_root,
)
label_package = _join_directories([ctx.label.workspace_root, ctx.label.package])
if ctx.executable.plugin:
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_GRPC_PROTO_HEADER_FMT,
)
for proto in protos
]
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_GRPC_PROTO_SRC_FMT,
)
for proto in protos
]
if ctx.attr.generate_mocks:
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_GRPC_PROTO_MOCK_HEADER_FMT,
)
for proto in protos
]
else:
arguments += ["--proto_path=."]
# Include the output directory so that protoc puts the generated code in the
# right directory.
arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
arguments += [proto.path for proto in protos]
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_PROTO_HEADER_FMT,
)
for proto in protos
]
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_PROTO_SRC_FMT,
)
for proto in protos
]
out_files = [ctx.actions.declare_file(out) for out in outs]
dir_out = str(ctx.genfiles_dir.path + proto_root)
# create a list of well known proto files if the argument is non-None
well_known_proto_files = []
if ctx.attr.well_known_protos:
f = ctx.attr.well_known_protos.files.to_list()[0].dirname
if f != "external/com_google_protobuf/src/google/protobuf":
print("Error: Only @com_google_protobuf//:well_known_protos is supported")
arguments = []
if ctx.executable.plugin:
arguments += get_plugin_args(
ctx.executable.plugin,
ctx.attr.flags,
dir_out,
ctx.attr.generate_mocks,
)
tools = [ctx.executable.plugin]
else:
# f points to "external/com_google_protobuf/src/google/protobuf"
# add -I argument to protoc so it knows where to look for the proto files.
arguments += ["-I{0}".format(f + "/../..")]
well_known_proto_files = [f for f in ctx.attr.well_known_protos.files]
arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
tools = []
arguments += get_include_protoc_args(includes)
ctx.actions.run(
inputs = protos + includes + well_known_proto_files,
tools = tools,
outputs = out_files,
executable = ctx.executable._protoc,
arguments = arguments,
)
# Include the output directory so that protoc puts the generated code in the
# right directory.
arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
arguments += [proto.path for proto in protos]
return struct(files=depset(out_files))
# create a list of well known proto files if the argument is non-None
well_known_proto_files = []
if ctx.attr.well_known_protos:
f = ctx.attr.well_known_protos.files.to_list()[0].dirname
if f != "external/com_google_protobuf/src/google/protobuf":
print(
"Error: Only @com_google_protobuf//:well_known_protos is supported",
)
else:
# f points to "external/com_google_protobuf/src/google/protobuf"
# add -I argument to protoc so it knows where to look for the proto files.
arguments += ["-I{0}".format(f + "/../..")]
well_known_proto_files = [
f
for f in ctx.attr.well_known_protos.files
]
ctx.actions.run(
inputs = protos + includes + well_known_proto_files,
tools = tools,
outputs = out_files,
executable = ctx.executable._protoc,
arguments = arguments,
)
return struct(files = depset(out_files))
_generate_cc = rule(
attrs = {
@ -96,10 +147,8 @@ _generate_cc = rule(
mandatory = False,
allow_empty = True,
),
"well_known_protos" : attr.label(
mandatory = False,
),
"generate_mocks" : attr.bool(
"well_known_protos": attr.label(mandatory = False),
"generate_mocks": attr.bool(
default = False,
mandatory = False,
),
@ -115,7 +164,10 @@ _generate_cc = rule(
)
def generate_cc(well_known_protos, **kwargs):
if well_known_protos:
_generate_cc(well_known_protos="@com_google_protobuf//:well_known_protos", **kwargs)
else:
_generate_cc(**kwargs)
if well_known_protos:
_generate_cc(
well_known_protos = "@com_google_protobuf//:well_known_protos",
**kwargs
)
else:
_generate_cc(**kwargs)

@ -1,16 +1,8 @@
load("//third_party/py:python_configure.bzl", "python_configure")
load("@io_bazel_rules_python//python:pip.bzl", "pip_repositories")
load("@grpc_python_dependencies//:requirements.bzl", "pip_install")
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_repositories")
def grpc_python_deps():
# TODO(https://github.com/grpc/grpc/issues/18256): Remove conditional.
if hasattr(native, "http_archive"):
python_configure(name = "local_config_python")
pip_repositories()
pip_install()
py_proto_repositories()
else:
print("Building Python gRPC with bazel 23.0+ is disabled pending " +
"resolution of https://github.com/grpc/grpc/issues/18256.")
python_configure(name = "local_config_python")
pip_repositories()
pip_install()

@ -0,0 +1,84 @@
"""Utility functions for generating protobuf code."""
_PROTO_EXTENSION = ".proto"
def get_proto_root(workspace_root):
"""Gets the root protobuf directory.
Args:
workspace_root: context.label.workspace_root
Returns:
The directory relative to which generated include paths should be.
"""
if workspace_root:
return "/{}".format(workspace_root)
else:
return ""
def _strip_proto_extension(proto_filename):
if not proto_filename.endswith(_PROTO_EXTENSION):
fail('"{}" does not end with "{}"'.format(
proto_filename,
_PROTO_EXTENSION,
))
return proto_filename[:-len(_PROTO_EXTENSION)]
def proto_path_to_generated_filename(proto_path, fmt_str):
"""Calculates the name of a generated file for a protobuf path.
For example, "examples/protos/helloworld.proto" might map to
"helloworld.pb.h".
Args:
proto_path: The path to the .proto file.
fmt_str: A format string used to calculate the generated filename. For
example, "{}.pb.h" might be used to calculate a C++ header filename.
Returns:
The generated filename.
"""
return fmt_str.format(_strip_proto_extension(proto_path))
def _get_include_directory(include):
directory = include.path
if directory.startswith("external"):
external_separator = directory.find("/")
repository_separator = directory.find("/", external_separator + 1)
return directory[:repository_separator]
else:
return "."
def get_include_protoc_args(includes):
"""Returns protoc args that imports protos relative to their import root.
Args:
includes: A list of included proto files.
Returns:
A list of arguments to be passed to protoc. For example, ["--proto_path=."].
"""
return [
"--proto_path={}".format(_get_include_directory(include))
for include in includes
]
def get_plugin_args(plugin, flags, dir_out, generate_mocks):
"""Returns arguments configuring protoc to use a plugin for a language.
Args:
plugin: An executable file to run as the protoc plugin.
flags: The plugin flags to be passed to protoc.
dir_out: The output directory for the plugin.
generate_mocks: A bool indicating whether to generate mocks.
Returns:
A list of protoc arguments configuring the plugin.
"""
augmented_flags = list(flags)
if generate_mocks:
augmented_flags.append("generate_mock_code=true")
return [
"--plugin=protoc-gen-PLUGIN=" + plugin.path,
"--PLUGIN_out=" + ",".join(augmented_flags) + ":" + dir_out,
]

@ -0,0 +1,203 @@
"""Generates and compiles Python gRPC stubs from proto_library rules."""
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load(
"//bazel:protobuf.bzl",
"get_include_protoc_args",
"get_plugin_args",
"get_proto_root",
"proto_path_to_generated_filename",
)
_GENERATED_PROTO_FORMAT = "{}_pb2.py"
_GENERATED_GRPC_PROTO_FORMAT = "{}_pb2_grpc.py"
def _get_staged_proto_file(context, source_file):
if source_file.dirname == context.label.package:
return source_file
else:
copied_proto = context.actions.declare_file(source_file.basename)
context.actions.run_shell(
inputs = [source_file],
outputs = [copied_proto],
command = "cp {} {}".format(source_file.path, copied_proto.path),
mnemonic = "CopySourceProto",
)
return copied_proto
def _generate_py_impl(context):
protos = []
for src in context.attr.deps:
for file in src.proto.direct_sources:
protos.append(_get_staged_proto_file(context, file))
includes = [
file
for src in context.attr.deps
for file in src.proto.transitive_imports
]
proto_root = get_proto_root(context.label.workspace_root)
format_str = (_GENERATED_GRPC_PROTO_FORMAT if context.executable.plugin else _GENERATED_PROTO_FORMAT)
out_files = [
context.actions.declare_file(
proto_path_to_generated_filename(
proto.basename,
format_str,
),
)
for proto in protos
]
arguments = []
tools = [context.executable._protoc]
if context.executable.plugin:
arguments += get_plugin_args(
context.executable.plugin,
context.attr.flags,
context.genfiles_dir.path,
False,
)
tools += [context.executable.plugin]
else:
arguments += [
"--python_out={}:{}".format(
",".join(context.attr.flags),
context.genfiles_dir.path,
),
]
arguments += get_include_protoc_args(includes)
arguments += [
"--proto_path={}".format(context.genfiles_dir.path)
for proto in protos
]
for proto in protos:
massaged_path = proto.path
if massaged_path.startswith(context.genfiles_dir.path):
massaged_path = proto.path[len(context.genfiles_dir.path) + 1:]
arguments.append(massaged_path)
well_known_proto_files = []
if context.attr.well_known_protos:
well_known_proto_directory = context.attr.well_known_protos.files.to_list(
)[0].dirname
arguments += ["-I{}".format(well_known_proto_directory + "/../..")]
well_known_proto_files = context.attr.well_known_protos.files.to_list()
context.actions.run(
inputs = protos + includes + well_known_proto_files,
tools = tools,
outputs = out_files,
executable = context.executable._protoc,
arguments = arguments,
mnemonic = "ProtocInvocation",
)
return struct(files = depset(out_files))
__generate_py = rule(
attrs = {
"deps": attr.label_list(
mandatory = True,
allow_empty = False,
providers = ["proto"],
),
"plugin": attr.label(
executable = True,
providers = ["files_to_run"],
cfg = "host",
),
"flags": attr.string_list(
mandatory = False,
allow_empty = True,
),
"well_known_protos": attr.label(mandatory = False),
"_protoc": attr.label(
default = Label("//external:protocol_compiler"),
executable = True,
cfg = "host",
),
},
output_to_genfiles = True,
implementation = _generate_py_impl,
)
def _generate_py(well_known_protos, **kwargs):
if well_known_protos:
__generate_py(
well_known_protos = "@com_google_protobuf//:well_known_protos",
**kwargs
)
else:
__generate_py(**kwargs)
_WELL_KNOWN_PROTO_LIBS = [
"@com_google_protobuf//:any_proto",
"@com_google_protobuf//:api_proto",
"@com_google_protobuf//:compiler_plugin_proto",
"@com_google_protobuf//:descriptor_proto",
"@com_google_protobuf//:duration_proto",
"@com_google_protobuf//:empty_proto",
"@com_google_protobuf//:field_mask_proto",
"@com_google_protobuf//:source_context_proto",
"@com_google_protobuf//:struct_proto",
"@com_google_protobuf//:timestamp_proto",
"@com_google_protobuf//:type_proto",
"@com_google_protobuf//:wrappers_proto",
]
def py_proto_library(
name,
deps,
well_known_protos = True,
proto_only = False,
**kwargs):
"""Generate python code for a protobuf.
Args:
name: The name of the target.
deps: A list of dependencies. Must contain a single element.
well_known_protos: A bool indicating whether or not to include well-known
protos.
proto_only: A bool indicating whether to generate vanilla protobuf code
or to also generate gRPC code.
"""
if len(deps) > 1:
fail("The supported length of 'deps' is 1.")
codegen_target = "_{}_codegen".format(name)
codegen_grpc_target = "_{}_grpc_codegen".format(name)
well_known_proto_rules = _WELL_KNOWN_PROTO_LIBS if well_known_protos else []
_generate_py(
name = codegen_target,
deps = deps,
well_known_protos = well_known_protos,
**kwargs
)
if not proto_only:
_generate_py(
name = codegen_grpc_target,
deps = deps,
plugin = "//:grpc_python_plugin",
well_known_protos = well_known_protos,
**kwargs
)
native.py_library(
name = name,
srcs = [
":{}".format(codegen_grpc_target),
":{}".format(codegen_target),
],
deps = [requirement("protobuf")],
**kwargs
)
else:
native.py_library(
name = name,
srcs = [":{}".format(codegen_target), ":{}".format(codegen_target)],
deps = [requirement("protobuf")],
**kwargs
)

@ -148,6 +148,7 @@ filegroups:
- src/core/lib/gpr/wrap_memcpy.cc
- src/core/lib/gprpp/arena.cc
- src/core/lib/gprpp/fork.cc
- src/core/lib/gprpp/global_config_env.cc
- src/core/lib/gprpp/thd_posix.cc
- src/core/lib/gprpp/thd_windows.cc
- src/core/lib/profiling/basic_timers.cc
@ -194,6 +195,10 @@ filegroups:
- src/core/lib/gprpp/arena.h
- src/core/lib/gprpp/atomic.h
- src/core/lib/gprpp/fork.h
- src/core/lib/gprpp/global_config.h
- src/core/lib/gprpp/global_config_custom.h
- src/core/lib/gprpp/global_config_env.h
- src/core/lib/gprpp/global_config_generic.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/map.h
- src/core/lib/gprpp/memory.h
@ -775,13 +780,17 @@ filegroups:
headers:
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h
src:
- src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
plugin: grpc_resolver_dns_ares
@ -4727,6 +4736,24 @@ targets:
- grpc++
- grpc
- gpr
- name: global_config_env_test
build: test
language: c++
src:
- test/core/gprpp/global_config_env_test.cc
deps:
- gpr
- grpc_test_util_unsecure
uses_polling: false
- name: global_config_test
build: test
language: c++
src:
- test/core/gprpp/global_config_test.cc
deps:
- gpr
- grpc_test_util_unsecure
uses_polling: false
- name: golden_file_test
gtest: true
build: test

@ -79,6 +79,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/gpr/wrap_memcpy.cc \
src/core/lib/gprpp/arena.cc \
src/core/lib/gprpp/fork.cc \
src/core/lib/gprpp/global_config_env.cc \
src/core/lib/gprpp/thd_posix.cc \
src/core/lib/gprpp/thd_windows.cc \
src/core/lib/profiling/basic_timers.cc \
@ -402,10 +403,13 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \

@ -54,6 +54,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\gpr\\wrap_memcpy.cc " +
"src\\core\\lib\\gprpp\\arena.cc " +
"src\\core\\lib\\gprpp\\fork.cc " +
"src\\core\\lib\\gprpp\\global_config_env.cc " +
"src\\core\\lib\\gprpp\\thd_posix.cc " +
"src\\core\\lib\\gprpp\\thd_windows.cc " +
"src\\core\\lib\\profiling\\basic_timers.cc " +
@ -377,10 +378,13 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin\\round_robin.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_libuv.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_posix.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_windows.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_fallback.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_libuv.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_libuv_windows.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_posix.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_windows.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\native\\dns_resolver.cc " +

@ -20,7 +20,7 @@ statuses are defined as such:
| OUT_OF_RANGE | 11 | The operation was attempted past the valid range. E.g., seeking or reading past end-of-file. Unlike `INVALID_ARGUMENT`, this error indicates a problem that may be fixed if the system state changes. For example, a 32-bit file system will generate `INVALID_ARGUMENT` if asked to read at an offset that is not in the range [0,2^32-1], but it will generate `OUT_OF_RANGE` if asked to read from an offset past the current file size. There is a fair bit of overlap between `FAILED_PRECONDITION` and `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific error) when it applies so that callers who are iterating through a space can easily look for an `OUT_OF_RANGE` error to detect when they are done. | 400 Bad Request |
| UNIMPLEMENTED | 12 | The operation is not implemented or is not supported/enabled in this service. | 501 Not Implemented |
| INTERNAL | 13 | Internal errors. This means that some invariants expected by the underlying system have been broken. This error code is reserved for serious errors. | 500 Internal Server Error |
| UNAVAILABLE | 14 | The service is currently unavailable. This is most likely a transient condition, which can be corrected by retrying with a backoff. | 503 Service Unavailable |
| UNAVAILABLE | 14 | The service is currently unavailable. This is most likely a transient condition, which can be corrected by retrying with a backoff. Note that it is not always safe to retry non-idempotent operations. | 503 Service Unavailable |
| DATA_LOSS | 15 | Unrecoverable data loss or corruption. | 500 Internal Server Error |
All RPCs started at a client return a `status` object composed of an integer

@ -16,9 +16,8 @@ licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//visibility:public"])
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
load("//bazel:python_rules.bzl", "py_proto_library")
grpc_proto_library(
name = "auth_sample",
@ -45,11 +44,14 @@ grpc_proto_library(
srcs = ["protos/keyvaluestore.proto"],
)
proto_library(
name = "helloworld_proto_descriptor",
srcs = ["protos/helloworld.proto"],
)
py_proto_library(
name = "py_helloworld",
protos = ["protos/helloworld.proto"],
with_grpc = True,
deps = [requirement('protobuf'),],
deps = [":helloworld_proto_descriptor"],
)
cc_binary(

@ -20,8 +20,8 @@ import grpc
from grpc_status import rpc_status
from google.rpc import error_details_pb2
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
from examples import helloworld_pb2
from examples import helloworld_pb2_grpc
_LOGGER = logging.getLogger(__name__)

@ -24,8 +24,8 @@ from grpc_status import rpc_status
from google.protobuf import any_pb2
from google.rpc import code_pb2, status_pb2, error_details_pb2
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
from examples import helloworld_pb2
from examples import helloworld_pb2_grpc
_ONE_DAY_IN_SECONDS = 60 * 60 * 24

@ -26,7 +26,7 @@ import logging
import grpc
from examples.protos import helloworld_pb2_grpc
from examples import helloworld_pb2_grpc
from examples.python.errors import client as error_handling_client
from examples.python.errors import server as error_handling_server

@ -15,12 +15,17 @@
# limitations under the License.
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
load("//bazel:python_rules.bzl", "py_proto_library")
py_proto_library(
proto_library(
name = "prime_proto",
protos = ["prime.proto",],
deps = [requirement("protobuf")],
srcs = ["prime.proto"]
)
py_proto_library(
name = "prime_proto_pb2",
deps = [":prime_proto"],
well_known_protos = False,
)
py_binary(
@ -29,7 +34,7 @@ py_binary(
srcs = ["client.py"],
deps = [
"//src/python/grpcio/grpc:grpcio",
":prime_proto",
":prime_proto_pb2",
],
default_python_version = "PY3",
)
@ -40,7 +45,7 @@ py_binary(
srcs = ["server.py"],
deps = [
"//src/python/grpcio/grpc:grpcio",
":prime_proto"
":prime_proto_pb2"
] + select({
"//conditions:default": [requirement("futures")],
"//:python3": [],

@ -22,8 +22,8 @@ import threading
import grpc
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
from examples import helloworld_pb2
from examples import helloworld_pb2_grpc
_LOGGER = logging.getLogger(__name__)
_LOGGER.setLevel(logging.INFO)
@ -33,10 +33,13 @@ _ONE_DAY_IN_SECONDS = 60 * 60 * 24
@contextmanager
def get_free_loopback_tcp_port():
tcp_socket = socket.socket(socket.AF_INET6)
if socket.has_ipv6:
tcp_socket = socket.socket(socket.AF_INET6)
else:
tcp_socket = socket.socket(socket.AF_INET)
tcp_socket.bind(('', 0))
address_tuple = tcp_socket.getsockname()
yield "[::1]:%s" % (address_tuple[1])
yield "localhost:%s" % (address_tuple[1])
tcp_socket.close()

@ -272,6 +272,10 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/global_config.h',
'src/core/lib/gprpp/global_config_custom.h',
'src/core/lib/gprpp/global_config_env.h',
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/map.h',
'src/core/lib/gprpp/memory.h',
@ -558,6 +562,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h',
'src/core/ext/filters/max_age/max_age_filter.h',
'src/core/ext/filters/message_size/message_size_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',
@ -595,6 +600,10 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/global_config.h',
'src/core/lib/gprpp/global_config_custom.h',
'src/core/lib/gprpp/global_config_env.h',
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/map.h',
'src/core/lib/gprpp/memory.h',

@ -208,6 +208,10 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/global_config.h',
'src/core/lib/gprpp/global_config_custom.h',
'src/core/lib/gprpp/global_config_env.h',
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/map.h',
'src/core/lib/gprpp/memory.h',
@ -250,6 +254,7 @@ Pod::Spec.new do |s|
'src/core/lib/gpr/wrap_memcpy.cc',
'src/core/lib/gprpp/arena.cc',
'src/core/lib/gprpp/fork.cc',
'src/core/lib/gprpp/global_config_env.cc',
'src/core/lib/gprpp/thd_posix.cc',
'src/core/lib/gprpp/thd_windows.cc',
'src/core/lib/profiling/basic_timers.cc',
@ -533,6 +538,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h',
'src/core/ext/filters/max_age/max_age_filter.h',
'src/core/ext/filters/message_size/message_size_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',
@ -854,10 +860,13 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc',
@ -890,6 +899,10 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/global_config.h',
'src/core/lib/gprpp/global_config_custom.h',
'src/core/lib/gprpp/global_config_env.h',
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/map.h',
'src/core/lib/gprpp/memory.h',
@ -1176,6 +1189,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h',
'src/core/ext/filters/max_age/max_age_filter.h',
'src/core/ext/filters/message_size/message_size_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',

@ -102,6 +102,10 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gprpp/arena.h )
s.files += %w( src/core/lib/gprpp/atomic.h )
s.files += %w( src/core/lib/gprpp/fork.h )
s.files += %w( src/core/lib/gprpp/global_config.h )
s.files += %w( src/core/lib/gprpp/global_config_custom.h )
s.files += %w( src/core/lib/gprpp/global_config_env.h )
s.files += %w( src/core/lib/gprpp/global_config_generic.h )
s.files += %w( src/core/lib/gprpp/manual_constructor.h )
s.files += %w( src/core/lib/gprpp/map.h )
s.files += %w( src/core/lib/gprpp/memory.h )
@ -144,6 +148,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gpr/wrap_memcpy.cc )
s.files += %w( src/core/lib/gprpp/arena.cc )
s.files += %w( src/core/lib/gprpp/fork.cc )
s.files += %w( src/core/lib/gprpp/global_config_env.cc )
s.files += %w( src/core/lib/gprpp/thd_posix.cc )
s.files += %w( src/core/lib/gprpp/thd_windows.cc )
s.files += %w( src/core/lib/profiling/basic_timers.cc )
@ -467,6 +472,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h )
s.files += %w( src/core/ext/filters/max_age/max_age_filter.h )
s.files += %w( src/core/ext/filters/message_size/message_size_filter.h )
s.files += %w( src/core/ext/filters/http/client_authority_filter.h )
@ -791,10 +797,13 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc )

@ -252,6 +252,7 @@
'src/core/lib/gpr/wrap_memcpy.cc',
'src/core/lib/gprpp/arena.cc',
'src/core/lib/gprpp/fork.cc',
'src/core/lib/gprpp/global_config_env.cc',
'src/core/lib/gprpp/thd_posix.cc',
'src/core/lib/gprpp/thd_windows.cc',
'src/core/lib/profiling/basic_timers.cc',
@ -584,10 +585,13 @@
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc',
@ -1341,10 +1345,13 @@
'src/core/ext/transport/inproc/inproc_transport.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc',

@ -77,7 +77,6 @@
#define GPR_WINDOWS 1
#define GPR_WINDOWS_SUBPROCESS 1
#define GPR_WINDOWS_ENV
#define GPR_HAS_ALIGNED_MALLOC 1
#ifdef __MSYS__
#define GPR_GETPID_IN_UNISTD_H 1
#define GPR_MSYS_TMPFILE
@ -174,7 +173,6 @@
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_HAS_ALIGNED_ALLOC 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifdef _LP64
#define GPR_ARCH_64 1
@ -240,7 +238,6 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_POSIX_MEMALIGN 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifndef GRPC_CFSTREAM

@ -128,7 +128,8 @@ typedef enum {
/** The service is currently unavailable. This is a most likely a
transient condition and may be corrected by retrying with
a backoff.
a backoff. Note that it is not always safe to retry non-idempotent
operations.
WARNING: Although data MIGHT not have been transmitted when this
status occurs, there is NOT A GUARANTEE that the server has not seen

@ -32,8 +32,6 @@ typedef struct gpr_allocation_functions {
void* (*zalloc_fn)(size_t size); /** if NULL, uses malloc_fn then memset */
void* (*realloc_fn)(void* ptr, size_t size);
void (*free_fn)(void* ptr);
void* (*aligned_alloc_fn)(size_t size, size_t alignment);
void (*aligned_free_fn)(void* ptr);
} gpr_allocation_functions;
/** malloc.

@ -119,7 +119,8 @@ enum StatusCode {
INTERNAL = 13,
/// The service is currently unavailable. This is a most likely a transient
/// condition and may be corrected by retrying with a backoff.
/// condition and may be corrected by retrying with a backoff. Note that it is
/// not always safe to retry non-idempotent operations.
///
/// \warning Although data MIGHT not have been transmitted when this
/// status occurs, there is NOT A GUARANTEE that the server has not seen

@ -107,6 +107,10 @@
<file baseinstalldir="/" name="src/core/lib/gprpp/arena.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/atomic.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/fork.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config_custom.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config_env.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config_generic.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/manual_constructor.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/map.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/memory.h" role="src" />
@ -149,6 +153,7 @@
<file baseinstalldir="/" name="src/core/lib/gpr/wrap_memcpy.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/arena.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/fork.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config_env.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/thd_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/thd_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" />
@ -472,6 +477,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/message_size/message_size_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client_authority_filter.h" role="src" />
@ -796,10 +802,13 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc" role="src" />

@ -25,8 +25,8 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/global_config.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/timer.h"
@ -56,21 +56,22 @@ static backup_poller* g_poller = nullptr; // guarded by g_poller_mu
// treated as const.
static int g_poll_interval_ms = DEFAULT_POLL_INTERVAL_MS;
GPR_GLOBAL_CONFIG_DEFINE_INT32(grpc_client_channel_backup_poll_interval_ms,
DEFAULT_POLL_INTERVAL_MS,
"Client channel backup poll interval (ms)");
static void init_globals() {
gpr_mu_init(&g_poller_mu);
char* env = gpr_getenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS");
if (env != nullptr) {
int poll_interval_ms = gpr_parse_nonnegative_int(env);
if (poll_interval_ms == -1) {
gpr_log(GPR_ERROR,
"Invalid GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS: %s, "
"default value %d will be used.",
env, g_poll_interval_ms);
} else {
g_poll_interval_ms = poll_interval_ms;
}
int32_t poll_interval_ms =
GPR_GLOBAL_CONFIG_GET(grpc_client_channel_backup_poll_interval_ms);
if (poll_interval_ms < 0) {
gpr_log(GPR_ERROR,
"Invalid GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS: %d, "
"default value %d will be used.",
poll_interval_ms, g_poll_interval_ms);
} else {
g_poll_interval_ms = poll_interval_ms;
}
gpr_free(env);
}
static void backup_poller_shutdown_unref(backup_poller* p) {

@ -23,6 +23,9 @@
#include <grpc/grpc.h>
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/gprpp/global_config.h"
GPR_GLOBAL_CONFIG_DECLARE_INT32(grpc_client_channel_backup_poll_interval_ms);
/* Start polling \a interested_parties periodically in the timer thread */
void grpc_client_channel_start_backup_polling(

@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
#if GRPC_ARES == 1 && !defined(GRPC_UV)
#if GRPC_ARES == 1
#include <limits.h>
#include <stdio.h>
@ -430,6 +430,13 @@ static grpc_error* blocking_resolve_address_ares(
static grpc_address_resolver_vtable ares_resolver = {
grpc_resolve_address_ares, blocking_resolve_address_ares};
#ifdef GRPC_UV
/* TODO(murgatroid99): Remove this when we want the cares resolver to be the
* default when using libuv */
static bool should_use_ares(const char* resolver_env) {
return resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0;
}
#else /* GRPC_UV */
static bool should_use_ares(const char* resolver_env) {
// TODO(lidiz): Remove the "g_custom_iomgr_enabled" flag once c-ares support
// custom IO managers (e.g. gevent).
@ -437,6 +444,7 @@ static bool should_use_ares(const char* resolver_env) {
(resolver_env == nullptr || strlen(resolver_env) == 0 ||
gpr_stricmp(resolver_env, "ares") == 0);
}
#endif /* GRPC_UV */
void grpc_resolver_dns_ares_init() {
char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
@ -468,10 +476,10 @@ void grpc_resolver_dns_ares_shutdown() {
gpr_free(resolver_env);
}
#else /* GRPC_ARES == 1 && !defined(GRPC_UV) */
#else /* GRPC_ARES == 1 */
void grpc_resolver_dns_ares_init(void) {}
void grpc_resolver_dns_ares_shutdown(void) {}
#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */
#endif /* GRPC_ARES == 1 */

@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && !defined(GRPC_UV)
#if GRPC_ARES == 1
#include <ares.h>
#include <string.h>
@ -218,6 +218,7 @@ static void on_timeout_locked(void* arg, grpc_error* error) {
static void on_readable_locked(void* arg, grpc_error* error) {
fd_node* fdn = static_cast<fd_node*>(arg);
GPR_ASSERT(fdn->readable_registered);
grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
fdn->readable_registered = false;
@ -242,6 +243,7 @@ static void on_readable_locked(void* arg, grpc_error* error) {
static void on_writable_locked(void* arg, grpc_error* error) {
fd_node* fdn = static_cast<fd_node*>(arg);
GPR_ASSERT(fdn->writable_registered);
grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
fdn->writable_registered = false;
@ -365,4 +367,4 @@ void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) {
}
}
#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */
#endif /* GRPC_ARES == 1 */

@ -0,0 +1,179 @@
/*
*
* Copyright 2019 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 <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && defined(GRPC_UV)
#include <ares.h>
#include <uv.h>
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.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/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/combiner.h"
namespace grpc_core {
void ares_uv_poll_cb(uv_poll_t* handle, int status, int events);
void ares_uv_poll_close_cb(uv_handle_t* handle) { Delete(handle); }
class GrpcPolledFdLibuv : public GrpcPolledFd {
public:
GrpcPolledFdLibuv(ares_socket_t as, grpc_combiner* combiner)
: as_(as), combiner_(combiner) {
gpr_asprintf(&name_, "c-ares socket: %" PRIdPTR, (intptr_t)as);
handle_ = New<uv_poll_t>();
uv_poll_init_socket(uv_default_loop(), handle_, as);
handle_->data = this;
GRPC_COMBINER_REF(combiner_, "libuv ares event driver");
}
~GrpcPolledFdLibuv() {
gpr_free(name_);
GRPC_COMBINER_UNREF(combiner_, "libuv ares event driver");
}
void RegisterForOnReadableLocked(grpc_closure* read_closure) override {
GPR_ASSERT(read_closure_ == nullptr);
GPR_ASSERT((poll_events_ & UV_READABLE) == 0);
read_closure_ = read_closure;
poll_events_ |= UV_READABLE;
uv_poll_start(handle_, poll_events_, ares_uv_poll_cb);
}
void RegisterForOnWriteableLocked(grpc_closure* write_closure) override {
GPR_ASSERT(write_closure_ == nullptr);
GPR_ASSERT((poll_events_ & UV_WRITABLE) == 0);
write_closure_ = write_closure;
poll_events_ |= UV_WRITABLE;
uv_poll_start(handle_, poll_events_, ares_uv_poll_cb);
}
bool IsFdStillReadableLocked() override {
/* uv_poll_t is based on poll, which is level triggered. So, if cares
* leaves some data unread, the event will trigger again. */
return false;
}
void ShutdownInternalLocked(grpc_error* error) {
uv_poll_stop(handle_);
uv_close(reinterpret_cast<uv_handle_t*>(handle_), ares_uv_poll_close_cb);
if (read_closure_ != nullptr) {
GRPC_CLOSURE_SCHED(read_closure_, GRPC_ERROR_CANCELLED);
}
if (write_closure_ != nullptr) {
GRPC_CLOSURE_SCHED(write_closure_, GRPC_ERROR_CANCELLED);
}
}
void ShutdownLocked(grpc_error* error) override {
if (grpc_core::ExecCtx::Get() == nullptr) {
grpc_core::ExecCtx exec_ctx;
ShutdownInternalLocked(error);
} else {
ShutdownInternalLocked(error);
}
}
ares_socket_t GetWrappedAresSocketLocked() override { return as_; }
const char* GetName() override { return name_; }
char* name_;
ares_socket_t as_;
uv_poll_t* handle_;
grpc_closure* read_closure_ = nullptr;
grpc_closure* write_closure_ = nullptr;
int poll_events_ = 0;
grpc_combiner* combiner_;
};
struct AresUvPollCbArg {
AresUvPollCbArg(uv_poll_t* handle, int status, int events)
: handle(handle), status(status), events(events) {}
uv_poll_t* handle;
int status;
int events;
};
static void ares_uv_poll_cb_locked(void* arg, grpc_error* error) {
grpc_core::UniquePtr<AresUvPollCbArg> arg_struct(
reinterpret_cast<AresUvPollCbArg*>(arg));
uv_poll_t* handle = arg_struct->handle;
int status = arg_struct->status;
int events = arg_struct->events;
GrpcPolledFdLibuv* polled_fd =
reinterpret_cast<GrpcPolledFdLibuv*>(handle->data);
if (status < 0) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("cares polling error");
error =
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string(uv_strerror(status)));
}
if (events & UV_READABLE) {
GPR_ASSERT(polled_fd->read_closure_ != nullptr);
GRPC_CLOSURE_SCHED(polled_fd->read_closure_, error);
polled_fd->read_closure_ = nullptr;
polled_fd->poll_events_ &= ~UV_READABLE;
}
if (events & UV_WRITABLE) {
GPR_ASSERT(polled_fd->write_closure_ != nullptr);
GRPC_CLOSURE_SCHED(polled_fd->write_closure_, error);
polled_fd->write_closure_ = nullptr;
polled_fd->poll_events_ &= ~UV_WRITABLE;
}
uv_poll_start(handle, polled_fd->poll_events_, ares_uv_poll_cb);
}
void ares_uv_poll_cb(uv_poll_t* handle, int status, int events) {
grpc_core::ExecCtx exec_ctx;
GrpcPolledFdLibuv* polled_fd =
reinterpret_cast<GrpcPolledFdLibuv*>(handle->data);
AresUvPollCbArg* arg = New<AresUvPollCbArg>(handle, status, events);
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(ares_uv_poll_cb_locked, arg,
grpc_combiner_scheduler(polled_fd->combiner_)),
GRPC_ERROR_NONE);
}
class GrpcPolledFdFactoryLibuv : public GrpcPolledFdFactory {
public:
GrpcPolledFd* NewGrpcPolledFdLocked(ares_socket_t as,
grpc_pollset_set* driver_pollset_set,
grpc_combiner* combiner) override {
return New<GrpcPolledFdLibuv>(as, combiner);
}
void ConfigureAresChannelLocked(ares_channel channel) override {}
};
UniquePtr<GrpcPolledFdFactory> NewGrpcPolledFdFactory(grpc_combiner* combiner) {
return UniquePtr<GrpcPolledFdFactory>(New<GrpcPolledFdFactoryLibuv>());
}
} // namespace grpc_core
#endif /* GRPC_ARES == 1 && defined(GRPC_UV) */

@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
#if GRPC_ARES == 1 && !defined(GRPC_UV)
#if GRPC_ARES == 1
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/lib/iomgr/sockaddr.h"
@ -687,4 +687,4 @@ void (*grpc_resolve_address_ares)(
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_resolved_addresses** addrs) = grpc_resolve_address_ares_impl;
#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */
#endif /* GRPC_ARES == 1 */

@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
#if GRPC_ARES != 1 || defined(GRPC_UV)
#if GRPC_ARES != 1
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
@ -62,4 +62,4 @@ void (*grpc_resolve_address_ares)(
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_resolved_addresses** addrs) = grpc_resolve_address_ares_impl;
#endif /* GRPC_ARES != 1 || defined(GRPC_UV) */
#endif /* GRPC_ARES != 1 */

@ -0,0 +1,52 @@
/*
*
* 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 <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && defined(GRPC_UV)
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
bool grpc_ares_query_ipv6() {
/* The libuv grpc code currently does not have the code to probe for this,
* so we assume for now that IPv6 is always available in contexts where this
* code will be used. */
return true;
}
bool grpc_ares_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs) {
char* host = nullptr;
char* port = nullptr;
bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port,
addrs, &host, &port);
gpr_free(host);
gpr_free(port);
return out;
}
#endif /* GRPC_ARES == 1 && defined(GRPC_UV) */

@ -0,0 +1,83 @@
/*
*
* Copyright 2019 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 <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && (defined(GRPC_UV) || defined(GPR_WINDOWS))
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
bool inner_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs, char** host,
char** port) {
gpr_split_host_port(name, host, port);
if (*host == nullptr) {
gpr_log(GPR_ERROR,
"Failed to parse %s into host:port during manual localhost "
"resolution check.",
name);
return false;
}
if (*port == nullptr) {
if (default_port == nullptr) {
gpr_log(GPR_ERROR,
"No port or default port for %s during manual localhost "
"resolution check.",
name);
return false;
}
*port = gpr_strdup(default_port);
}
if (gpr_stricmp(*host, "localhost") == 0) {
GPR_ASSERT(*addrs == nullptr);
*addrs = grpc_core::MakeUnique<grpc_core::ServerAddressList>();
uint16_t numeric_port = grpc_strhtons(*port);
// Append the ipv6 loopback address.
struct sockaddr_in6 ipv6_loopback_addr;
memset(&ipv6_loopback_addr, 0, sizeof(ipv6_loopback_addr));
((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1;
ipv6_loopback_addr.sin6_family = AF_INET6;
ipv6_loopback_addr.sin6_port = numeric_port;
(*addrs)->emplace_back(&ipv6_loopback_addr, sizeof(ipv6_loopback_addr),
nullptr /* args */);
// Append the ipv4 loopback address.
struct sockaddr_in ipv4_loopback_addr;
memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr));
((char*)&ipv4_loopback_addr.sin_addr)[0] = 0x7f;
((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01;
ipv4_loopback_addr.sin_family = AF_INET;
ipv4_loopback_addr.sin_port = numeric_port;
(*addrs)->emplace_back(&ipv4_loopback_addr, sizeof(ipv4_loopback_addr),
nullptr /* args */);
// Let the address sorter figure out which one should be tried first.
grpc_cares_wrapper_address_sorting_sort(addrs->get());
return true;
}
return false;
}
#endif /* GRPC_ARES == 1 && (defined(GRPC_UV) || defined(GPR_WINDOWS)) */

@ -0,0 +1,34 @@
/*
*
* Copyright 2019 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.
*
*/
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_LIBUV_WINDOWS_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_LIBUV_WINDOWS_H
#include <grpc/support/port_platform.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
bool inner_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs, char** host,
char** port);
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_LIBUV_WINDOWS_H \
*/

@ -25,6 +25,7 @@
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
@ -32,56 +33,6 @@
bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); }
static bool inner_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs, char** host,
char** port) {
gpr_split_host_port(name, host, port);
if (*host == nullptr) {
gpr_log(GPR_ERROR,
"Failed to parse %s into host:port during Windows localhost "
"resolution check.",
name);
return false;
}
if (*port == nullptr) {
if (default_port == nullptr) {
gpr_log(GPR_ERROR,
"No port or default port for %s during Windows localhost "
"resolution check.",
name);
return false;
}
*port = gpr_strdup(default_port);
}
if (gpr_stricmp(*host, "localhost") == 0) {
GPR_ASSERT(*addrs == nullptr);
*addrs = grpc_core::MakeUnique<grpc_core::ServerAddressList>();
uint16_t numeric_port = grpc_strhtons(*port);
// Append the ipv6 loopback address.
struct sockaddr_in6 ipv6_loopback_addr;
memset(&ipv6_loopback_addr, 0, sizeof(ipv6_loopback_addr));
((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1;
ipv6_loopback_addr.sin6_family = AF_INET6;
ipv6_loopback_addr.sin6_port = numeric_port;
(*addrs)->emplace_back(&ipv6_loopback_addr, sizeof(ipv6_loopback_addr),
nullptr /* args */);
// Append the ipv4 loopback address.
struct sockaddr_in ipv4_loopback_addr;
memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr));
((char*)&ipv4_loopback_addr.sin_addr)[0] = 0x7f;
((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01;
ipv4_loopback_addr.sin_family = AF_INET;
ipv4_loopback_addr.sin_port = numeric_port;
(*addrs)->emplace_back(&ipv4_loopback_addr, sizeof(ipv4_loopback_addr),
nullptr /* args */);
// Let the address sorter figure out which one should be tried first.
grpc_cares_wrapper_address_sorting_sort(addrs->get());
return true;
}
return false;
}
bool grpc_ares_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs) {

@ -66,13 +66,12 @@
#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
// Conversion between subchannel call and call stack.
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) \
(grpc_call_stack*)((char*)(call) + GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE( \
sizeof(SubchannelCall)))
#define CALL_STACK_TO_SUBCHANNEL_CALL(callstack) \
(SubchannelCall*)(((char*)(call_stack)) - \
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE( \
sizeof(SubchannelCall)))
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) \
(grpc_call_stack*)((char*)(call) + \
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall)))
#define CALL_STACK_TO_SUBCHANNEL_CALL(callstack) \
(SubchannelCall*)(((char*)(call_stack)) - \
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall)))
namespace grpc_core {
@ -152,10 +151,10 @@ RefCountedPtr<SubchannelCall> ConnectedSubchannel::CreateCall(
size_t ConnectedSubchannel::GetInitialCallSizeEstimate(
size_t parent_data_size) const {
size_t allocation_size =
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(SubchannelCall));
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall));
if (parent_data_size > 0) {
allocation_size +=
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(channel_stack_->call_stack_size) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(channel_stack_->call_stack_size) +
parent_data_size;
} else {
allocation_size += channel_stack_->call_stack_size;
@ -179,9 +178,8 @@ void SubchannelCall::StartTransportStreamOpBatch(
void* SubchannelCall::GetParentData() {
grpc_channel_stack* chanstk = connected_subchannel_->channel_stack();
return (char*)this +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(SubchannelCall)) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(chanstk->call_stack_size);
return (char*)this + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(chanstk->call_stack_size);
}
grpc_call_stack* SubchannelCall::GetCallStack() {

@ -20,16 +20,15 @@
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gprpp/global_config.h"
#include "src/core/lib/transport/metadata.h"
GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_experimental_disable_flow_control, false,
"Disable flow control");
void grpc_chttp2_plugin_init(void) {
g_flow_control_enabled = true;
char* env_variable = gpr_getenv("GRPC_EXPERIMENTAL_DISABLE_FLOW_CONTROL");
if (env_variable != nullptr) {
g_flow_control_enabled = false;
gpr_free(env_variable);
}
g_flow_control_enabled =
!GPR_GLOBAL_CONFIG_GET(grpc_experimental_disable_flow_control);
}
void grpc_chttp2_plugin_shutdown(void) {}

@ -679,8 +679,6 @@ grpc_chttp2_stream::grpc_chttp2_stream(grpc_chttp2_transport* t,
grpc_slice_buffer_init(&frame_storage);
grpc_slice_buffer_init(&unprocessed_incoming_frames_buffer);
grpc_slice_buffer_init(&flow_controlled_buffer);
grpc_slice_buffer_init(&compressed_data_buffer);
grpc_slice_buffer_init(&decompressed_data_buffer);
GRPC_CLOSURE_INIT(&complete_fetch_locked, ::complete_fetch_locked, this,
grpc_combiner_scheduler(t->combiner));
@ -704,8 +702,13 @@ grpc_chttp2_stream::~grpc_chttp2_stream() {
grpc_slice_buffer_destroy_internal(&unprocessed_incoming_frames_buffer);
grpc_slice_buffer_destroy_internal(&frame_storage);
grpc_slice_buffer_destroy_internal(&compressed_data_buffer);
grpc_slice_buffer_destroy_internal(&decompressed_data_buffer);
if (stream_compression_method != GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS) {
grpc_slice_buffer_destroy_internal(&compressed_data_buffer);
}
if (stream_decompression_method !=
GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS) {
grpc_slice_buffer_destroy_internal(&decompressed_data_buffer);
}
grpc_chttp2_list_remove_stalled_by_transport(t, this);
grpc_chttp2_list_remove_stalled_by_stream(t, this);
@ -759,12 +762,15 @@ static void destroy_stream(grpc_transport* gt, grpc_stream* gs,
GPR_TIMER_SCOPE("destroy_stream", 0);
grpc_chttp2_transport* t = reinterpret_cast<grpc_chttp2_transport*>(gt);
grpc_chttp2_stream* s = reinterpret_cast<grpc_chttp2_stream*>(gs);
if (s->stream_compression_ctx != nullptr) {
if (s->stream_compression_method !=
GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS &&
s->stream_compression_ctx != nullptr) {
grpc_stream_compression_context_destroy(s->stream_compression_ctx);
s->stream_compression_ctx = nullptr;
}
if (s->stream_decompression_ctx != nullptr) {
if (s->stream_decompression_method !=
GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS &&
s->stream_decompression_ctx != nullptr) {
grpc_stream_compression_context_destroy(s->stream_decompression_ctx);
s->stream_decompression_ctx = nullptr;
}
@ -1442,7 +1448,12 @@ static void perform_stream_op_locked(void* stream_op,
true, &s->stream_compression_method) == 0) {
s->stream_compression_method = GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS;
}
if (s->stream_compression_method !=
GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS) {
s->uncompressed_data_size = 0;
s->stream_compression_ctx = nullptr;
grpc_slice_buffer_init(&s->compressed_data_buffer);
}
s->send_initial_metadata_finished = add_closure_barrier(on_complete);
s->send_initial_metadata =
op_payload->send_initial_metadata.send_initial_metadata;
@ -1998,27 +2009,39 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_chttp2_transport* t,
!s->seen_error && s->recv_trailing_metadata_finished != nullptr) {
/* Maybe some SYNC_FLUSH data is left in frame_storage. Consume them and
* maybe decompress the next 5 bytes in the stream. */
bool end_of_context;
if (!s->stream_decompression_ctx) {
s->stream_decompression_ctx = grpc_stream_compression_context_create(
s->stream_decompression_method);
}
if (!grpc_stream_decompress(
s->stream_decompression_ctx, &s->frame_storage,
&s->unprocessed_incoming_frames_buffer, nullptr,
GRPC_HEADER_SIZE_IN_BYTES, &end_of_context)) {
grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage);
grpc_slice_buffer_reset_and_unref_internal(
&s->unprocessed_incoming_frames_buffer);
s->seen_error = true;
} else {
if (s->stream_decompression_method ==
GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS) {
grpc_slice_buffer_move_first(&s->frame_storage,
GRPC_HEADER_SIZE_IN_BYTES,
&s->unprocessed_incoming_frames_buffer);
if (s->unprocessed_incoming_frames_buffer.length > 0) {
s->unprocessed_incoming_frames_decompressed = true;
pending_data = true;
}
if (end_of_context) {
grpc_stream_compression_context_destroy(s->stream_decompression_ctx);
s->stream_decompression_ctx = nullptr;
} else {
bool end_of_context;
if (!s->stream_decompression_ctx) {
s->stream_decompression_ctx = grpc_stream_compression_context_create(
s->stream_decompression_method);
}
if (!grpc_stream_decompress(
s->stream_decompression_ctx, &s->frame_storage,
&s->unprocessed_incoming_frames_buffer, nullptr,
GRPC_HEADER_SIZE_IN_BYTES, &end_of_context)) {
grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage);
grpc_slice_buffer_reset_and_unref_internal(
&s->unprocessed_incoming_frames_buffer);
s->seen_error = true;
} else {
if (s->unprocessed_incoming_frames_buffer.length > 0) {
s->unprocessed_incoming_frames_decompressed = true;
pending_data = true;
}
if (end_of_context) {
grpc_stream_compression_context_destroy(
s->stream_decompression_ctx);
s->stream_decompression_ctx = nullptr;
}
}
}
}
@ -2941,6 +2964,8 @@ bool Chttp2IncomingByteStream::Next(size_t max_size_hint,
}
void Chttp2IncomingByteStream::MaybeCreateStreamDecompressionCtx() {
GPR_DEBUG_ASSERT(stream_->stream_decompression_method !=
GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS);
if (!stream_->stream_decompression_ctx) {
stream_->stream_decompression_ctx = grpc_stream_compression_context_create(
stream_->stream_decompression_method);
@ -2951,7 +2976,9 @@ grpc_error* Chttp2IncomingByteStream::Pull(grpc_slice* slice) {
GPR_TIMER_SCOPE("incoming_byte_stream_pull", 0);
grpc_error* error;
if (stream_->unprocessed_incoming_frames_buffer.length > 0) {
if (!stream_->unprocessed_incoming_frames_decompressed) {
if (!stream_->unprocessed_incoming_frames_decompressed &&
stream_->stream_decompression_method !=
GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS) {
bool end_of_context;
MaybeCreateStreamDecompressionCtx();
if (!grpc_stream_decompress(stream_->stream_decompression_ctx,

@ -1616,6 +1616,12 @@ static void parse_stream_compression_md(grpc_chttp2_transport* t,
s->stream_decompression_method =
GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS;
}
if (s->stream_decompression_method !=
GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS) {
s->stream_decompression_ctx = nullptr;
grpc_slice_buffer_init(&s->decompressed_data_buffer);
}
}
grpc_error* grpc_chttp2_header_parser_parse(void* hpack_parser,

@ -583,10 +583,6 @@ struct grpc_chttp2_stream {
grpc_slice_buffer frame_storage; /* protected by t combiner */
/* Accessed only by transport thread when stream->pending_byte_stream == false
* Accessed only by application thread when stream->pending_byte_stream ==
* true */
grpc_slice_buffer unprocessed_incoming_frames_buffer;
grpc_closure* on_next = nullptr; /* protected by t combiner */
bool pending_byte_stream = false; /* protected by t combiner */
// cached length of buffer to be used by the transport thread in cases where
@ -594,6 +590,10 @@ struct grpc_chttp2_stream {
// application threads are allowed to modify
// unprocessed_incoming_frames_buffer
size_t unprocessed_incoming_frames_buffer_cached_length = 0;
/* Accessed only by transport thread when stream->pending_byte_stream == false
* Accessed only by application thread when stream->pending_byte_stream ==
* true */
grpc_slice_buffer unprocessed_incoming_frames_buffer;
grpc_closure reset_byte_stream;
grpc_error* byte_stream_error = GRPC_ERROR_NONE; /* protected by t combiner */
bool received_last_frame = false; /* protected by t combiner */
@ -634,18 +634,7 @@ struct grpc_chttp2_stream {
/* Stream decompression method to be used. */
grpc_stream_compression_method stream_decompression_method =
GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS;
/** Stream compression decompress context */
grpc_stream_compression_context* stream_decompression_ctx = nullptr;
/** Stream compression compress context */
grpc_stream_compression_context* stream_compression_ctx = nullptr;
/** Buffer storing data that is compressed but not sent */
grpc_slice_buffer compressed_data_buffer;
/** Amount of uncompressed bytes sent out when compressed_data_buffer is
* emptied */
size_t uncompressed_data_size = 0;
/** Temporary buffer storing decompressed data */
grpc_slice_buffer decompressed_data_buffer;
/** Whether bytes stored in unprocessed_incoming_byte_stream is decompressed
*/
bool unprocessed_incoming_frames_decompressed = false;
@ -655,6 +644,22 @@ struct grpc_chttp2_stream {
size_t decompressed_header_bytes = 0;
/** Byte counter for number of bytes written */
size_t byte_counter = 0;
/** Amount of uncompressed bytes sent out when compressed_data_buffer is
* emptied */
size_t uncompressed_data_size;
/** Stream compression compress context */
grpc_stream_compression_context* stream_compression_ctx;
/** Buffer storing data that is compressed but not sent */
grpc_slice_buffer compressed_data_buffer;
/** Stream compression decompress context */
grpc_stream_compression_context* stream_decompression_ctx;
/** Temporary buffer storing decompressed data.
* Initialized, used, and destroyed only when stream uses (non-identity)
* compression.
*/
grpc_slice_buffer decompressed_data_buffer;
};
/** Transport writing call flow:

@ -25,6 +25,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/compression/stream_compression.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
@ -150,7 +151,11 @@ static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
":flowed=%" PRId64 ":peer_initwin=%d:t_win=%" PRId64
":s_win=%d:s_delta=%" PRId64 "]",
t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length,
s->compressed_data_buffer.length, s->flow_controlled_bytes_flowed,
s->stream_compression_method ==
GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS
? 0
: s->compressed_data_buffer.length,
s->flow_controlled_bytes_flowed,
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
t->flow_control->remote_window(),
@ -325,7 +330,23 @@ class DataSendContext {
bool AnyOutgoing() const { return max_outgoing() > 0; }
void FlushUncompressedBytes() {
uint32_t send_bytes = static_cast<uint32_t> GPR_MIN(
max_outgoing(), s_->flow_controlled_buffer.length);
is_last_frame_ = send_bytes == s_->flow_controlled_buffer.length &&
s_->fetching_send_message == nullptr &&
s_->send_trailing_metadata != nullptr &&
grpc_metadata_batch_is_empty(s_->send_trailing_metadata);
grpc_chttp2_encode_data(s_->id, &s_->flow_controlled_buffer, send_bytes,
is_last_frame_, &s_->stats.outgoing, &t_->outbuf);
s_->flow_control->SentData(send_bytes);
s_->sending_bytes += send_bytes;
}
void FlushCompressedBytes() {
GPR_DEBUG_ASSERT(s_->stream_compression_method !=
GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS);
uint32_t send_bytes = static_cast<uint32_t> GPR_MIN(
max_outgoing(), s_->compressed_data_buffer.length);
bool is_last_data_frame =
@ -360,6 +381,9 @@ class DataSendContext {
}
void CompressMoreBytes() {
GPR_DEBUG_ASSERT(s_->stream_compression_method !=
GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS);
if (s_->stream_compression_ctx == nullptr) {
s_->stream_compression_ctx =
grpc_stream_compression_context_create(s_->stream_compression_method);
@ -417,7 +441,7 @@ class StreamWriteContext {
// https://github.com/grpc/proposal/blob/master/A6-client-retries.md#when-retries-are-valid
if (!t_->is_client && s_->fetching_send_message == nullptr &&
s_->flow_controlled_buffer.length == 0 &&
s_->compressed_data_buffer.length == 0 &&
compressed_data_buffer_len() == 0 &&
s_->send_trailing_metadata != nullptr &&
is_default_initial_metadata(s_->send_initial_metadata)) {
ConvertInitialMetadataToTrailingMetadata();
@ -446,6 +470,13 @@ class StreamWriteContext {
"send_initial_metadata_finished");
}
bool compressed_data_buffer_len() {
return s_->stream_compression_method ==
GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS
? 0
: s_->compressed_data_buffer.length;
}
void FlushWindowUpdates() {
/* send any window updates */
const uint32_t stream_announce = s_->flow_control->MaybeSendUpdate();
@ -462,7 +493,7 @@ class StreamWriteContext {
if (!s_->sent_initial_metadata) return;
if (s_->flow_controlled_buffer.length == 0 &&
s_->compressed_data_buffer.length == 0) {
compressed_data_buffer_len() == 0) {
return; // early out: nothing to do
}
@ -479,13 +510,21 @@ class StreamWriteContext {
return; // early out: nothing to do
}
while ((s_->flow_controlled_buffer.length > 0 ||
s_->compressed_data_buffer.length > 0) &&
data_send_context.max_outgoing() > 0) {
if (s_->compressed_data_buffer.length > 0) {
data_send_context.FlushCompressedBytes();
} else {
data_send_context.CompressMoreBytes();
if (s_->stream_compression_method ==
GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS) {
while (s_->flow_controlled_buffer.length > 0 &&
data_send_context.max_outgoing() > 0) {
data_send_context.FlushUncompressedBytes();
}
} else {
while ((s_->flow_controlled_buffer.length > 0 ||
s_->compressed_data_buffer.length > 0) &&
data_send_context.max_outgoing() > 0) {
if (s_->compressed_data_buffer.length > 0) {
data_send_context.FlushCompressedBytes();
} else {
data_send_context.CompressMoreBytes();
}
}
}
write_context_->ResetPingClock();
@ -495,7 +534,7 @@ class StreamWriteContext {
data_send_context.CallCallbacks();
stream_became_writable_ = true;
if (s_->flow_controlled_buffer.length > 0 ||
s_->compressed_data_buffer.length > 0) {
compressed_data_buffer_len() > 0) {
GRPC_CHTTP2_STREAM_REF(s_, "chttp2_writing:fork");
grpc_chttp2_list_add_writable_stream(t_, s_);
}
@ -508,7 +547,7 @@ class StreamWriteContext {
if (s_->send_trailing_metadata == nullptr) return;
if (s_->fetching_send_message != nullptr) return;
if (s_->flow_controlled_buffer.length != 0) return;
if (s_->compressed_data_buffer.length != 0) return;
if (compressed_data_buffer_len() != 0) return;
GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "sending trailing_metadata"));
if (grpc_metadata_batch_is_empty(s_->send_trailing_metadata)) {

@ -47,9 +47,9 @@ grpc_core::TraceFlag grpc_trace_channel(false, "channel");
size_t grpc_channel_stack_size(const grpc_channel_filter** filters,
size_t filter_count) {
/* always need the header, and size for the channel elements */
size_t size = GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(
filter_count * sizeof(grpc_channel_element));
size_t size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filter_count *
sizeof(grpc_channel_element));
size_t i;
GPR_ASSERT((GPR_MAX_ALIGNMENT & (GPR_MAX_ALIGNMENT - 1)) == 0 &&
@ -57,18 +57,18 @@ size_t grpc_channel_stack_size(const grpc_channel_filter** filters,
/* add the size for each filter */
for (i = 0; i < filter_count; i++) {
size += GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
size += GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
}
return size;
}
#define CHANNEL_ELEMS_FROM_STACK(stk) \
((grpc_channel_element*)((char*)(stk) + GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE( \
#define CHANNEL_ELEMS_FROM_STACK(stk) \
((grpc_channel_element*)((char*)(stk) + GPR_ROUND_UP_TO_ALIGNMENT_SIZE( \
sizeof(grpc_channel_stack))))
#define CALL_ELEMS_FROM_STACK(stk) \
((grpc_call_element*)((char*)(stk) + GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE( \
#define CALL_ELEMS_FROM_STACK(stk) \
((grpc_call_element*)((char*)(stk) + GPR_ROUND_UP_TO_ALIGNMENT_SIZE( \
sizeof(grpc_call_stack))))
grpc_channel_element* grpc_channel_stack_element(
@ -92,9 +92,8 @@ grpc_error* grpc_channel_stack_init(
const grpc_channel_args* channel_args, grpc_transport* optional_transport,
const char* name, grpc_channel_stack* stack) {
size_t call_size =
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filter_count *
sizeof(grpc_call_element));
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element));
grpc_channel_element* elems;
grpc_channel_element_args args;
char* user_data;
@ -105,8 +104,8 @@ grpc_error* grpc_channel_stack_init(
name);
elems = CHANNEL_ELEMS_FROM_STACK(stack);
user_data = (reinterpret_cast<char*>(elems)) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filter_count *
sizeof(grpc_channel_element));
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filter_count *
sizeof(grpc_channel_element));
/* init per-filter data */
grpc_error* first_error = GRPC_ERROR_NONE;
@ -127,9 +126,8 @@ grpc_error* grpc_channel_stack_init(
}
}
user_data +=
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
call_size +=
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
call_size += GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
}
GPR_ASSERT(user_data > (char*)stack);
@ -164,9 +162,8 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
GRPC_STREAM_REF_INIT(&elem_args->call_stack->refcount, initial_refs, destroy,
destroy_arg, "CALL_STACK");
call_elems = CALL_ELEMS_FROM_STACK(elem_args->call_stack);
user_data =
(reinterpret_cast<char*>(call_elems)) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
user_data = (reinterpret_cast<char*>(call_elems)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
/* init per-filter data */
grpc_error* first_error = GRPC_ERROR_NONE;
@ -174,8 +171,8 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
call_elems[i].filter = channel_elems[i].filter;
call_elems[i].channel_data = channel_elems[i].channel_data;
call_elems[i].call_data = user_data;
user_data += GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(
call_elems[i].filter->sizeof_call_data);
user_data +=
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
}
for (size_t i = 0; i < count; i++) {
grpc_error* error =
@ -245,11 +242,11 @@ grpc_channel_stack* grpc_channel_stack_from_top_element(
grpc_channel_element* elem) {
return reinterpret_cast<grpc_channel_stack*>(
reinterpret_cast<char*>(elem) -
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)));
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)));
}
grpc_call_stack* grpc_call_stack_from_top_element(grpc_call_element* elem) {
return reinterpret_cast<grpc_call_stack*>(
reinterpret_cast<char*>(elem) -
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_call_stack)));
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)));
}

@ -23,7 +23,6 @@
#include <grpc/support/log.h>
#include <stdlib.h>
#include <string.h>
#include "src/core/lib/gpr/alloc.h"
#include "src/core/lib/profiling/timers.h"
static void* zalloc_with_calloc(size_t sz) { return calloc(sz, 1); }
@ -34,56 +33,8 @@ static void* zalloc_with_gpr_malloc(size_t sz) {
return p;
}
#ifndef NDEBUG
static constexpr bool is_power_of_two(size_t value) {
// 2^N = 100000...000
// 2^N - 1 = 011111...111
// (2^N) && ((2^N)-1)) = 0
return (value & (value - 1)) == 0;
}
#endif
static void* platform_malloc_aligned(size_t size, size_t alignment) {
#if defined(GPR_HAS_ALIGNED_ALLOC)
GPR_DEBUG_ASSERT(is_power_of_two(alignment));
size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(size, alignment);
void* ret = aligned_alloc(alignment, size);
GPR_ASSERT(ret != nullptr);
return ret;
#elif defined(GPR_HAS_ALIGNED_MALLOC)
GPR_DEBUG_ASSERT(is_power_of_two(alignment));
void* ret = _aligned_malloc(size, alignment);
GPR_ASSERT(ret != nullptr);
return ret;
#elif defined(GPR_HAS_POSIX_MEMALIGN)
GPR_DEBUG_ASSERT(is_power_of_two(alignment));
GPR_DEBUG_ASSERT(alignment % sizeof(void*) == 0);
void* ret = nullptr;
GPR_ASSERT(posix_memalign(&ret, alignment, size) == 0);
return ret;
#else
GPR_DEBUG_ASSERT(is_power_of_two(alignment));
size_t extra = alignment - 1 + sizeof(void*);
void* p = gpr_malloc(size + extra);
void** ret = (void**)(((uintptr_t)p + extra) & ~(alignment - 1));
ret[-1] = p;
return (void*)ret;
#endif
}
static void platform_free_aligned(void* ptr) {
#if defined(GPR_HAS_ALIGNED_ALLOC) || defined(GPR_HAS_POSIX_MEMALIGN)
free(ptr);
#elif defined(GPR_HAS_ALIGNED_MALLOC)
_aligned_free(ptr);
#else
gpr_free((static_cast<void**>(ptr))[-1]);
#endif
}
static gpr_allocation_functions g_alloc_functions = {
malloc, zalloc_with_calloc, realloc,
free, platform_malloc_aligned, platform_free_aligned};
static gpr_allocation_functions g_alloc_functions = {malloc, zalloc_with_calloc,
realloc, free};
gpr_allocation_functions gpr_get_allocation_functions() {
return g_alloc_functions;
@ -96,12 +47,6 @@ void gpr_set_allocation_functions(gpr_allocation_functions functions) {
if (functions.zalloc_fn == nullptr) {
functions.zalloc_fn = zalloc_with_gpr_malloc;
}
GPR_ASSERT((functions.aligned_alloc_fn == nullptr) ==
(functions.aligned_free_fn == nullptr));
if (functions.aligned_alloc_fn == nullptr) {
functions.aligned_alloc_fn = platform_malloc_aligned;
functions.aligned_free_fn = platform_free_aligned;
}
g_alloc_functions = functions;
}
@ -143,12 +88,12 @@ void* gpr_realloc(void* p, size_t size) {
}
void* gpr_malloc_aligned(size_t size, size_t alignment) {
GPR_TIMER_SCOPE("gpr_malloc_aligned", 0);
if (size == 0) return nullptr;
return g_alloc_functions.aligned_alloc_fn(size, alignment);
GPR_ASSERT(((alignment - 1) & alignment) == 0); // Must be power of 2.
size_t extra = alignment - 1 + sizeof(void*);
void* p = gpr_malloc(size + extra);
void** ret = (void**)(((uintptr_t)p + extra) & ~(alignment - 1));
ret[-1] = p;
return (void*)ret;
}
void gpr_free_aligned(void* ptr) {
GPR_TIMER_SCOPE("gpr_free_aligned", 0);
g_alloc_functions.aligned_free_fn(ptr);
}
void gpr_free_aligned(void* ptr) { gpr_free((static_cast<void**>(ptr))[-1]); }

@ -22,13 +22,7 @@
#include <grpc/support/port_platform.h>
/// Given a size, round up to the next multiple of sizeof(void*).
#define GPR_ROUND_UP_TO_ALIGNMENT_SIZE(x, align) \
(((x) + (align)-1u) & ~((align)-1u))
#define GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(x) \
GPR_ROUND_UP_TO_ALIGNMENT_SIZE((x), GPR_MAX_ALIGNMENT)
#define GPR_ROUND_UP_TO_CACHELINE_SIZE(x) \
GPR_ROUND_UP_TO_ALIGNMENT_SIZE((x), GPR_CACHELINE_SIZE)
#define GPR_ROUND_UP_TO_ALIGNMENT_SIZE(x) \
(((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u))
#endif /* GRPC_CORE_LIB_GPR_ALLOC_H */

@ -40,4 +40,7 @@ void gpr_setenv(const char* name, const char* value);
level of logging. So DO NOT USE THIS. */
const char* gpr_getenv_silent(const char* name, char** dst);
/* Deletes the variable name from the environment. */
void gpr_unsetenv(const char* name);
#endif /* GRPC_CORE_LIB_GPR_ENV_H */

@ -79,4 +79,9 @@ void gpr_setenv(const char* name, const char* value) {
GPR_ASSERT(res == 0);
}
void gpr_unsetenv(const char* name) {
int res = unsetenv(name);
GPR_ASSERT(res == 0);
}
#endif /* GPR_LINUX_ENV */

@ -44,4 +44,9 @@ void gpr_setenv(const char* name, const char* value) {
GPR_ASSERT(res == 0);
}
void gpr_unsetenv(const char* name) {
int res = unsetenv(name);
GPR_ASSERT(res == 0);
}
#endif /* GPR_POSIX_ENV */

@ -69,4 +69,11 @@ void gpr_setenv(const char* name, const char* value) {
GPR_ASSERT(res);
}
void gpr_unsetenv(const char* name) {
LPTSTR tname = gpr_char_to_tchar(name);
BOOL res = SetEnvironmentVariable(tname, NULL);
gpr_free(tname);
GPR_ASSERT(res);
}
#endif /* GPR_WINDOWS_ENV */

@ -332,16 +332,22 @@ void* gpr_memrchr(const void* s, int c, size_t n) {
return nullptr;
}
bool gpr_is_true(const char* s) {
size_t i;
bool gpr_parse_bool_value(const char* s, bool* dst) {
const char* kTrue[] = {"1", "t", "true", "y", "yes"};
const char* kFalse[] = {"0", "f", "false", "n", "no"};
static_assert(sizeof(kTrue) == sizeof(kFalse), "true_false_equal");
if (s == nullptr) {
return false;
}
static const char* truthy[] = {"yes", "true", "1"};
for (i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
if (0 == gpr_stricmp(s, truthy[i])) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(kTrue); ++i) {
if (gpr_stricmp(s, kTrue[i]) == 0) {
*dst = true;
return true;
} else if (gpr_stricmp(s, kFalse[i]) == 0) {
*dst = false;
return true;
}
}
return false;
return false; // didn't match a legal input
}

@ -113,7 +113,9 @@ int gpr_stricmp(const char* a, const char* b);
void* gpr_memrchr(const void* s, int c, size_t n);
/** Return true if lower(s) equals "true", "yes" or "1", otherwise false. */
bool gpr_is_true(const char* s);
/* Try to parse given string into a boolean value.
When parsed successfully, dst will have the value and returns true.
Otherwise, it returns false. */
bool gpr_parse_bool_value(const char* value, bool* dst);
#endif /* GRPC_CORE_LIB_GPR_STRING_H */

@ -35,8 +35,8 @@ namespace {
void* ArenaStorage(size_t initial_size) {
static constexpr size_t base_size =
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_core::Arena));
initial_size = GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(initial_size);
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_core::Arena));
initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size);
size_t alloc_size = base_size + initial_size;
static constexpr size_t alignment =
(GPR_CACHELINE_SIZE > GPR_MAX_ALIGNMENT &&
@ -67,7 +67,7 @@ Arena* Arena::Create(size_t initial_size) {
Pair<Arena*, void*> Arena::CreateWithAlloc(size_t initial_size,
size_t alloc_size) {
static constexpr size_t base_size =
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(Arena));
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Arena));
auto* new_arena =
new (ArenaStorage(initial_size)) Arena(initial_size, alloc_size);
void* first_alloc = reinterpret_cast<char*>(new_arena) + base_size;
@ -88,7 +88,7 @@ void* Arena::AllocZone(size_t size) {
// sizing hysteresis (that is, most calls should have a large enough initial
// zone and will not need to grow the arena).
static constexpr size_t zone_base_size =
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(Zone));
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Zone));
size_t alloc_size = zone_base_size + size;
Zone* z = new (gpr_malloc_aligned(alloc_size, GPR_MAX_ALIGNMENT)) Zone();
{

@ -58,10 +58,10 @@ class Arena {
// Allocate \a size bytes from the arena.
void* Alloc(size_t size) {
static constexpr size_t base_size =
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(Arena));
size = GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(size);
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Arena));
size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(size);
size_t begin = total_used_.FetchAdd(size, MemoryOrder::RELAXED);
if (GPR_LIKELY(begin + size <= initial_zone_size_)) {
if (begin + size <= initial_zone_size_) {
return reinterpret_cast<char*>(this) + base_size + begin;
} else {
return AllocZone(size);

@ -0,0 +1,87 @@
/*
*
* Copyright 2019 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.
*
*/
#ifndef GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_H
#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_H
#include <grpc/support/port_platform.h>
#include <stdint.h>
// --------------------------------------------------------------------
// How to use global configuration variables:
//
// Defining config variables of a specified type:
// GPR_GLOBAL_CONFIG_DEFINE_*TYPE*(name, default_value, help);
//
// Supported TYPEs: BOOL, INT32, STRING
//
// It's recommended to use lowercase letters for 'name' like
// regular variables. The builtin configuration system uses
// environment variable and the name is converted to uppercase
// when looking up the value. For example,
// GPR_GLOBAL_CONFIG_DEFINE(grpc_latency) looks up the value with the
// name, "GRPC_LATENCY".
//
// The variable initially has the specified 'default_value'
// which must be an expression convertible to 'Type'.
// 'default_value' may be evaluated 0 or more times,
// and at an unspecified time; keep it
// simple and usually free of side-effects.
//
// GPR_GLOBAL_CONFIG_DEFINE_*TYPE* should not be called in a C++ header.
// It should be called at the top-level (outside any namespaces)
// in a .cc file.
//
// Getting the variables:
// GPR_GLOBAL_CONFIG_GET(name)
//
// If error happens during getting variables, error messages will
// be logged and default value will be returned.
//
// Setting the variables with new value:
// GPR_GLOBAL_CONFIG_SET(name, new_value)
//
// Declaring config variables for other modules to access:
// GPR_GLOBAL_CONFIG_DECLARE_*TYPE*(name)
// --------------------------------------------------------------------
// How to customize the global configuration system:
//
// How to read and write configuration value can be customized.
// Builtin system uses environment variables but it can be extended to
// support command-line flag, file, etc.
//
// To customize it, following macros should be redefined.
//
// GPR_GLOBAL_CONFIG_DEFINE_BOOL
// GPR_GLOBAL_CONFIG_DEFINE_INT32
// GPR_GLOBAL_CONFIG_DEFINE_STRING
//
// These macros should define functions for getting and setting variable.
// For example, GPR_GLOBAL_CONFIG_DEFINE_BOOL(test, ...) would define two
// functions.
//
// bool gpr_global_config_get_test();
// void gpr_global_config_set_test(bool value);
#include "src/core/lib/gprpp/global_config_env.h"
#include "src/core/lib/gprpp/global_config_custom.h"
#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_H */

@ -0,0 +1,29 @@
/*
*
* Copyright 2019 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.
*
*/
#ifndef GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H
#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H
// This is a placeholder for custom global configuration implementaion.
// To use the custom one, please define following macros here.
//
// GPR_GLOBAL_CONFIG_DEFINE_BOOL
// GPR_GLOBAL_CONFIG_DEFINE_INT32
// GPR_GLOBAL_CONFIG_DEFINE_STRING
#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H */

@ -0,0 +1,135 @@
/*
*
* Copyright 2019 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 <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/global_config_env.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include <ctype.h>
#include <string.h>
namespace grpc_core {
namespace {
void DefaultGlobalConfigEnvErrorFunction(const char* error_message) {
gpr_log(GPR_ERROR, "%s", error_message);
}
GlobalConfigEnvErrorFunctionType g_global_config_env_error_func =
DefaultGlobalConfigEnvErrorFunction;
void LogParsingError(const char* name, const char* value) {
char* error_message;
gpr_asprintf(&error_message,
"Illegal value '%s' specified for environment variable '%s'",
value, name);
(*g_global_config_env_error_func)(error_message);
gpr_free(error_message);
}
} // namespace
void SetGlobalConfigEnvErrorFunction(GlobalConfigEnvErrorFunctionType func) {
g_global_config_env_error_func = func;
}
UniquePtr<char> GlobalConfigEnv::GetValue() {
return UniquePtr<char>(gpr_getenv(GetName()));
}
void GlobalConfigEnv::SetValue(const char* value) {
gpr_setenv(GetName(), value);
}
void GlobalConfigEnv::Unset() { gpr_unsetenv(GetName()); }
char* GlobalConfigEnv::GetName() {
// This makes sure that name_ is in a canonical form having uppercase
// letters. This is okay to be called serveral times.
for (char* c = name_; *c != 0; ++c) {
*c = toupper(*c);
}
return name_;
}
static_assert(std::is_trivially_destructible<GlobalConfigEnvBool>::value,
"GlobalConfigEnvBool needs to be trivially destructible.");
bool GlobalConfigEnvBool::Get() {
UniquePtr<char> str = GetValue();
if (str == nullptr) {
return default_value_;
}
// parsing given value string.
bool result = false;
if (!gpr_parse_bool_value(str.get(), &result)) {
LogParsingError(GetName(), str.get());
result = default_value_;
}
return result;
}
void GlobalConfigEnvBool::Set(bool value) {
SetValue(value ? "true" : "false");
}
static_assert(std::is_trivially_destructible<GlobalConfigEnvInt32>::value,
"GlobalConfigEnvInt32 needs to be trivially destructible.");
int32_t GlobalConfigEnvInt32::Get() {
UniquePtr<char> str = GetValue();
if (str == nullptr) {
return default_value_;
}
// parsing given value string.
char* end = str.get();
long result = strtol(str.get(), &end, 10);
if (*end != 0) {
LogParsingError(GetName(), str.get());
result = default_value_;
}
return static_cast<int32_t>(result);
}
void GlobalConfigEnvInt32::Set(int32_t value) {
char buffer[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(value, buffer);
SetValue(buffer);
}
static_assert(std::is_trivially_destructible<GlobalConfigEnvString>::value,
"GlobalConfigEnvString needs to be trivially destructible.");
UniquePtr<char> GlobalConfigEnvString::Get() {
UniquePtr<char> str = GetValue();
if (str == nullptr) {
return UniquePtr<char>(gpr_strdup(default_value_));
}
return str;
}
void GlobalConfigEnvString::Set(const char* value) { SetValue(value); }
} // namespace grpc_core

@ -0,0 +1,131 @@
/*
*
* Copyright 2019 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.
*
*/
#ifndef GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_ENV_H
#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_ENV_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/global_config_generic.h"
#include "src/core/lib/gprpp/memory.h"
namespace grpc_core {
typedef void (*GlobalConfigEnvErrorFunctionType)(const char* error_message);
/*
* Set global_config_env_error_function which is called when config system
* encounters errors such as parsing error. What the default function does
* is logging error message.
*/
void SetGlobalConfigEnvErrorFunction(GlobalConfigEnvErrorFunctionType func);
// Base class for all classes to access environment variables.
class GlobalConfigEnv {
protected:
// `name` should be writable and alive after constructor is called.
constexpr explicit GlobalConfigEnv(char* name) : name_(name) {}
public:
// Returns the value of `name` variable.
UniquePtr<char> GetValue();
// Sets the value of `name` variable.
void SetValue(const char* value);
// Unsets `name` variable.
void Unset();
protected:
char* GetName();
private:
char* name_;
};
class GlobalConfigEnvBool : public GlobalConfigEnv {
public:
constexpr GlobalConfigEnvBool(char* name, bool default_value)
: GlobalConfigEnv(name), default_value_(default_value) {}
bool Get();
void Set(bool value);
private:
bool default_value_;
};
class GlobalConfigEnvInt32 : public GlobalConfigEnv {
public:
constexpr GlobalConfigEnvInt32(char* name, int32_t default_value)
: GlobalConfigEnv(name), default_value_(default_value) {}
int32_t Get();
void Set(int32_t value);
private:
int32_t default_value_;
};
class GlobalConfigEnvString : public GlobalConfigEnv {
public:
constexpr GlobalConfigEnvString(char* name, const char* default_value)
: GlobalConfigEnv(name), default_value_(default_value) {}
UniquePtr<char> Get();
void Set(const char* value);
private:
const char* default_value_;
};
} // namespace grpc_core
// Macros for defining global config instances using environment variables.
// This defines a GlobalConfig*Type* instance with arguments for
// mutable variable name and default value.
// Mutable name (g_env_str_##name) is here for having an array
// for the canonical name without dynamic allocation.
// `help` argument is ignored for this implementation.
#define GPR_GLOBAL_CONFIG_DEFINE_BOOL(name, default_value, help) \
static char g_env_str_##name[] = #name; \
static ::grpc_core::GlobalConfigEnvBool g_env_##name(g_env_str_##name, \
default_value); \
bool gpr_global_config_get_##name() { return g_env_##name.Get(); } \
void gpr_global_config_set_##name(bool value) { g_env_##name.Set(value); }
#define GPR_GLOBAL_CONFIG_DEFINE_INT32(name, default_value, help) \
static char g_env_str_##name[] = #name; \
static ::grpc_core::GlobalConfigEnvInt32 g_env_##name(g_env_str_##name, \
default_value); \
int32_t gpr_global_config_get_##name() { return g_env_##name.Get(); } \
void gpr_global_config_set_##name(int32_t value) { g_env_##name.Set(value); }
#define GPR_GLOBAL_CONFIG_DEFINE_STRING(name, default_value, help) \
static char g_env_str_##name[] = #name; \
static ::grpc_core::GlobalConfigEnvString g_env_##name(g_env_str_##name, \
default_value); \
::grpc_core::UniquePtr<char> gpr_global_config_get_##name() { \
return g_env_##name.Get(); \
} \
void gpr_global_config_set_##name(const char* value) { \
g_env_##name.Set(value); \
}
#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_ENV_H */

@ -0,0 +1,44 @@
/*
*
* Copyright 2019 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.
*
*/
#ifndef GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_GENERIC_H
#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_GENERIC_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/memory.h"
#include <stdint.h>
#define GPR_GLOBAL_CONFIG_GET(name) gpr_global_config_get_##name()
#define GPR_GLOBAL_CONFIG_SET(name, value) gpr_global_config_set_##name(value)
#define GPR_GLOBAL_CONFIG_DECLARE_BOOL(name) \
extern bool gpr_global_config_get_##name(); \
extern void gpr_global_config_set_##name(bool value)
#define GPR_GLOBAL_CONFIG_DECLARE_INT32(name) \
extern int32_t gpr_global_config_get_##name(); \
extern void gpr_global_config_set_##name(int32_t value)
#define GPR_GLOBAL_CONFIG_DECLARE_STRING(name) \
extern grpc_core::UniquePtr<char> gpr_global_config_get_##name(); \
extern void gpr_global_config_set_##name(const char* value)
#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_GENERIC_H */

@ -31,7 +31,7 @@
// Provides serialized access to some resource.
// Each action queued on a combiner is executed serially in a borrowed thread.
// The actual thread executing actions may change over time (but there will only
// every be one at a time).
// ever be one at a time).
// Initialize the lock, with an optional workqueue to shift load to when
// necessary

@ -384,7 +384,10 @@ static void fd_shutdown_internal(grpc_fd* fd, grpc_error* why,
if (!releasing_fd) {
shutdown(fd->fd, SHUT_RDWR);
} else {
if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_DEL, fd->fd, nullptr) != 0) {
/* we need a dummy event for earlier linux versions. */
epoll_event dummy_event;
if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_DEL, fd->fd, &dummy_event) !=
0) {
gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno));
}
}

@ -29,9 +29,9 @@
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/global_config.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/buffer_list.h"
#include "src/core/lib/iomgr/exec_ctx.h"
@ -41,6 +41,9 @@
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/iomgr/timer_manager.h"
GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_abort_on_leaks, false,
"Abort when leak is found");
static gpr_mu g_mu;
static gpr_cv g_rcv;
static int g_shutdown;
@ -186,8 +189,5 @@ void grpc_iomgr_unregister_object(grpc_iomgr_object* obj) {
}
bool grpc_iomgr_abort_on_leaks(void) {
char* env = gpr_getenv("GRPC_ABORT_ON_LEAKS");
bool should_we = gpr_is_true(env);
gpr_free(env);
return should_we;
return GPR_GLOBAL_CONFIG_GET(grpc_abort_on_leaks);
}

@ -30,6 +30,7 @@
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/global_config.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/context/security_context.h"
@ -47,9 +48,8 @@ static const char* installed_roots_path =
/** Environment variable used as a flag to enable/disable loading system root
certificates from the OS trust store. */
#ifndef GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR
#define GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_NOT_USE_SYSTEM_SSL_ROOTS"
#endif
GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_not_use_system_ssl_roots, false,
"Disable loading system root certificates.");
#ifndef TSI_OPENSSL_ALPN_SUPPORT
#define TSI_OPENSSL_ALPN_SUPPORT 1
@ -428,10 +428,8 @@ const char* DefaultSslRootStore::GetPemRootCerts() {
grpc_slice DefaultSslRootStore::ComputePemRootCerts() {
grpc_slice result = grpc_empty_slice();
char* not_use_system_roots_env_value =
gpr_getenv(GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR);
const bool not_use_system_roots = gpr_is_true(not_use_system_roots_env_value);
gpr_free(not_use_system_roots_env_value);
const bool not_use_system_roots =
GPR_GLOBAL_CONFIG_GET(grpc_not_use_system_ssl_roots);
// First try to load the roots from the environment.
char* default_root_certs_path =
gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);

@ -33,6 +33,10 @@
#define GROW(x) (3 * (x) / 2)
static void maybe_embiggen(grpc_slice_buffer* sb) {
if (sb->length == 0) {
sb->slices = sb->base_slices;
}
/* How far away from sb->base_slices is sb->slices pointer */
size_t slice_offset = static_cast<size_t>(sb->slices - sb->base_slices);
size_t slice_count = sb->count + slice_offset;
@ -177,6 +181,7 @@ void grpc_slice_buffer_reset_and_unref_internal(grpc_slice_buffer* sb) {
sb->count = 0;
sb->length = 0;
sb->slices = sb->base_slices;
}
void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer* sb) {

@ -222,7 +222,7 @@ inline uint32_t grpc_slice_refcount::Hash(const grpc_slice& slice) {
g_hash_seed);
}
inline grpc_slice grpc_slice_ref_internal(const grpc_slice& slice) {
inline const grpc_slice& grpc_slice_ref_internal(const grpc_slice& slice) {
if (slice.refcount) {
slice.refcount->Ref();
}

@ -260,10 +260,10 @@ grpc_core::TraceFlag grpc_compression_trace(false, "compression");
#define CALL_STACK_FROM_CALL(call) \
(grpc_call_stack*)((char*)(call) + \
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_call)))
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)))
#define CALL_FROM_CALL_STACK(call_stack) \
(grpc_call*)(((char*)(call_stack)) - \
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_call)))
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)))
#define CALL_ELEM_FROM_CALL(call, idx) \
grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
@ -329,7 +329,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
size_t initial_size = grpc_channel_get_call_size_estimate(args->channel);
GRPC_STATS_INC_CALL_INITIAL_SIZE(initial_size);
size_t call_and_stack_size =
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_call)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) +
channel_stack->call_stack_size;
size_t call_alloc_size =
call_and_stack_size + (args->parent ? sizeof(child_call) : 0);

@ -48,6 +48,18 @@ void grpc_error_get_status(grpc_error* error, grpc_millis deadline,
grpc_status_code* code, grpc_slice* slice,
grpc_http2_error_code* http_error,
const char** error_string) {
// Fast path: We expect no error.
if (GPR_LIKELY(error == GRPC_ERROR_NONE)) {
if (code != nullptr) *code = GRPC_STATUS_OK;
if (slice != nullptr) {
grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, slice);
}
if (http_error != nullptr) {
*http_error = GRPC_HTTP2_NO_ERROR;
}
return;
}
// Start with the parent error and recurse through the tree of children
// until we find the first one that has a status code.
grpc_error* found_error =

@ -115,7 +115,7 @@ void grpc_transport_move_stats(grpc_transport_stream_stats* from,
}
size_t grpc_transport_stream_size(grpc_transport* transport) {
return GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(transport->vtable->sizeof_stream);
return GPR_ROUND_UP_TO_ALIGNMENT_SIZE(transport->vtable->sizeof_stream);
}
void grpc_transport_destroy(grpc_transport* transport) {

@ -39,7 +39,7 @@ namespace Grpc.Core
/// Also, allocating a new buffer each time can put excessive pressure on GC, especially if
/// the payload is more than 86700 bytes large (which means the newly allocated buffer will be placed in LOH,
/// and LOH object can only be garbage collected via a full ("stop the world") GC run).
/// NOTE: Deserializers are expected not to call this method more than once per received message
/// NOTE: Deserializers are expected not to call this method (or other payload accessor methods) more than once per received message
/// (as there is no practical reason for doing so) and <c>DeserializationContext</c> implementations are free to assume so.
/// </summary>
/// <returns>byte array containing the entire payload.</returns>
@ -47,5 +47,22 @@ namespace Grpc.Core
{
throw new NotImplementedException();
}
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
/// <summary>
/// Gets the entire payload as a ReadOnlySequence.
/// The ReadOnlySequence is only valid for the duration of the deserializer routine and the caller must not access it after the deserializer returns.
/// Using the read only sequence is the most efficient way to access the message payload. Where possible it allows directly
/// accessing the received payload without needing to perform any buffer copying or buffer allocations.
/// NOTE: This method is only available in the netstandard2.0 build of the library.
/// NOTE: Deserializers are expected not to call this method (or other payload accessor methods) more than once per received message
/// (as there is no practical reason for doing so) and <c>DeserializationContext</c> implementations are free to assume so.
/// </summary>
/// <returns>read only sequence containing the entire payload.</returns>
public virtual System.Buffers.ReadOnlySequence<byte> PayloadAsReadOnlySequence()
{
throw new NotImplementedException();
}
#endif
}
}

@ -19,12 +19,20 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<DefineConstants>$(DefineConstants);GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY</DefineConstants>
</PropertyGroup>
<Import Project="..\Grpc.Core\SourceLink.csproj.include" />
<ItemGroup>
<PackageReference Include="System.Interactive.Async" Version="3.2.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Memory" Version="4.5.2" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />

@ -114,7 +114,8 @@ namespace Grpc.Core
/// <summary>
/// The service is currently unavailable. This is a most likely a
/// transient condition and may be corrected by retrying with
/// a backoff.
/// a backoff. Note that it is not always safe to retry
/// non-idempotent operations.
/// </summary>
Unavailable = 14,

@ -8,6 +8,10 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">
<DefineConstants>$(DefineConstants);GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
</ItemGroup>

@ -35,6 +35,7 @@ namespace Grpc.Core.Internal.Tests
Server server;
FakeNativeCall fakeCall;
AsyncCallServer<string, string> asyncCallServer;
FakeBufferReaderManager fakeBufferReaderManager;
[SetUp]
public void Init()
@ -52,11 +53,13 @@ namespace Grpc.Core.Internal.Tests
Marshallers.StringMarshaller.ContextualSerializer, Marshallers.StringMarshaller.ContextualDeserializer,
server);
asyncCallServer.InitializeForTesting(fakeCall);
fakeBufferReaderManager = new FakeBufferReaderManager();
}
[TearDown]
public void Cleanup()
{
fakeBufferReaderManager.Dispose();
server.ShutdownAsync().Wait();
}
@ -77,7 +80,7 @@ namespace Grpc.Core.Internal.Tests
var moveNextTask = requestStream.MoveNext();
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
Assert.IsFalse(moveNextTask.Result);
AssertFinished(asyncCallServer, fakeCall, finishedTask);
@ -107,7 +110,7 @@ namespace Grpc.Core.Internal.Tests
// if a read completion's success==false, the request stream will silently finish
// and we rely on C core cancelling the call.
var moveNextTask = requestStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, CreateNullResponse());
Assert.IsFalse(moveNextTask.Result);
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
@ -182,5 +185,10 @@ namespace Grpc.Core.Internal.Tests
Assert.IsTrue(finishedTask.IsCompleted);
Assert.DoesNotThrow(() => finishedTask.Wait());
}
IBufferReader CreateNullResponse()
{
return fakeBufferReaderManager.CreateNullPayloadBufferReader();
}
}
}

@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
namespace Grpc.Core.Internal.Tests
@ -33,6 +34,7 @@ namespace Grpc.Core.Internal.Tests
Channel channel;
FakeNativeCall fakeCall;
AsyncCall<string, string> asyncCall;
FakeBufferReaderManager fakeBufferReaderManager;
[SetUp]
public void Init()
@ -43,12 +45,14 @@ namespace Grpc.Core.Internal.Tests
var callDetails = new CallInvocationDetails<string, string>(channel, "someMethod", null, Marshallers.StringMarshaller, Marshallers.StringMarshaller, new CallOptions());
asyncCall = new AsyncCall<string, string>(callDetails, fakeCall);
fakeBufferReaderManager = new FakeBufferReaderManager();
}
[TearDown]
public void Cleanup()
{
channel.ShutdownAsync().Wait();
fakeBufferReaderManager.Dispose();
}
[Test]
@ -87,7 +91,7 @@ namespace Grpc.Core.Internal.Tests
var resultTask = asyncCall.UnaryCallAsync("request1");
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.InvalidArgument),
null,
CreateNullResponse(),
new Metadata());
AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.InvalidArgument);
@ -168,7 +172,7 @@ namespace Grpc.Core.Internal.Tests
var resultTask = asyncCall.ClientStreamingCallAsync();
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.InvalidArgument),
null,
CreateNullResponse(),
new Metadata());
AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.InvalidArgument);
@ -214,7 +218,7 @@ namespace Grpc.Core.Internal.Tests
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.Internal),
null,
CreateNullResponse(),
new Metadata());
var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
@ -233,7 +237,7 @@ namespace Grpc.Core.Internal.Tests
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.Internal),
null,
CreateNullResponse(),
new Metadata());
fakeCall.SendCompletionCallback.OnSendCompletion(false);
@ -259,7 +263,7 @@ namespace Grpc.Core.Internal.Tests
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.Internal),
null,
CreateNullResponse(),
new Metadata());
var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
@ -357,7 +361,7 @@ namespace Grpc.Core.Internal.Tests
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.Cancelled),
null,
CreateNullResponse(),
new Metadata());
AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Cancelled);
@ -390,7 +394,7 @@ namespace Grpc.Core.Internal.Tests
fakeCall.ReceivedResponseHeadersCallback.OnReceivedResponseHeaders(true, new Metadata());
Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
@ -405,7 +409,7 @@ namespace Grpc.Core.Internal.Tests
// try alternative order of completions
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
}
@ -417,7 +421,7 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, null); // after a failed read, we rely on C core to deliver appropriate status code.
fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, CreateNullResponse()); // after a failed read, we rely on C core to deliver appropriate status code.
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Internal));
AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Internal);
@ -441,7 +445,7 @@ namespace Grpc.Core.Internal.Tests
var readTask3 = responseStream.MoveNext();
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask3);
}
@ -479,7 +483,7 @@ namespace Grpc.Core.Internal.Tests
Assert.DoesNotThrowAsync(async () => await writeTask1);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
@ -493,7 +497,7 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
@ -511,7 +515,7 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
@ -533,7 +537,7 @@ namespace Grpc.Core.Internal.Tests
Assert.IsFalse(writeTask.IsCompleted);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.PermissionDenied));
var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
@ -552,7 +556,7 @@ namespace Grpc.Core.Internal.Tests
var writeTask = requestStream.WriteAsync("request1");
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.PermissionDenied));
fakeCall.SendCompletionCallback.OnSendCompletion(false);
@ -576,7 +580,7 @@ namespace Grpc.Core.Internal.Tests
Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await writeTask);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled));
AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Cancelled);
@ -597,7 +601,7 @@ namespace Grpc.Core.Internal.Tests
Assert.AreEqual("response1", responseStream.Current);
var readTask2 = responseStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled));
AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
@ -618,7 +622,7 @@ namespace Grpc.Core.Internal.Tests
Assert.AreEqual("response1", responseStream.Current);
var readTask2 = responseStream.MoveNext();
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse());
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled));
AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
@ -638,9 +642,14 @@ namespace Grpc.Core.Internal.Tests
return new ClientSideStatus(new Status(statusCode, ""), new Metadata());
}
byte[] CreateResponsePayload()
IBufferReader CreateResponsePayload()
{
return fakeBufferReaderManager.CreateSingleSegmentBufferReader(Marshallers.StringMarshaller.Serializer("response1"));
}
IBufferReader CreateNullResponse()
{
return Marshallers.StringMarshaller.Serializer("response1");
return fakeBufferReaderManager.CreateNullPayloadBufferReader();
}
static void AssertUnaryResponseSuccess(AsyncCall<string, string> asyncCall, FakeNativeCall fakeCall, Task<string> resultTask)

@ -0,0 +1,240 @@
#region Copyright notice and license
// Copyright 2019 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.Collections.Generic;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
using System.Runtime.InteropServices;
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
using System.Buffers;
#endif
namespace Grpc.Core.Internal.Tests
{
public class DefaultDeserializationContextTest
{
FakeBufferReaderManager fakeBufferReaderManager;
[SetUp]
public void Init()
{
fakeBufferReaderManager = new FakeBufferReaderManager();
}
[TearDown]
public void Cleanup()
{
fakeBufferReaderManager.Dispose();
}
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
[TestCase]
public void PayloadAsReadOnlySequence_ZeroSegmentPayload()
{
var context = new DefaultDeserializationContext();
context.Initialize(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> {}));
Assert.AreEqual(0, context.PayloadLength);
var sequence = context.PayloadAsReadOnlySequence();
Assert.AreEqual(ReadOnlySequence<byte>.Empty, sequence);
Assert.IsTrue(sequence.IsEmpty);
Assert.IsTrue(sequence.IsSingleSegment);
}
[TestCase(0)]
[TestCase(1)]
[TestCase(10)]
[TestCase(100)]
[TestCase(1000)]
public void PayloadAsReadOnlySequence_SingleSegmentPayload(int segmentLength)
{
var origBuffer = GetTestBuffer(segmentLength);
var context = new DefaultDeserializationContext();
context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer));
Assert.AreEqual(origBuffer.Length, context.PayloadLength);
var sequence = context.PayloadAsReadOnlySequence();
Assert.AreEqual(origBuffer.Length, sequence.Length);
Assert.AreEqual(origBuffer.Length, sequence.First.Length);
Assert.IsTrue(sequence.IsSingleSegment);
CollectionAssert.AreEqual(origBuffer, sequence.First.ToArray());
}
[TestCase(0, 5, 10)]
[TestCase(1, 1, 1)]
[TestCase(10, 100, 1000)]
[TestCase(100, 100, 10)]
[TestCase(1000, 1000, 1000)]
public void PayloadAsReadOnlySequence_MultiSegmentPayload(int segmentLen1, int segmentLen2, int segmentLen3)
{
var origBuffer1 = GetTestBuffer(segmentLen1);
var origBuffer2 = GetTestBuffer(segmentLen2);
var origBuffer3 = GetTestBuffer(segmentLen3);
int totalLen = origBuffer1.Length + origBuffer2.Length + origBuffer3.Length;
var context = new DefaultDeserializationContext();
context.Initialize(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> { origBuffer1, origBuffer2, origBuffer3 }));
Assert.AreEqual(totalLen, context.PayloadLength);
var sequence = context.PayloadAsReadOnlySequence();
Assert.AreEqual(totalLen, sequence.Length);
var segmentEnumerator = sequence.GetEnumerator();
Assert.IsTrue(segmentEnumerator.MoveNext());
CollectionAssert.AreEqual(origBuffer1, segmentEnumerator.Current.ToArray());
Assert.IsTrue(segmentEnumerator.MoveNext());
CollectionAssert.AreEqual(origBuffer2, segmentEnumerator.Current.ToArray());
Assert.IsTrue(segmentEnumerator.MoveNext());
CollectionAssert.AreEqual(origBuffer3, segmentEnumerator.Current.ToArray());
Assert.IsFalse(segmentEnumerator.MoveNext());
}
#endif
[TestCase]
public void NullPayloadNotAllowed()
{
var context = new DefaultDeserializationContext();
Assert.Throws(typeof(InvalidOperationException), () => context.Initialize(fakeBufferReaderManager.CreateNullPayloadBufferReader()));
}
[TestCase]
public void PayloadAsNewByteBuffer_ZeroSegmentPayload()
{
var context = new DefaultDeserializationContext();
context.Initialize(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> {}));
Assert.AreEqual(0, context.PayloadLength);
var payload = context.PayloadAsNewBuffer();
Assert.AreEqual(0, payload.Length);
}
[TestCase(0)]
[TestCase(1)]
[TestCase(10)]
[TestCase(100)]
[TestCase(1000)]
public void PayloadAsNewByteBuffer_SingleSegmentPayload(int segmentLength)
{
var origBuffer = GetTestBuffer(segmentLength);
var context = new DefaultDeserializationContext();
context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer));
Assert.AreEqual(origBuffer.Length, context.PayloadLength);
var payload = context.PayloadAsNewBuffer();
CollectionAssert.AreEqual(origBuffer, payload);
}
[TestCase(0, 5, 10)]
[TestCase(1, 1, 1)]
[TestCase(10, 100, 1000)]
[TestCase(100, 100, 10)]
[TestCase(1000, 1000, 1000)]
public void PayloadAsNewByteBuffer_MultiSegmentPayload(int segmentLen1, int segmentLen2, int segmentLen3)
{
var origBuffer1 = GetTestBuffer(segmentLen1);
var origBuffer2 = GetTestBuffer(segmentLen2);
var origBuffer3 = GetTestBuffer(segmentLen3);
var context = new DefaultDeserializationContext();
context.Initialize(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> { origBuffer1, origBuffer2, origBuffer3 }));
var payload = context.PayloadAsNewBuffer();
var concatenatedOrigBuffers = new List<byte>();
concatenatedOrigBuffers.AddRange(origBuffer1);
concatenatedOrigBuffers.AddRange(origBuffer2);
concatenatedOrigBuffers.AddRange(origBuffer3);
Assert.AreEqual(concatenatedOrigBuffers.Count, context.PayloadLength);
Assert.AreEqual(concatenatedOrigBuffers.Count, payload.Length);
CollectionAssert.AreEqual(concatenatedOrigBuffers, payload);
}
[TestCase]
public void GetPayloadMultipleTimesIsIllegal()
{
var origBuffer = GetTestBuffer(100);
var context = new DefaultDeserializationContext();
context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer));
Assert.AreEqual(origBuffer.Length, context.PayloadLength);
var payload = context.PayloadAsNewBuffer();
CollectionAssert.AreEqual(origBuffer, payload);
// Getting payload multiple times is illegal
Assert.Throws(typeof(InvalidOperationException), () => context.PayloadAsNewBuffer());
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
Assert.Throws(typeof(InvalidOperationException), () => context.PayloadAsReadOnlySequence());
#endif
}
[TestCase]
public void ResetContextAndReinitialize()
{
var origBuffer = GetTestBuffer(100);
var context = new DefaultDeserializationContext();
context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer));
Assert.AreEqual(origBuffer.Length, context.PayloadLength);
// Reset invalidates context
context.Reset();
Assert.AreEqual(0, context.PayloadLength);
Assert.Throws(typeof(NullReferenceException), () => context.PayloadAsNewBuffer());
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
Assert.Throws(typeof(NullReferenceException), () => context.PayloadAsReadOnlySequence());
#endif
// Previously reset context can be initialized again
var origBuffer2 = GetTestBuffer(50);
context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer2));
Assert.AreEqual(origBuffer2.Length, context.PayloadLength);
CollectionAssert.AreEqual(origBuffer2, context.PayloadAsNewBuffer());
}
private byte[] GetTestBuffer(int length)
{
var testBuffer = new byte[length];
for (int i = 0; i < testBuffer.Length; i++)
{
testBuffer[i] = (byte) i;
}
return testBuffer;
}
}
}

@ -0,0 +1,118 @@
#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.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal.Tests
{
// Creates instances of fake IBufferReader. All created instances will become invalid once Dispose is called.
internal class FakeBufferReaderManager : IDisposable
{
List<GCHandle> pinnedHandles = new List<GCHandle>();
bool disposed = false;
public IBufferReader CreateSingleSegmentBufferReader(byte[] data)
{
return CreateMultiSegmentBufferReader(new List<byte[]> { data });
}
public IBufferReader CreateMultiSegmentBufferReader(IEnumerable<byte[]> dataSegments)
{
GrpcPreconditions.CheckState(!disposed);
GrpcPreconditions.CheckNotNull(dataSegments);
var segments = new List<GCHandle>();
foreach (var data in dataSegments)
{
GrpcPreconditions.CheckNotNull(data);
segments.Add(GCHandle.Alloc(data, GCHandleType.Pinned));
}
pinnedHandles.AddRange(segments); // all the allocated GCHandles will be freed on Dispose()
return new FakeBufferReader(segments);
}
public IBufferReader CreateNullPayloadBufferReader()
{
GrpcPreconditions.CheckState(!disposed);
return new FakeBufferReader(null);
}
public void Dispose()
{
if (!disposed)
{
disposed = true;
for (int i = 0; i < pinnedHandles.Count; i++)
{
pinnedHandles[i].Free();
}
}
}
private class FakeBufferReader : IBufferReader
{
readonly List<GCHandle> bufferSegments;
readonly int? totalLength;
readonly IEnumerator<GCHandle> segmentEnumerator;
public FakeBufferReader(List<GCHandle> bufferSegments)
{
this.bufferSegments = bufferSegments;
this.totalLength = ComputeTotalLength(bufferSegments);
this.segmentEnumerator = bufferSegments?.GetEnumerator();
}
public int? TotalLength => totalLength;
public bool TryGetNextSlice(out Slice slice)
{
GrpcPreconditions.CheckNotNull(bufferSegments);
if (!segmentEnumerator.MoveNext())
{
slice = default(Slice);
return false;
}
var segment = segmentEnumerator.Current;
int sliceLen = ((byte[]) segment.Target).Length;
slice = new Slice(segment.AddrOfPinnedObject(), sliceLen);
return true;
}
static int? ComputeTotalLength(List<GCHandle> bufferSegments)
{
if (bufferSegments == null)
{
return null;
}
int sum = 0;
foreach (var segment in bufferSegments)
{
var data = (byte[]) segment.Target;
sum += data.Length;
}
return sum;
}
}
}
}

@ -0,0 +1,121 @@
#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.Collections.Generic;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
namespace Grpc.Core.Internal.Tests
{
public class FakeBufferReaderManagerTest
{
FakeBufferReaderManager fakeBufferReaderManager;
[SetUp]
public void Init()
{
fakeBufferReaderManager = new FakeBufferReaderManager();
}
[TearDown]
public void Cleanup()
{
fakeBufferReaderManager.Dispose();
}
[TestCase]
public void NullPayload()
{
var fakeBufferReader = fakeBufferReaderManager.CreateNullPayloadBufferReader();
Assert.IsFalse(fakeBufferReader.TotalLength.HasValue);
Assert.Throws(typeof(ArgumentNullException), () => fakeBufferReader.TryGetNextSlice(out Slice slice));
}
[TestCase]
public void ZeroSegmentPayload()
{
var fakeBufferReader = fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> {});
Assert.AreEqual(0, fakeBufferReader.TotalLength.Value);
Assert.IsFalse(fakeBufferReader.TryGetNextSlice(out Slice slice));
}
[TestCase(0)]
[TestCase(1)]
[TestCase(10)]
[TestCase(30)]
[TestCase(100)]
[TestCase(1000)]
public void SingleSegmentPayload(int bufferLen)
{
var origBuffer = GetTestBuffer(bufferLen);
var fakeBufferReader = fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer);
Assert.AreEqual(origBuffer.Length, fakeBufferReader.TotalLength.Value);
Assert.IsTrue(fakeBufferReader.TryGetNextSlice(out Slice slice));
AssertSliceDataEqual(origBuffer, slice);
Assert.IsFalse(fakeBufferReader.TryGetNextSlice(out Slice slice2));
}
[TestCase(0, 5, 10)]
[TestCase(1, 1, 1)]
[TestCase(10, 100, 1000)]
[TestCase(100, 100, 10)]
[TestCase(1000, 1000, 1000)]
public void MultiSegmentPayload(int segmentLen1, int segmentLen2, int segmentLen3)
{
var origBuffer1 = GetTestBuffer(segmentLen1);
var origBuffer2 = GetTestBuffer(segmentLen2);
var origBuffer3 = GetTestBuffer(segmentLen3);
var fakeBufferReader = fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> { origBuffer1, origBuffer2, origBuffer3 });
Assert.AreEqual(origBuffer1.Length + origBuffer2.Length + origBuffer3.Length, fakeBufferReader.TotalLength.Value);
Assert.IsTrue(fakeBufferReader.TryGetNextSlice(out Slice slice1));
AssertSliceDataEqual(origBuffer1, slice1);
Assert.IsTrue(fakeBufferReader.TryGetNextSlice(out Slice slice2));
AssertSliceDataEqual(origBuffer2, slice2);
Assert.IsTrue(fakeBufferReader.TryGetNextSlice(out Slice slice3));
AssertSliceDataEqual(origBuffer3, slice3);
Assert.IsFalse(fakeBufferReader.TryGetNextSlice(out Slice slice4));
}
private void AssertSliceDataEqual(byte[] expected, Slice actual)
{
var actualSliceData = new byte[actual.Length];
actual.CopyTo(new ArraySegment<byte>(actualSliceData));
CollectionAssert.AreEqual(expected, actualSliceData);
}
// create a buffer of given size and fill it with some data
private byte[] GetTestBuffer(int length)
{
var testBuffer = new byte[length];
for (int i = 0; i < testBuffer.Length; i++)
{
testBuffer[i] = (byte) i;
}
return testBuffer;
}
}
}

@ -0,0 +1,151 @@
#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.Collections.Generic;
using System.Linq;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
using System.Runtime.InteropServices;
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
using System.Buffers;
#endif
namespace Grpc.Core.Internal.Tests
{
// Converts IBufferReader into instances of ReadOnlySequence<byte>
// Objects representing the sequence segments are cached to decrease GC load.
public class ReusableSliceBufferTest
{
FakeBufferReaderManager fakeBufferReaderManager;
[SetUp]
public void Init()
{
fakeBufferReaderManager = new FakeBufferReaderManager();
}
[TearDown]
public void Cleanup()
{
fakeBufferReaderManager.Dispose();
}
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
[TestCase]
public void NullPayload()
{
var sliceBuffer = new ReusableSliceBuffer();
Assert.Throws(typeof(ArgumentNullException), () => sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateNullPayloadBufferReader()));
}
[TestCase]
public void ZeroSegmentPayload()
{
var sliceBuffer = new ReusableSliceBuffer();
var sequence = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> {}));
Assert.AreEqual(ReadOnlySequence<byte>.Empty, sequence);
Assert.IsTrue(sequence.IsEmpty);
Assert.IsTrue(sequence.IsSingleSegment);
}
[TestCase]
public void SegmentsAreCached()
{
var bufferSegments1 = Enumerable.Range(0, 100).Select((_) => GetTestBuffer(50)).ToList();
var bufferSegments2 = Enumerable.Range(0, 100).Select((_) => GetTestBuffer(50)).ToList();
var sliceBuffer = new ReusableSliceBuffer();
var sequence1 = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(bufferSegments1));
var memoryManagers1 = GetMemoryManagersForSequenceSegments(sequence1);
sliceBuffer.Invalidate();
var sequence2 = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(bufferSegments2));
var memoryManagers2 = GetMemoryManagersForSequenceSegments(sequence2);
// check memory managers are identical objects (i.e. they've been reused)
CollectionAssert.AreEquivalent(memoryManagers1, memoryManagers2);
}
[TestCase]
public void MultiSegmentPayload_LotsOfSegments()
{
var bufferSegments = Enumerable.Range(0, ReusableSliceBuffer.MaxCachedSegments + 100).Select((_) => GetTestBuffer(10)).ToList();
var sliceBuffer = new ReusableSliceBuffer();
var sequence = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(bufferSegments));
int index = 0;
foreach (var memory in sequence)
{
CollectionAssert.AreEqual(bufferSegments[index], memory.ToArray());
index ++;
}
}
[TestCase]
public void InvalidateMakesSequenceUnusable()
{
var origBuffer = GetTestBuffer(100);
var sliceBuffer = new ReusableSliceBuffer();
var sequence = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List<byte[]> { origBuffer }));
Assert.AreEqual(origBuffer.Length, sequence.Length);
sliceBuffer.Invalidate();
// Invalidate with make the returned sequence completely unusable and broken, users must not use it beyond the deserializer functions.
Assert.Throws(typeof(ArgumentOutOfRangeException), () => { var first = sequence.First; });
}
private List<MemoryManager<byte>> GetMemoryManagersForSequenceSegments(ReadOnlySequence<byte> sequence)
{
var result = new List<MemoryManager<byte>>();
foreach (var memory in sequence)
{
Assert.IsTrue(MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<byte> memoryManager));
result.Add(memoryManager);
}
return result;
}
#else
[TestCase]
public void OnlySupportedOnNetCore()
{
// Test case needs to exist to make C# sanity test happy.
}
#endif
private byte[] GetTestBuffer(int length)
{
var testBuffer = new byte[length];
for (int i = 0; i < testBuffer.Length; i++)
{
testBuffer[i] = (byte) i;
}
return testBuffer;
}
}
}

@ -0,0 +1,83 @@
#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 Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
using System.Runtime.InteropServices;
namespace Grpc.Core.Internal.Tests
{
public class SliceTest
{
[TestCase(0)]
[TestCase(1)]
[TestCase(10)]
[TestCase(100)]
[TestCase(1000)]
public void SliceFromNativePtr_CopyToArraySegment(int bufferLength)
{
var origBuffer = GetTestBuffer(bufferLength);
var gcHandle = GCHandle.Alloc(origBuffer, GCHandleType.Pinned);
try
{
var slice = new Slice(gcHandle.AddrOfPinnedObject(), origBuffer.Length);
Assert.AreEqual(bufferLength, slice.Length);
var newBuffer = new byte[bufferLength];
slice.CopyTo(new ArraySegment<byte>(newBuffer));
CollectionAssert.AreEqual(origBuffer, newBuffer);
}
finally
{
gcHandle.Free();
}
}
[TestCase]
public void SliceFromNativePtr_CopyToArraySegmentTooSmall()
{
var origBuffer = GetTestBuffer(100);
var gcHandle = GCHandle.Alloc(origBuffer, GCHandleType.Pinned);
try
{
var slice = new Slice(gcHandle.AddrOfPinnedObject(), origBuffer.Length);
var tooSmall = new byte[origBuffer.Length - 1];
Assert.Catch(typeof(ArgumentException), () => slice.CopyTo(new ArraySegment<byte>(tooSmall)));
}
finally
{
gcHandle.Free();
}
}
// create a buffer of given size and fill it with some data
private byte[] GetTestBuffer(int length)
{
var testBuffer = new byte[length];
for (int i = 0; i < testBuffer.Length; i++)
{
testBuffer[i] = (byte) i;
}
return testBuffer;
}
}
}

@ -18,6 +18,7 @@
using System.Runtime.CompilerServices;
using Grpc.Core;
using Grpc.Core.Interceptors;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
@ -32,16 +33,18 @@ using Grpc.Core.Utils;
[assembly:TypeForwardedToAttribute(typeof(AuthContext))]
[assembly:TypeForwardedToAttribute(typeof(AsyncAuthInterceptor))]
[assembly:TypeForwardedToAttribute(typeof(AuthInterceptorContext))]
[assembly: TypeForwardedToAttribute(typeof(CallCredentials))]
[assembly: TypeForwardedToAttribute(typeof(CallFlags))]
[assembly: TypeForwardedToAttribute(typeof(CallInvoker))]
[assembly: TypeForwardedToAttribute(typeof(CallOptions))]
[assembly:TypeForwardedToAttribute(typeof(CallCredentials))]
[assembly:TypeForwardedToAttribute(typeof(CallFlags))]
[assembly:TypeForwardedToAttribute(typeof(CallInvoker))]
[assembly:TypeForwardedToAttribute(typeof(CallOptions))]
[assembly:TypeForwardedToAttribute(typeof(ClientInterceptorContext<,>))]
[assembly:TypeForwardedToAttribute(typeof(ContextPropagationOptions))]
[assembly:TypeForwardedToAttribute(typeof(ContextPropagationToken))]
[assembly:TypeForwardedToAttribute(typeof(DeserializationContext))]
[assembly:TypeForwardedToAttribute(typeof(IAsyncStreamReader<>))]
[assembly:TypeForwardedToAttribute(typeof(IAsyncStreamWriter<>))]
[assembly:TypeForwardedToAttribute(typeof(IClientStreamWriter<>))]
[assembly:TypeForwardedToAttribute(typeof(Interceptor))]
[assembly:TypeForwardedToAttribute(typeof(IServerStreamWriter<>))]
[assembly:TypeForwardedToAttribute(typeof(Marshaller<>))]
[assembly:TypeForwardedToAttribute(typeof(Marshallers))]

@ -19,6 +19,15 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<LangVersion>7.2</LangVersion>
<DefineConstants>$(DefineConstants);GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core.Api\Version.cs" />
</ItemGroup>

@ -111,7 +111,7 @@ namespace Grpc.Core.Internal
{
using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch"))
{
HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata());
HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessageReader(), ctx.GetReceivedInitialMetadata());
}
}
catch (Exception e)
@ -537,14 +537,14 @@ namespace Grpc.Core.Internal
/// <summary>
/// Handler for unary response completion.
/// </summary>
private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders)
private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, IBufferReader receivedMessageReader, Metadata responseHeaders)
{
// NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT,
// success will be always set to true.
TaskCompletionSource<object> delayedStreamingWriteTcs = null;
TResponse msg = default(TResponse);
var deserializeException = TryDeserialize(receivedMessage, out msg);
var deserializeException = TryDeserialize(receivedMessageReader, out msg);
bool releasedResources;
lock (myLock)
@ -634,9 +634,9 @@ namespace Grpc.Core.Internal
IUnaryResponseClientCallback UnaryResponseClientCallback => this;
void IUnaryResponseClientCallback.OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders)
void IUnaryResponseClientCallback.OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, IBufferReader receivedMessageReader, Metadata responseHeaders)
{
HandleUnaryResponse(success, receivedStatus, receivedMessage, responseHeaders);
HandleUnaryResponse(success, receivedStatus, receivedMessageReader, responseHeaders);
}
IReceivedStatusOnClientCallback ReceivedStatusOnClientCallback => this;

@ -228,12 +228,12 @@ namespace Grpc.Core.Internal
}
}
protected Exception TryDeserialize(byte[] payload, out TRead msg)
protected Exception TryDeserialize(IBufferReader reader, out TRead msg)
{
DefaultDeserializationContext context = null;
try
{
context = DefaultDeserializationContext.GetInitializedThreadLocal(payload);
context = DefaultDeserializationContext.GetInitializedThreadLocal(reader);
msg = deserializer(context);
return null;
}
@ -245,7 +245,6 @@ namespace Grpc.Core.Internal
finally
{
context?.Reset();
}
}
@ -333,21 +332,21 @@ namespace Grpc.Core.Internal
/// <summary>
/// Handles streaming read completion.
/// </summary>
protected void HandleReadFinished(bool success, byte[] receivedMessage)
protected void HandleReadFinished(bool success, IBufferReader receivedMessageReader)
{
// if success == false, received message will be null. It that case we will
// if success == false, the message reader will report null payload. It that case we will
// treat this completion as the last read an rely on C core to handle the failed
// read (e.g. deliver approriate statusCode on the clientside).
TRead msg = default(TRead);
var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null;
var deserializeException = (success && receivedMessageReader.TotalLength.HasValue) ? TryDeserialize(receivedMessageReader, out msg) : null;
TaskCompletionSource<TRead> origTcs = null;
bool releasedResources;
lock (myLock)
{
origTcs = streamingReadTcs;
if (receivedMessage == null)
if (!receivedMessageReader.TotalLength.HasValue)
{
// This was the last read.
readingDone = true;
@ -391,9 +390,9 @@ namespace Grpc.Core.Internal
IReceivedMessageCallback ReceivedMessageCallback => this;
void IReceivedMessageCallback.OnReceivedMessage(bool success, byte[] receivedMessage)
void IReceivedMessageCallback.OnReceivedMessage(bool success, IBufferReader receivedMessageReader)
{
HandleReadFinished(success, receivedMessage);
HandleReadFinished(success, receivedMessageReader);
}
}
}

@ -30,10 +30,17 @@ namespace Grpc.Core.Internal
void OnComplete(bool success);
}
internal interface IBufferReader
{
int? TotalLength { get; }
bool TryGetNextSlice(out Slice slice);
}
/// <summary>
/// grpcsharp_batch_context
/// </summary>
internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback, IPooledObject<BatchContextSafeHandle>
internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback, IPooledObject<BatchContextSafeHandle>, IBufferReader
{
static readonly NativeMethods Native = NativeMethods.Get();
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<BatchContextSafeHandle>();
@ -93,17 +100,9 @@ namespace Grpc.Core.Internal
return new ClientSideStatus(status, metadata);
}
// Gets data of recv_message completion.
public byte[] GetReceivedMessage()
public IBufferReader GetReceivedMessageReader()
{
IntPtr len = Native.grpcsharp_batch_context_recv_message_length(this);
if (len == new IntPtr(-1))
{
return null;
}
byte[] data = new byte[(int)len];
Native.grpcsharp_batch_context_recv_message_to_buffer(this, data, new UIntPtr((ulong)data.Length));
return data;
return this;
}
// Gets data of receive_close_on_server completion.
@ -153,6 +152,29 @@ namespace Grpc.Core.Internal
}
}
int? IBufferReader.TotalLength
{
get
{
var len = Native.grpcsharp_batch_context_recv_message_length(this);
return len != new IntPtr(-1) ? (int?) len : null;
}
}
bool IBufferReader.TryGetNextSlice(out Slice slice)
{
UIntPtr sliceLen;
IntPtr sliceDataPtr;
if (0 == Native.grpcsharp_batch_context_recv_message_next_slice_peek(this, out sliceLen, out sliceDataPtr))
{
slice = default(Slice);
return false;
}
slice = new Slice(sliceDataPtr, (int) sliceLen);
return true;
}
struct CompletionCallbackData
{
public CompletionCallbackData(BatchCompletionDelegate callback, object state)

@ -35,11 +35,11 @@ namespace Grpc.Core.Internal
// Completion handlers are pre-allocated to avoid unneccessary delegate allocations.
// The "state" field is used to store the actual callback to invoke.
static readonly BatchCompletionDelegate CompletionHandler_IUnaryResponseClientCallback =
(success, context, state) => ((IUnaryResponseClientCallback)state).OnUnaryResponseClient(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata());
(success, context, state) => ((IUnaryResponseClientCallback)state).OnUnaryResponseClient(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessageReader(), context.GetReceivedInitialMetadata());
static readonly BatchCompletionDelegate CompletionHandler_IReceivedStatusOnClientCallback =
(success, context, state) => ((IReceivedStatusOnClientCallback)state).OnReceivedStatusOnClient(success, context.GetReceivedStatusOnClient());
static readonly BatchCompletionDelegate CompletionHandler_IReceivedMessageCallback =
(success, context, state) => ((IReceivedMessageCallback)state).OnReceivedMessage(success, context.GetReceivedMessage());
(success, context, state) => ((IReceivedMessageCallback)state).OnReceivedMessage(success, context.GetReceivedMessageReader());
static readonly BatchCompletionDelegate CompletionHandler_IReceivedResponseHeadersCallback =
(success, context, state) => ((IReceivedResponseHeadersCallback)state).OnReceivedResponseHeaders(success, context.GetReceivedInitialMetadata());
static readonly BatchCompletionDelegate CompletionHandler_ISendCompletionCallback =

@ -20,6 +20,10 @@ using Grpc.Core.Utils;
using System;
using System.Threading;
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
using System.Buffers;
#endif
namespace Grpc.Core.Internal
{
internal class DefaultDeserializationContext : DeserializationContext
@ -27,40 +31,71 @@ namespace Grpc.Core.Internal
static readonly ThreadLocal<DefaultDeserializationContext> threadLocalInstance =
new ThreadLocal<DefaultDeserializationContext>(() => new DefaultDeserializationContext(), false);
byte[] payload;
bool alreadyCalledPayloadAsNewBuffer;
IBufferReader bufferReader;
int payloadLength;
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
ReusableSliceBuffer cachedSliceBuffer = new ReusableSliceBuffer();
#endif
public DefaultDeserializationContext()
{
Reset();
}
public override int PayloadLength => payload.Length;
public override int PayloadLength => payloadLength;
public override byte[] PayloadAsNewBuffer()
{
GrpcPreconditions.CheckState(!alreadyCalledPayloadAsNewBuffer);
alreadyCalledPayloadAsNewBuffer = true;
return payload;
var buffer = new byte[payloadLength];
FillContinguousBuffer(bufferReader, buffer);
return buffer;
}
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
public override ReadOnlySequence<byte> PayloadAsReadOnlySequence()
{
var sequence = cachedSliceBuffer.PopulateFrom(bufferReader);
GrpcPreconditions.CheckState(sequence.Length == payloadLength);
return sequence;
}
#endif
public void Initialize(byte[] payload)
public void Initialize(IBufferReader bufferReader)
{
this.payload = GrpcPreconditions.CheckNotNull(payload);
this.alreadyCalledPayloadAsNewBuffer = false;
this.bufferReader = GrpcPreconditions.CheckNotNull(bufferReader);
this.payloadLength = bufferReader.TotalLength.Value; // payload must not be null
}
public void Reset()
{
this.payload = null;
this.alreadyCalledPayloadAsNewBuffer = true; // mark payload as read
this.bufferReader = null;
this.payloadLength = 0;
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
this.cachedSliceBuffer.Invalidate();
#endif
}
public static DefaultDeserializationContext GetInitializedThreadLocal(byte[] payload)
public static DefaultDeserializationContext GetInitializedThreadLocal(IBufferReader bufferReader)
{
var instance = threadLocalInstance.Value;
instance.Initialize(payload);
instance.Initialize(bufferReader);
return instance;
}
private void FillContinguousBuffer(IBufferReader reader, byte[] destination)
{
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
PayloadAsReadOnlySequence().CopyTo(new Span<byte>(destination));
#else
int offset = 0;
while (reader.TryGetNextSlice(out Slice slice))
{
slice.CopyTo(new ArraySegment<byte>(destination, offset, (int)slice.Length));
offset += (int)slice.Length;
}
// check that we filled the entire destination
GrpcPreconditions.CheckState(offset == payloadLength);
#endif
}
}
}

@ -22,7 +22,7 @@ namespace Grpc.Core.Internal
{
internal interface IUnaryResponseClientCallback
{
void OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders);
void OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, IBufferReader receivedMessageReader, Metadata responseHeaders);
}
// Received status for streaming response calls.
@ -33,7 +33,7 @@ namespace Grpc.Core.Internal
internal interface IReceivedMessageCallback
{
void OnReceivedMessage(bool success, byte[] receivedMessage);
void OnReceivedMessage(bool success, IBufferReader receivedMessageReader);
}
internal interface IReceivedResponseHeadersCallback

@ -40,7 +40,7 @@ namespace Grpc.Core.Internal
public readonly Delegates.grpcsharp_batch_context_create_delegate grpcsharp_batch_context_create;
public readonly Delegates.grpcsharp_batch_context_recv_initial_metadata_delegate grpcsharp_batch_context_recv_initial_metadata;
public readonly Delegates.grpcsharp_batch_context_recv_message_length_delegate grpcsharp_batch_context_recv_message_length;
public readonly Delegates.grpcsharp_batch_context_recv_message_to_buffer_delegate grpcsharp_batch_context_recv_message_to_buffer;
public readonly Delegates.grpcsharp_batch_context_recv_message_next_slice_peek_delegate grpcsharp_batch_context_recv_message_next_slice_peek;
public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_status_delegate grpcsharp_batch_context_recv_status_on_client_status;
public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_details_delegate grpcsharp_batch_context_recv_status_on_client_details;
public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate grpcsharp_batch_context_recv_status_on_client_trailing_metadata;
@ -141,7 +141,7 @@ namespace Grpc.Core.Internal
this.grpcsharp_batch_context_create = GetMethodDelegate<Delegates.grpcsharp_batch_context_create_delegate>(library);
this.grpcsharp_batch_context_recv_initial_metadata = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_initial_metadata_delegate>(library);
this.grpcsharp_batch_context_recv_message_length = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_message_length_delegate>(library);
this.grpcsharp_batch_context_recv_message_to_buffer = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_message_to_buffer_delegate>(library);
this.grpcsharp_batch_context_recv_message_next_slice_peek = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_message_next_slice_peek_delegate>(library);
this.grpcsharp_batch_context_recv_status_on_client_status = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_status_delegate>(library);
this.grpcsharp_batch_context_recv_status_on_client_details = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_details_delegate>(library);
this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate>(library);
@ -241,7 +241,7 @@ namespace Grpc.Core.Internal
this.grpcsharp_batch_context_create = DllImportsFromStaticLib.grpcsharp_batch_context_create;
this.grpcsharp_batch_context_recv_initial_metadata = DllImportsFromStaticLib.grpcsharp_batch_context_recv_initial_metadata;
this.grpcsharp_batch_context_recv_message_length = DllImportsFromStaticLib.grpcsharp_batch_context_recv_message_length;
this.grpcsharp_batch_context_recv_message_to_buffer = DllImportsFromStaticLib.grpcsharp_batch_context_recv_message_to_buffer;
this.grpcsharp_batch_context_recv_message_next_slice_peek = DllImportsFromStaticLib.grpcsharp_batch_context_recv_message_next_slice_peek;
this.grpcsharp_batch_context_recv_status_on_client_status = DllImportsFromStaticLib.grpcsharp_batch_context_recv_status_on_client_status;
this.grpcsharp_batch_context_recv_status_on_client_details = DllImportsFromStaticLib.grpcsharp_batch_context_recv_status_on_client_details;
this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = DllImportsFromStaticLib.grpcsharp_batch_context_recv_status_on_client_trailing_metadata;
@ -341,7 +341,7 @@ namespace Grpc.Core.Internal
this.grpcsharp_batch_context_create = DllImportsFromSharedLib.grpcsharp_batch_context_create;
this.grpcsharp_batch_context_recv_initial_metadata = DllImportsFromSharedLib.grpcsharp_batch_context_recv_initial_metadata;
this.grpcsharp_batch_context_recv_message_length = DllImportsFromSharedLib.grpcsharp_batch_context_recv_message_length;
this.grpcsharp_batch_context_recv_message_to_buffer = DllImportsFromSharedLib.grpcsharp_batch_context_recv_message_to_buffer;
this.grpcsharp_batch_context_recv_message_next_slice_peek = DllImportsFromSharedLib.grpcsharp_batch_context_recv_message_next_slice_peek;
this.grpcsharp_batch_context_recv_status_on_client_status = DllImportsFromSharedLib.grpcsharp_batch_context_recv_status_on_client_status;
this.grpcsharp_batch_context_recv_status_on_client_details = DllImportsFromSharedLib.grpcsharp_batch_context_recv_status_on_client_details;
this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = DllImportsFromSharedLib.grpcsharp_batch_context_recv_status_on_client_trailing_metadata;
@ -444,7 +444,7 @@ namespace Grpc.Core.Internal
public delegate BatchContextSafeHandle grpcsharp_batch_context_create_delegate();
public delegate IntPtr grpcsharp_batch_context_recv_initial_metadata_delegate(BatchContextSafeHandle ctx);
public delegate IntPtr grpcsharp_batch_context_recv_message_length_delegate(BatchContextSafeHandle ctx);
public delegate void grpcsharp_batch_context_recv_message_to_buffer_delegate(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen);
public delegate int grpcsharp_batch_context_recv_message_next_slice_peek_delegate(BatchContextSafeHandle ctx, out UIntPtr sliceLen, out IntPtr sliceDataPtr);
public delegate StatusCode grpcsharp_batch_context_recv_status_on_client_status_delegate(BatchContextSafeHandle ctx);
public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_details_delegate(BatchContextSafeHandle ctx, out UIntPtr detailsLength);
public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate(BatchContextSafeHandle ctx);
@ -562,7 +562,7 @@ namespace Grpc.Core.Internal
public static extern IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx);
[DllImport(ImportName)]
public static extern void grpcsharp_batch_context_recv_message_to_buffer(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen);
public static extern int grpcsharp_batch_context_recv_message_next_slice_peek(BatchContextSafeHandle ctx, out UIntPtr sliceLen, out IntPtr sliceDataPtr);
[DllImport(ImportName)]
public static extern StatusCode grpcsharp_batch_context_recv_status_on_client_status(BatchContextSafeHandle ctx);
@ -858,7 +858,7 @@ namespace Grpc.Core.Internal
public static extern IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx);
[DllImport(ImportName)]
public static extern void grpcsharp_batch_context_recv_message_to_buffer(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen);
public static extern int grpcsharp_batch_context_recv_message_next_slice_peek(BatchContextSafeHandle ctx, out UIntPtr sliceLen, out IntPtr sliceDataPtr);
[DllImport(ImportName)]
public static extern StatusCode grpcsharp_batch_context_recv_status_on_client_status(BatchContextSafeHandle ctx);

@ -0,0 +1,148 @@
#region Copyright notice and license
// Copyright 2019 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
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
using Grpc.Core.Utils;
using System;
using System.Threading;
using System.Buffers;
namespace Grpc.Core.Internal
{
internal class ReusableSliceBuffer
{
public const int MaxCachedSegments = 1024; // ~4MB payload for 4K slices
readonly SliceSegment[] cachedSegments = new SliceSegment[MaxCachedSegments];
int populatedSegmentCount;
public ReadOnlySequence<byte> PopulateFrom(IBufferReader bufferReader)
{
populatedSegmentCount = 0;
long offset = 0;
SliceSegment prevSegment = null;
while (bufferReader.TryGetNextSlice(out Slice slice))
{
// Initialize cached segment if still null or just allocate a new segment if we already reached MaxCachedSegments
var current = populatedSegmentCount < cachedSegments.Length ? cachedSegments[populatedSegmentCount] : new SliceSegment();
if (current == null)
{
current = cachedSegments[populatedSegmentCount] = new SliceSegment();
}
current.Reset(slice, offset);
prevSegment?.SetNext(current);
populatedSegmentCount ++;
offset += slice.Length;
prevSegment = current;
}
// Not necessary for ending the ReadOnlySequence, but for making sure we
// don't keep more than MaxCachedSegments alive.
prevSegment?.SetNext(null);
if (populatedSegmentCount == 0)
{
return ReadOnlySequence<byte>.Empty;
}
var firstSegment = cachedSegments[0];
var lastSegment = prevSegment;
return new ReadOnlySequence<byte>(firstSegment, 0, lastSegment, lastSegment.Memory.Length);
}
public void Invalidate()
{
if (populatedSegmentCount == 0)
{
return;
}
var segment = cachedSegments[0];
while (segment != null)
{
segment.Reset(new Slice(IntPtr.Zero, 0), 0);
var nextSegment = (SliceSegment) segment.Next;
segment.SetNext(null);
segment = nextSegment;
}
populatedSegmentCount = 0;
}
// Represents a segment in ReadOnlySequence
// Segment is backed by Slice and the instances are reusable.
private class SliceSegment : ReadOnlySequenceSegment<byte>
{
readonly SliceMemoryManager pointerMemoryManager = new SliceMemoryManager();
public void Reset(Slice slice, long runningIndex)
{
pointerMemoryManager.Reset(slice);
Memory = pointerMemoryManager.Memory; // maybe not always necessary
RunningIndex = runningIndex;
}
public void SetNext(ReadOnlySequenceSegment<byte> next)
{
Next = next;
}
}
// Allow creating instances of Memory<byte> from Slice.
// Represents a chunk of native memory, but doesn't manage its lifetime.
// Instances of this class are reuseable - they can be reset to point to a different memory chunk.
// That is important to make the instances cacheable (rather then creating new instances
// the old ones will be reused to reduce GC pressure).
private class SliceMemoryManager : MemoryManager<byte>
{
private Slice slice;
public void Reset(Slice slice)
{
this.slice = slice;
}
public void Reset()
{
Reset(new Slice(IntPtr.Zero, 0));
}
public override Span<byte> GetSpan()
{
return slice.ToSpanUnsafe();
}
public override MemoryHandle Pin(int elementIndex = 0)
{
throw new NotSupportedException();
}
public override void Unpin()
{
}
protected override void Dispose(bool disposing)
{
// NOP
}
}
}
}
#endif

@ -0,0 +1,68 @@
#region Copyright notice and license
// Copyright 2019 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.Runtime.InteropServices;
using System.Threading;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
/// <summary>
/// Slice of native memory.
/// Rough equivalent of grpc_slice (but doesn't support inlined slices, just a pointer to data and length)
/// </summary>
internal struct Slice
{
private readonly IntPtr dataPtr;
private readonly int length;
public Slice(IntPtr dataPtr, int length)
{
this.dataPtr = dataPtr;
this.length = length;
}
public int Length => length;
// copies data of the slice to given span.
// there needs to be enough space in the destination buffer
public void CopyTo(ArraySegment<byte> destination)
{
Marshal.Copy(dataPtr, destination.Array, destination.Offset, length);
}
#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY
public Span<byte> ToSpanUnsafe()
{
unsafe
{
return new Span<byte>((byte*) dataPtr, length);
}
}
#endif
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="Grpc.Core.Internal.Slice"/>.
/// </summary>
public override string ToString()
{
return string.Format("[Slice: dataPtr={0}, length={1}]", dataPtr, length);
}
}
}

@ -28,6 +28,7 @@
<ProtoRoot Condition="'%(Protobuf.ProtoRoot)' == '' " />
<CompileOutputs Condition="'%(Protobuf.CompileOutputs)' == ''">True</CompileOutputs>
<OutputDir Condition="'%(Protobuf.OutputDir)' == '' ">$(Protobuf_OutputPath)</OutputDir>
<Generator Condition="'%(Protobuf.Generator)' == '' and '$(DisableProtobufDesignTimeBuild)' != 'true' " >MSBuild:Compile</Generator>
</Protobuf>
</ItemDefinitionGroup>

@ -59,12 +59,16 @@ typedef struct grpcsharp_batch_context {
} send_status_from_server;
grpc_metadata_array recv_initial_metadata;
grpc_byte_buffer* recv_message;
grpc_byte_buffer_reader* recv_message_reader;
struct {
grpc_metadata_array trailing_metadata;
grpc_status_code status;
grpc_slice status_details;
} recv_status_on_client;
int recv_close_on_server_cancelled;
/* reserve space for byte_buffer_reader */
grpc_byte_buffer_reader reserved_recv_message_reader;
} grpcsharp_batch_context;
GPR_EXPORT grpcsharp_batch_context* GPR_CALLTYPE
@ -206,6 +210,9 @@ grpcsharp_batch_context_reset(grpcsharp_batch_context* ctx) {
grpcsharp_metadata_array_destroy_metadata_only(&(ctx->recv_initial_metadata));
if (ctx->recv_message_reader) {
grpc_byte_buffer_reader_destroy(ctx->recv_message_reader);
}
grpc_byte_buffer_destroy(ctx->recv_message);
grpcsharp_metadata_array_destroy_metadata_only(
@ -264,27 +271,42 @@ GPR_EXPORT intptr_t GPR_CALLTYPE grpcsharp_batch_context_recv_message_length(
}
/*
* Copies data from recv_message to a buffer. Fatal error occurs if
* buffer is too small.
* Gets the next slice from recv_message byte buffer.
* Returns 1 if a slice was get successfully, 0 if there are no more slices to
* read. Set slice_len to the length of the slice and the slice_data_ptr to
* point to slice's data. Caller must ensure that the byte buffer being read
* from stays alive as long as the data of the slice are being accessed
* (grpc_byte_buffer_reader_peek method is used internally)
*
* Remarks:
* Slices can only be iterated once.
* Initializes recv_message_buffer_reader if it was not initialized yet.
*/
GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_recv_message_to_buffer(
const grpcsharp_batch_context* ctx, char* buffer, size_t buffer_len) {
grpc_byte_buffer_reader reader;
grpc_slice slice;
size_t offset = 0;
GPR_EXPORT int GPR_CALLTYPE
grpcsharp_batch_context_recv_message_next_slice_peek(
grpcsharp_batch_context* ctx, size_t* slice_len, uint8_t** slice_data_ptr) {
*slice_len = 0;
*slice_data_ptr = NULL;
GPR_ASSERT(grpc_byte_buffer_reader_init(&reader, ctx->recv_message));
if (!ctx->recv_message) {
return 0;
}
while (grpc_byte_buffer_reader_next(&reader, &slice)) {
size_t len = GRPC_SLICE_LENGTH(slice);
GPR_ASSERT(offset + len <= buffer_len);
memcpy(buffer + offset, GRPC_SLICE_START_PTR(slice),
GRPC_SLICE_LENGTH(slice));
offset += len;
grpc_slice_unref(slice);
if (!ctx->recv_message_reader) {
ctx->recv_message_reader = &ctx->reserved_recv_message_reader;
GPR_ASSERT(grpc_byte_buffer_reader_init(ctx->recv_message_reader,
ctx->recv_message));
}
grpc_byte_buffer_reader_destroy(&reader);
grpc_slice* slice_ptr;
if (!grpc_byte_buffer_reader_peek(ctx->recv_message_reader, &slice_ptr)) {
return 0;
}
/* recv_message buffer must not be deleted before all the data is read */
*slice_len = GRPC_SLICE_LENGTH(*slice_ptr);
*slice_data_ptr = GRPC_SLICE_START_PTR(*slice_ptr);
return 1;
}
GPR_EXPORT grpc_status_code GPR_CALLTYPE

@ -7,8 +7,12 @@
"Grpc.Core.Internal.Tests.ChannelArgsSafeHandleTest",
"Grpc.Core.Internal.Tests.CompletionQueueEventTest",
"Grpc.Core.Internal.Tests.CompletionQueueSafeHandleTest",
"Grpc.Core.Internal.Tests.DefaultDeserializationContextTest",
"Grpc.Core.Internal.Tests.DefaultObjectPoolTest",
"Grpc.Core.Internal.Tests.FakeBufferReaderManagerTest",
"Grpc.Core.Internal.Tests.MetadataArraySafeHandleTest",
"Grpc.Core.Internal.Tests.ReusableSliceBufferTest",
"Grpc.Core.Internal.Tests.SliceTest",
"Grpc.Core.Internal.Tests.TimespecTest",
"Grpc.Core.Tests.AppDomainUnloadTest",
"Grpc.Core.Tests.AuthContextTest",

@ -46,7 +46,7 @@ void grpcsharp_batch_context_recv_message_length() {
fprintf(stderr, "Should never reach here");
abort();
}
void grpcsharp_batch_context_recv_message_to_buffer() {
void grpcsharp_batch_context_recv_message_next_slice_peek() {
fprintf(stderr, "Should never reach here");
abort();
}

@ -135,7 +135,8 @@ typedef NS_ENUM(NSUInteger, GRPCErrorCode) {
/**
* The server is currently unavailable. This is most likely a transient condition and may be
* corrected by retrying with a backoff.
* corrected by retrying with a backoff. Note that it is not always safe to retry
* non-idempotent operations.
*/
GRPCErrorCodeUnavailable = 14,

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

Loading…
Cancel
Save