Merge branch 'master' of https://github.com/grpc/grpc into upmerge-from-v1.7

pull/13466/head
Nicolas "Pixel" Noble 7 years ago
commit 361f8108e4
  1. 14
      BUILD
  2. 390
      CMakeLists.txt
  3. 4
      INSTALL.md
  4. 132
      Makefile
  5. 4
      README.md
  6. 61
      WORKSPACE
  7. 4
      bazel/cc_grpc_library.bzl
  8. 50
      build.yaml
  9. 1
      config.m4
  10. 1
      config.w32
  11. 197
      doc/core/transport_explainer.md
  12. 1
      doc/g_stands_for.md
  13. 4
      examples/BUILD
  14. 3
      examples/python/route_guide/route_guide_client.py
  15. 9
      gRPC-Core.podspec
  16. 2
      gRPC-ProtoRPC.podspec
  17. 2
      gRPC-RxLibrary.podspec
  18. 2
      gRPC.podspec
  19. 4
      grpc.gemspec
  20. 4
      grpc.gyp
  21. 6
      include/grpc++/impl/codegen/call.h
  22. 2
      include/grpc/grpc_security.h
  23. 4
      include/grpc/impl/codegen/grpc_types.h
  24. 21
      include/grpc/impl/codegen/port_platform.h
  25. 2
      include/grpc/support/alloc.h
  26. 2
      include/grpc/support/log.h
  27. 8
      package.xml
  28. 2
      requirements.txt
  29. 2
      setup.py
  30. 2
      src/compiler/cpp_generator.cc
  31. 2
      src/compiler/csharp_generator.cc
  32. 2
      src/compiler/node_generator.cc
  33. 2
      src/compiler/objective_c_generator.cc
  34. 12
      src/compiler/objective_c_plugin.cc
  35. 2
      src/compiler/php_generator.cc
  36. 1
      src/compiler/protobuf_plugin.h
  37. 2
      src/compiler/python_generator.cc
  38. 2
      src/compiler/ruby_generator.cc
  39. 1
      src/compiler/schema_interface.h
  40. 2
      src/core/ext/filters/client_channel/subchannel_index.cc
  41. 2
      src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
  42. 9
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  43. 1
      src/core/ext/transport/chttp2/transport/flow_control.h
  44. 1
      src/core/lib/channel/channel_stack.h
  45. 4
      src/core/lib/debug/trace.cc
  46. 10
      src/core/lib/iomgr/ev_epoll1_linux.cc
  47. 10
      src/core/lib/iomgr/ev_epollex_linux.cc
  48. 10
      src/core/lib/iomgr/ev_epollsig_linux.cc
  49. 6
      src/core/lib/iomgr/lockfree_event.cc
  50. 7
      src/core/lib/iomgr/lockfree_event.h
  51. 2
      src/core/lib/iomgr/sockaddr_utils.cc
  52. 29
      src/core/lib/support/abstract.h
  53. 30
      src/core/lib/support/cpu_posix.cc
  54. 135
      src/core/lib/support/manual_constructor.h
  55. 19
      src/core/lib/support/murmur_hash.cc
  56. 137
      src/core/lib/support/stack_lockfree.cc
  57. 46
      src/core/lib/support/stack_lockfree.h
  58. 34
      src/core/lib/surface/call.cc
  59. 4
      src/core/lib/surface/version.cc
  60. 9
      src/core/lib/transport/error_utils.cc
  61. 8
      src/core/lib/transport/error_utils.h
  62. 2
      src/cpp/common/version_cc.cc
  63. 28
      src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
  64. 106
      src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
  65. 58
      src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
  66. 4
      src/csharp/Grpc.Core.Tests/PInvokeTest.cs
  67. 28
      src/csharp/Grpc.Core/Channel.cs
  68. 37
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  69. 20
      src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
  70. 42
      src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
  71. 48
      src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
  72. 61
      src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
  73. 4
      src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
  74. 85
      src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
  75. 8
      src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
  76. 57
      src/csharp/Grpc.Core/Internal/INativeCall.cs
  77. 4
      src/csharp/Grpc.Core/Internal/NativeMethods.cs
  78. 23
      src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs
  79. 12
      src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
  80. 4
      src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
  81. 2
      src/csharp/Grpc.Core/Server.cs
  82. 2
      src/csharp/Grpc.Core/Version.csproj.include
  83. 4
      src/csharp/Grpc.Core/VersionInfo.cs
  84. 78
      src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs
  85. 69
      src/csharp/Grpc.Microbenchmarks/GCStats.cs
  86. 4
      src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
  87. 64
      src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs
  88. 70
      src/csharp/Grpc.Microbenchmarks/Program.cs
  89. 14
      src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs
  90. 3
      src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs
  91. 2
      src/csharp/build_packages_dotnetcli.bat
  92. 4
      src/csharp/build_packages_dotnetcli.sh
  93. 2
      src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
  94. 6
      src/objective-c/GRPCClient/GRPCCall.m
  95. 4
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
  96. 4
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
  97. 2
      src/objective-c/GRPCClient/private/GRPCHost.m
  98. 10
      src/objective-c/GRPCClient/private/GRPCWrappedCall.h
  99. 14
      src/objective-c/GRPCClient/private/GRPCWrappedCall.m
  100. 2
      src/objective-c/GRPCClient/private/version.h
  101. Some files were not shown because too many files have changed in this diff Show More

14
BUILD

@ -418,7 +418,6 @@ grpc_cc_library(
],
external_deps = [
"nanopb",
"libssl",
],
language = "c++",
public_hdrs = [
@ -456,7 +455,6 @@ grpc_cc_library(
"src/core/lib/support/log_windows.cc",
"src/core/lib/support/mpscq.cc",
"src/core/lib/support/murmur_hash.cc",
"src/core/lib/support/stack_lockfree.cc",
"src/core/lib/support/string.cc",
"src/core/lib/support/string_posix.cc",
"src/core/lib/support/string_util_windows.cc",
@ -481,6 +479,7 @@ grpc_cc_library(
],
hdrs = [
"src/core/lib/profiling/timers.h",
"src/core/lib/support/abstract.h",
"src/core/lib/support/arena.h",
"src/core/lib/support/atomic.h",
"src/core/lib/support/atomic_with_atm.h",
@ -490,21 +489,22 @@ grpc_cc_library(
"src/core/lib/support/memory.h",
"src/core/lib/support/vector.h",
"src/core/lib/support/manual_constructor.h",
"src/core/lib/support/memory.h",
"src/core/lib/support/mpscq.h",
"src/core/lib/support/murmur_hash.h",
"src/core/lib/support/spinlock.h",
"src/core/lib/support/stack_lockfree.h",
"src/core/lib/support/string.h",
"src/core/lib/support/string_windows.h",
"src/core/lib/support/thd_internal.h",
"src/core/lib/support/time_precise.h",
"src/core/lib/support/tmpfile.h",
"src/core/lib/support/vector.h",
],
language = "c++",
public_hdrs = GPR_PUBLIC_HDRS,
deps = [
"gpr_codegen",
"@com_google_absl//absl/container:inlined_vector"
"@com_google_absl//absl/container:inlined_vector",
],
)
@ -677,6 +677,7 @@ grpc_cc_library(
"src/core/lib/transport/transport_op_string.cc",
],
hdrs = [
"src/core/lib/backoff/backoff.h",
"src/core/lib/channel/channel_args.h",
"src/core/lib/channel/channel_stack.h",
"src/core/lib/channel/channel_stack_builder.h",
@ -695,6 +696,7 @@ grpc_cc_library(
"src/core/lib/http/format_request.h",
"src/core/lib/http/httpcli.h",
"src/core/lib/http/parser.h",
"src/core/lib/iomgr/block_annotate.h",
"src/core/lib/iomgr/call_combiner.h",
"src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/combiner.h",
@ -739,7 +741,6 @@ grpc_cc_library(
"src/core/lib/iomgr/socket_utils_posix.h",
"src/core/lib/iomgr/socket_windows.h",
"src/core/lib/iomgr/sys_epoll_wrapper.h",
"src/core/lib/iomgr/block_annotate.h",
"src/core/lib/iomgr/tcp_client.h",
"src/core/lib/iomgr/tcp_client_posix.h",
"src/core/lib/iomgr/tcp_posix.h",
@ -795,7 +796,6 @@ grpc_cc_library(
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
"src/core/lib/transport/transport_impl.h",
"src/core/lib/backoff/backoff.h",
],
external_deps = [
"zlib",
@ -1255,8 +1255,8 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/bin_decoder.h",
"src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h",
"src/core/ext/transport/chttp2/transport/frame.h",
"src/core/ext/transport/chttp2/transport/flow_control.h",
"src/core/ext/transport/chttp2/transport/frame.h",
"src/core/ext/transport/chttp2/transport/frame_data.h",
"src/core/ext/transport/chttp2/transport/frame_goaway.h",
"src/core/ext/transport/chttp2/transport/frame_ping.h",

File diff suppressed because it is too large Load Diff

@ -94,6 +94,7 @@ on experience with the tools involved.
### Building using CMake (RECOMMENDED)
Builds gRPC C and C++ with boringssl.
- Install [Git](https://git-scm.com/).
- Install Visual Studio 2015 or 2017 (Visual C++ compiler will be used).
- Install [CMake](https://cmake.org/download/).
- Install [Active State Perl](https://www.activestate.com/activeperl/) (`choco install activeperl`)
@ -106,11 +107,14 @@ Builds gRPC C and C++ with boringssl.
Please note that when using Ninja, you'll still need Visual C++ (part of Visual Studio)
installed to be able to compile the C/C++ sources.
```
> powershell git clone --recursive -b ((New-Object System.Net.WebClient).DownloadString(\"https://grpc.io/release\").Trim()) https://github.com/grpc/grpc
> cd grpc
> md .build
> cd .build
> call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" x64
> cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
> cmake --build .
> ninja
```
#### cmake: Using Visual Studio 2015 (can only build with OPENSSL_NO_ASM).

@ -114,7 +114,7 @@ CC_msan = clang
CXX_msan = clang++
LD_msan = clang++
LDXX_msan = clang++
CPPFLAGS_msan = -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
CPPFLAGS_msan = -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins -fsanitize-memory-use-after-dtor -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
DEFINES_msan = NDEBUG
@ -327,7 +327,8 @@ CXXFLAGS += -std=c++11
ifeq ($(SYSTEM),Darwin)
CXXFLAGS += -stdlib=libc++
endif
CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 -Ithird_party/abseil-cpp
CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
COREFLAGS += -fno-rtti -fno-exceptions
LDFLAGS += -g
CPPFLAGS += $(CPPFLAGS_$(CONFIG))
@ -410,9 +411,9 @@ E = @echo
Q = @
endif
CORE_VERSION = 5.0.0
CPP_VERSION = 1.7.2
CSHARP_VERSION = 1.7.2
CORE_VERSION = 5.0.0-dev
CPP_VERSION = 1.9.0-dev
CSHARP_VERSION = 1.9.0-dev
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@ -990,9 +991,9 @@ gpr_env_test: $(BINDIR)/$(CONFIG)/gpr_env_test
gpr_histogram_test: $(BINDIR)/$(CONFIG)/gpr_histogram_test
gpr_host_port_test: $(BINDIR)/$(CONFIG)/gpr_host_port_test
gpr_log_test: $(BINDIR)/$(CONFIG)/gpr_log_test
gpr_manual_constructor_test: $(BINDIR)/$(CONFIG)/gpr_manual_constructor_test
gpr_mpscq_test: $(BINDIR)/$(CONFIG)/gpr_mpscq_test
gpr_spinlock_test: $(BINDIR)/$(CONFIG)/gpr_spinlock_test
gpr_stack_lockfree_test: $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test
gpr_string_test: $(BINDIR)/$(CONFIG)/gpr_string_test
gpr_sync_test: $(BINDIR)/$(CONFIG)/gpr_sync_test
gpr_thd_test: $(BINDIR)/$(CONFIG)/gpr_thd_test
@ -1179,7 +1180,6 @@ stress_test: $(BINDIR)/$(CONFIG)/stress_test
thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test
thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test
transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
vector_test: $(BINDIR)/$(CONFIG)/vector_test
writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test
public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89
boringssl_aes_test: $(BINDIR)/$(CONFIG)/boringssl_aes_test
@ -1384,9 +1384,9 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/gpr_histogram_test \
$(BINDIR)/$(CONFIG)/gpr_host_port_test \
$(BINDIR)/$(CONFIG)/gpr_log_test \
$(BINDIR)/$(CONFIG)/gpr_manual_constructor_test \
$(BINDIR)/$(CONFIG)/gpr_mpscq_test \
$(BINDIR)/$(CONFIG)/gpr_spinlock_test \
$(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test \
$(BINDIR)/$(CONFIG)/gpr_string_test \
$(BINDIR)/$(CONFIG)/gpr_sync_test \
$(BINDIR)/$(CONFIG)/gpr_thd_test \
@ -1614,7 +1614,6 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/vector_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/boringssl_aes_test \
$(BINDIR)/$(CONFIG)/boringssl_asn1_test \
@ -1740,7 +1739,6 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/thread_manager_test \
$(BINDIR)/$(CONFIG)/thread_stress_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/vector_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \
$(BINDIR)/$(CONFIG)/resolver_component_test \
@ -1831,12 +1829,12 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/gpr_host_port_test || ( echo test gpr_host_port_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_log_test"
$(Q) $(BINDIR)/$(CONFIG)/gpr_log_test || ( echo test gpr_log_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_manual_constructor_test"
$(Q) $(BINDIR)/$(CONFIG)/gpr_manual_constructor_test || ( echo test gpr_manual_constructor_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_mpscq_test"
$(Q) $(BINDIR)/$(CONFIG)/gpr_mpscq_test || ( echo test gpr_mpscq_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_spinlock_test"
$(Q) $(BINDIR)/$(CONFIG)/gpr_spinlock_test || ( echo test gpr_spinlock_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_stack_lockfree_test"
$(Q) $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test || ( echo test gpr_stack_lockfree_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_string_test"
$(Q) $(BINDIR)/$(CONFIG)/gpr_string_test || ( echo test gpr_string_test failed ; exit 1 )
$(E) "[RUN] Testing gpr_sync_test"
@ -2153,8 +2151,6 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 )
$(E) "[RUN] Testing transport_pid_controller_test"
$(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 )
$(E) "[RUN] Testing vector_test"
$(Q) $(BINDIR)/$(CONFIG)/vector_test || ( echo test vector_test failed ; exit 1 )
$(E) "[RUN] Testing writes_per_rpc_test"
$(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 )
$(E) "[RUN] Testing resolver_component_tests_runner_invoker_unsecure"
@ -2579,6 +2575,16 @@ $(OBJDIR)/$(CONFIG)/src/compiler/%.o : src/compiler/%.cc
$(Q) mkdir -p `dirname $@`
$(Q) $(HOST_CXX) $(HOST_CXXFLAGS) $(HOST_CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
$(OBJDIR)/$(CONFIG)/src/core/%.o : src/core/%.cc
$(E) "[CXX] Compiling $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(COREFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
$(OBJDIR)/$(CONFIG)/test/core/%.o : test/core/%.cc
$(E) "[CXX] Compiling $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(COREFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
$(OBJDIR)/$(CONFIG)/%.o : %.cc
$(E) "[CXX] Compiling $<"
$(Q) mkdir -p `dirname $@`
@ -2822,7 +2828,6 @@ LIBGPR_SRC = \
src/core/lib/support/log_windows.cc \
src/core/lib/support/mpscq.cc \
src/core/lib/support/murmur_hash.cc \
src/core/lib/support/stack_lockfree.cc \
src/core/lib/support/string.cc \
src/core/lib/support/string_posix.cc \
src/core/lib/support/string_util_windows.cc \
@ -10176,98 +10181,98 @@ endif
endif
GPR_MPSCQ_TEST_SRC = \
test/core/support/mpscq_test.cc \
GPR_MANUAL_CONSTRUCTOR_TEST_SRC = \
test/core/support/manual_constructor_test.cc \
GPR_MPSCQ_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_MPSCQ_TEST_SRC))))
GPR_MANUAL_CONSTRUCTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_MANUAL_CONSTRUCTOR_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/gpr_mpscq_test: openssl_dep_error
$(BINDIR)/$(CONFIG)/gpr_manual_constructor_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/gpr_mpscq_test: $(GPR_MPSCQ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(BINDIR)/$(CONFIG)/gpr_manual_constructor_test: $(GPR_MANUAL_CONSTRUCTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(GPR_MPSCQ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_mpscq_test
$(Q) $(LD) $(LDFLAGS) $(GPR_MANUAL_CONSTRUCTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_manual_constructor_test
endif
$(OBJDIR)/$(CONFIG)/test/core/support/mpscq_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/test/core/support/manual_constructor_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_gpr_mpscq_test: $(GPR_MPSCQ_TEST_OBJS:.o=.dep)
deps_gpr_manual_constructor_test: $(GPR_MANUAL_CONSTRUCTOR_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GPR_MPSCQ_TEST_OBJS:.o=.dep)
-include $(GPR_MANUAL_CONSTRUCTOR_TEST_OBJS:.o=.dep)
endif
endif
GPR_SPINLOCK_TEST_SRC = \
test/core/support/spinlock_test.cc \
GPR_MPSCQ_TEST_SRC = \
test/core/support/mpscq_test.cc \
GPR_SPINLOCK_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_SPINLOCK_TEST_SRC))))
GPR_MPSCQ_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_MPSCQ_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/gpr_spinlock_test: openssl_dep_error
$(BINDIR)/$(CONFIG)/gpr_mpscq_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/gpr_spinlock_test: $(GPR_SPINLOCK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(BINDIR)/$(CONFIG)/gpr_mpscq_test: $(GPR_MPSCQ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(GPR_SPINLOCK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_spinlock_test
$(Q) $(LD) $(LDFLAGS) $(GPR_MPSCQ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_mpscq_test
endif
$(OBJDIR)/$(CONFIG)/test/core/support/spinlock_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/test/core/support/mpscq_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_gpr_spinlock_test: $(GPR_SPINLOCK_TEST_OBJS:.o=.dep)
deps_gpr_mpscq_test: $(GPR_MPSCQ_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GPR_SPINLOCK_TEST_OBJS:.o=.dep)
-include $(GPR_MPSCQ_TEST_OBJS:.o=.dep)
endif
endif
GPR_STACK_LOCKFREE_TEST_SRC = \
test/core/support/stack_lockfree_test.cc \
GPR_SPINLOCK_TEST_SRC = \
test/core/support/spinlock_test.cc \
GPR_STACK_LOCKFREE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_STACK_LOCKFREE_TEST_SRC))))
GPR_SPINLOCK_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_SPINLOCK_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test: openssl_dep_error
$(BINDIR)/$(CONFIG)/gpr_spinlock_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test: $(GPR_STACK_LOCKFREE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(BINDIR)/$(CONFIG)/gpr_spinlock_test: $(GPR_SPINLOCK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(GPR_STACK_LOCKFREE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test
$(Q) $(LD) $(LDFLAGS) $(GPR_SPINLOCK_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_spinlock_test
endif
$(OBJDIR)/$(CONFIG)/test/core/support/stack_lockfree_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/test/core/support/spinlock_test.o: $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_gpr_stack_lockfree_test: $(GPR_STACK_LOCKFREE_TEST_OBJS:.o=.dep)
deps_gpr_spinlock_test: $(GPR_SPINLOCK_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GPR_STACK_LOCKFREE_TEST_OBJS:.o=.dep)
-include $(GPR_SPINLOCK_TEST_OBJS:.o=.dep)
endif
endif
@ -17204,49 +17209,6 @@ endif
endif
VECTOR_TEST_SRC = \
test/core/support/vector_test.cc \
VECTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(VECTOR_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/vector_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.0.0+.
$(BINDIR)/$(CONFIG)/vector_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/vector_test: $(PROTOBUF_DEP) $(VECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(VECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/vector_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/support/vector_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_vector_test: $(VECTOR_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(VECTOR_TEST_OBJS:.o=.dep)
endif
endif
WRITES_PER_RPC_TEST_SRC = \
test/cpp/performance/writes_per_rpc_test.cc \

@ -30,7 +30,6 @@ Libraries in different languages may be in different states of development. We a
| Shared C [core library] | [src/core](src/core) | 1.6 |
| C++ | [src/cpp](src/cpp) | 1.6 |
| Ruby | [src/ruby](src/ruby) | 1.6 |
| NodeJS | [src/node](src/node) | 1.6 |
| Python | [src/python](src/python) | 1.6 |
| PHP | [src/php](src/php) | 1.6 |
| C# | [src/csharp](src/csharp) | 1.6 |
@ -38,7 +37,8 @@ Libraries in different languages may be in different states of development. We a
Java source code is in the [grpc-java](http://github.com/grpc/grpc-java)
repository. Go source code is in the
[grpc-go](http://github.com/grpc/grpc-go) repository.
[grpc-go](http://github.com/grpc/grpc-go) repository. NodeJS source code is in the
[grpc-node](https://github.com/grpc/grpc-node) repository.
See [MANIFEST.md](MANIFEST.md) for a listing of top-level items in the
repository.

@ -10,7 +10,7 @@ bind(
bind(
name = "zlib",
actual = "@submodule_zlib//:z",
actual = "@com_github_madler_zlib//:z",
)
bind(
@ -35,22 +35,22 @@ bind(
bind(
name = "cares",
actual = "@submodule_cares//:ares",
actual = "@com_github_cares_cares//:ares",
)
bind(
name = "gtest",
actual = "@submodule_gtest//:gtest",
actual = "@com_github_google_googletest//:gtest",
)
bind(
name = "gmock",
actual = "@submodule_gtest//:gmock",
actual = "@com_github_google_googletest//:gmock",
)
bind(
name = "benchmark",
actual = "@submodule_benchmark//:benchmark",
actual = "@com_github_google_benchmark//:benchmark",
)
bind(
@ -58,47 +58,60 @@ bind(
actual = "@com_github_gflags_gflags//:gflags",
)
local_repository(
http_archive(
name = "boringssl",
path = "third_party/boringssl-with-bazel",
# on the master-with-bazel branch
url = "https://boringssl.googlesource.com/boringssl/+archive/886e7d75368e3f4fab3f4d0d3584e4abfc557755.tar.gz",
)
new_local_repository(
name = "submodule_zlib",
new_http_archive(
name = "com_github_madler_zlib",
build_file = "third_party/zlib.BUILD",
path = "third_party/zlib",
strip_prefix = "zlib-cacf7f1d4e3d44d871b605da3b647f07d718623f",
url = "https://github.com/madler/zlib/archive/cacf7f1d4e3d44d871b605da3b647f07d718623f.tar.gz",
)
new_local_repository(
http_archive(
name = "com_google_protobuf",
build_file = "third_party/protobuf/BUILD",
path = "third_party/protobuf",
strip_prefix = "protobuf-2761122b810fe8861004ae785cc3ab39f384d342",
url = "https://github.com/google/protobuf/archive/2761122b810fe8861004ae785cc3ab39f384d342.tar.gz",
)
new_local_repository(
name = "submodule_gtest",
new_http_archive(
name = "com_github_google_googletest",
build_file = "third_party/gtest.BUILD",
path = "third_party/googletest",
strip_prefix = "googletest-ec44c6c1675c25b9827aacd08c02433cccde7780",
url = "https://github.com/google/googletest/archive/ec44c6c1675c25b9827aacd08c02433cccde7780.tar.gz",
)
local_repository(
http_archive(
name = "com_github_gflags_gflags",
path = "third_party/gflags",
strip_prefix = "gflags-30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e",
url = "https://github.com/gflags/gflags/archive/30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e.tar.gz",
)
new_local_repository(
name = "submodule_benchmark",
path = "third_party/benchmark",
new_http_archive(
name = "com_github_google_benchmark",
build_file = "third_party/benchmark.BUILD",
strip_prefix = "benchmark-5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8",
url = "https://github.com/google/benchmark/archive/5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8.tar.gz",
)
new_local_repository(
name = "submodule_cares",
name = "cares_local_files",
build_file = "third_party/cares/cares_local_files.BUILD",
path = "third_party/cares",
)
new_http_archive(
name = "com_github_cares_cares",
build_file = "third_party/cares/cares.BUILD",
strip_prefix = "c-ares-3be1924221e1326df520f8498d704a5c4c8d0cce",
url = "https://github.com/c-ares/c-ares/archive/3be1924221e1326df520f8498d704a5c4c8d0cce.tar.gz",
)
local_repository(
http_archive(
name = "com_google_absl",
path = "third_party/abseil-cpp",
strip_prefix = "abseil-cpp-cc4bed2d74f7c8717e31f9579214ab52a9c9c610",
url = "https://github.com/abseil/abseil-cpp/archive/cc4bed2d74f7c8717e31f9579214ab52a9c9c610.tar.gz",
)

@ -60,10 +60,10 @@ def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, generate_mo
if use_external:
# when this file is used by non-grpc projects
grpc_deps = ["//external:grpc++", "//external:grpc++_codegen_proto",
grpc_deps = ["//external:grpc++_codegen_proto",
"//external:protobuf"]
else:
grpc_deps = ["//:grpc++", "//:grpc++_codegen_proto", "//external:protobuf"]
grpc_deps = ["//:grpc++_codegen_proto", "//external:protobuf"]
native.cc_library(
name = name,

@ -12,9 +12,9 @@ settings:
'#08': Use "-preN" suffixes to identify pre-release versions
'#09': Per-language overrides are possible with (eg) ruby_version tag here
'#10': See the expand_version.py for all the quirks here
core_version: 5.0.0
g_stands_for: gambit
version: 1.7.2
core_version: 5.0.0-dev
g_stands_for: glossy
version: 1.9.0-dev
filegroups:
- name: census
public_headers:
@ -50,7 +50,6 @@ filegroups:
- src/core/lib/support/log_windows.cc
- src/core/lib/support/mpscq.cc
- src/core/lib/support/murmur_hash.cc
- src/core/lib/support/stack_lockfree.cc
- src/core/lib/support/string.cc
- src/core/lib/support/string_posix.cc
- src/core/lib/support/string_util_windows.cc
@ -105,6 +104,7 @@ filegroups:
- include/grpc/support/useful.h
headers:
- src/core/lib/profiling/timers.h
- src/core/lib/support/abstract.h
- src/core/lib/support/arena.h
- src/core/lib/support/atomic.h
- src/core/lib/support/atomic_with_atm.h
@ -116,7 +116,6 @@ filegroups:
- src/core/lib/support/mpscq.h
- src/core/lib/support/murmur_hash.h
- src/core/lib/support/spinlock.h
- src/core/lib/support/stack_lockfree.h
- src/core/lib/support/string.h
- src/core/lib/support/string_windows.h
- src/core/lib/support/thd_internal.h
@ -399,7 +398,6 @@ filegroups:
- src/core/lib/slice/slice_hash_table.h
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/support/vector.h
- src/core/lib/surface/alarm_internal.h
- src/core/lib/surface/api_trace.h
- src/core/lib/surface/call.h
@ -2222,32 +2220,32 @@ targets:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_mpscq_test
cpu_cost: 30
- name: gpr_manual_constructor_test
cpu_cost: 3
build: test
language: c
src:
- test/core/support/mpscq_test.cc
- test/core/support/manual_constructor_test.cc
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_spinlock_test
cpu_cost: 3
- name: gpr_mpscq_test
cpu_cost: 30
build: test
language: c
src:
- test/core/support/spinlock_test.cc
- test/core/support/mpscq_test.cc
deps:
- gpr_test_util
- gpr
uses_polling: false
- name: gpr_stack_lockfree_test
cpu_cost: 7
- name: gpr_spinlock_test
cpu_cost: 3
build: test
language: c
src:
- test/core/support/stack_lockfree_test.cc
- test/core/support/spinlock_test.cc
deps:
- gpr_test_util
- gpr
@ -4778,20 +4776,6 @@ targets:
- grpc
- gpr_test_util
- gpr
- name: vector_test
gtest: true
build: test
language: c++
src:
- test/core/support/vector_test.cc
deps:
- grpc_test_util
- grpc++
- grpc
- gpr_test_util
- gpr
uses:
- grpc++_test
- name: writes_per_rpc_test
gtest: true
cpu_cost: 0.5
@ -4911,8 +4895,8 @@ configs:
msan:
CC: clang
CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins
-fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1
-Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
-fsanitize-memory-use-after-dtor -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0
-DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
CXX: clang++
DEFINES: NDEBUG
LD: clang++
@ -4920,6 +4904,8 @@ configs:
-fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
LDXX: clang++
compile_the_world: true
test_environ:
MSAN_OPTIONS: poison_in_dtor=1
mutrace:
CPPFLAGS: -O3 -fno-omit-frame-pointer
DEFINES: NDEBUG
@ -4972,8 +4958,8 @@ defaults:
CPPFLAGS: -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM
-D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
global:
COREFLAGS: -fno-rtti -fno-exceptions
CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
-Ithird_party/abseil-cpp
LDFLAGS: -g
zlib:
CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration

@ -63,7 +63,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/support/log_windows.cc \
src/core/lib/support/mpscq.cc \
src/core/lib/support/murmur_hash.cc \
src/core/lib/support/stack_lockfree.cc \
src/core/lib/support/string.cc \
src/core/lib/support/string_posix.cc \
src/core/lib/support/string_util_windows.cc \

@ -40,7 +40,6 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\support\\log_windows.cc " +
"src\\core\\lib\\support\\mpscq.cc " +
"src\\core\\lib\\support\\murmur_hash.cc " +
"src\\core\\lib\\support\\stack_lockfree.cc " +
"src\\core\\lib\\support\\string.cc " +
"src\\core\\lib\\support\\string_posix.cc " +
"src\\core\\lib\\support\\string_util_windows.cc " +

@ -0,0 +1,197 @@
# Transport Explainer
@vjpai
## Existing Transports
[gRPC
transports](https://github.com/grpc/grpc/tree/master/src/core/ext/transport)
plug in below the core API (one level below the C++ or other wrapped-language
API). You can write your transport in C or C++ though; currently (Nov 2017) all
the transports are nominally written in C++ though they are idiomatically C. The
existing transports are:
* [HTTP/2](https://github.com/grpc/grpc/tree/master/src/core/ext/transport/chttp2)
* [Cronet](https://github.com/grpc/grpc/tree/master/src/core/ext/transport/cronet)
* [In-process](https://github.com/grpc/grpc/tree/master/src/core/ext/transport/inproc)
Among these, the in-process is likely the easiest to understand, though arguably
also the least similar to a "real" sockets-based transport since it is only used
in a single process.
## Transport stream ops
In the gRPC core implementation, a fundamental struct is the
`grpc_transport_stream_op_batch` which represents a collection of stream
operations sent to a transport. (Note that in gRPC, _stream_ and _RPC_ are used
synonymously since all RPCs are actually streams internally.) The ops in a batch
can include:
* send\_initial\_metadata
- Client: initate an RPC
- Server: supply response headers
* recv\_initial\_metadata
- Client: get response headers
- Server: accept an RPC
* send\_message (zero or more) : send a data buffer
* recv\_message (zero or more) : receive a data buffer
* send\_trailing\_metadata
- Client: half-close indicating that no more messages will be coming
- Server: full-close providing final status for the RPC
* recv\_trailing\_metadata: get final status for the RPC
- Server extra: This op shouldn't actually be considered complete until the
server has also sent trailing metadata to provide the other side with final
status
* cancel\_stream: Attempt to cancel an RPC
* collect\_stats: Get stats
The fundamental responsibility of the transport is to transform between this
internal format and an actual wire format, so the processing of these operations
is largely transport-specific.
One or more of these ops are grouped into a batch. Applications can start all of
a call's ops in a single batch, or they can split them up into multiple
batches. Results of each batch are returned asynchronously via a completion
queue.
Internally, we use callbacks to indicate completion. The surface layer creates a
callback when starting a new batch and sends it down the filter stack along with
the batch. The transport must invoke this callback when the batch is complete,
and then the surface layer returns an event to the application via the
completion queue. Each batch can have up to 3 callbacks:
* recv\_initial\_metadata\_ready (called by the transport when the
recv\_initial\_metadata op is complete)
* recv\_message\_ready (called by the transport when the recv_message op is
complete)
* on\_complete (called by the transport when the entire batch is complete)
## Timelines of transport stream op batches
The transport's job is to sequence and interpret various possible interleavings
of the basic stream ops. For example, a sample timeline of batches would be:
1. Client send\_initial\_metadata: Initiate an RPC with a path (method) and authority
1. Server recv\_initial\_metadata: accept an RPC
1. Client send\_message: Supply the input proto for the RPC
1. Server recv\_message: Get the input proto from the RPC
1. Client send\_trailing\_metadata: This is a half-close indicating that the
client will not be sending any more messages
1. Server recv\_trailing\_metadata: The server sees this from the client and
knows that it will not get any more messages. This won't complete yet though,
as described above.
1. Server send\_initial\_metadata, send\_message, send\_trailing\_metadata: A
batch can contain multiple ops, and this batch provides the RPC response
headers, response content, and status. Note that sending the trailing
metadata will also complete the server's receive of trailing metadata.
1. Client recv\_initial\_metadata: The number of ops in one side of the batch
has no relation with the number of ops on the other side of the batch. In
this case, the client is just collecting the response headers.
1. Client recv\_message, recv\_trailing\_metadata: Get the data response and
status
There are other possible sample timelines. For example, for client-side streaming, a "typical" sequence would be:
1. Server: recv\_initial\_metadata
- At API-level, that would be the server requesting an RPC
1. Server: recv\_trailing\_metadata
- This is for when the server wants to know the final completion of the RPC
through an `AsyncNotifyWhenDone` API in C++
1. Client: send\_initial\_metadata, recv\_message, recv\_trailing\_metadata
- At API-level, that's a client invoking a client-side streaming call. The
send\_initial\_metadata is the call invocation, the recv\_message colects
the final response from the server, and the recv\_trailing\_metadata gets
the `grpc::Status` value that will be returned from the call
1. Client: send\_message / Server: recv\_message
- Repeat the above step numerous times; these correspond to a client issuing
`Write` in a loop and a server doing `Read` in a loop until `Read` fails
1. Client: send\_trailing\_metadata / Server: recv\_message that indicates doneness (NULL)
- These correspond to a client issuing `WritesDone` which causes the server's
`Read` to fail
1. Server: send\_message, send\_trailing\_metadata
- These correpond to the server doing `Finish`
The sends on one side will call their own callbacks when complete, and they will
in turn trigger actions that cause the other side's recv operations to
complete. In some transports, a send can sometimes complete before the recv on
the other side (e.g., in HTTP/2 if there is sufficient flow-control buffer space
available)
## Other transport duties
In addition to these basic stream ops, the transport must handle cancellations
of a stream at any time and pass their effects to the other side. For example,
in HTTP/2, this triggers a `RST_STREAM` being sent on the wire. The transport
must perform operations like pings and statistics that are used to shape
transport-level characteristics like flow control (see, for example, their use
in the HTTP/2 transport).
## Putting things together with detail: Sending Metadata
* API layer: `map<string, string>` that is specific to this RPC
* Core surface layer: array of `{slice, slice}` pairs where each slice
references an underlying string
* [Core transport
layer](https://github.com/grpc/grpc/tree/master/src/core/lib/transport): list
of `{slice, slice}` pairs that includes the above plus possibly some general
metadata (e.g., Method and Authority for initial metadata)
* [Specific transport
layer](https://github.com/grpc/grpc/tree/master/src/core/ext/transport):
- Either send it to the other side using transport-specific API (e.g., Cronet)
- Or have it sent through the [iomgr/endpoint
layer](https://github.com/grpc/grpc/tree/master/src/core/lib/iomgr) (e.g.,
HTTP/2)
- Or just manipulate pointers to get it from one side to the other (e.g.,
In-process)
## Requirements for any transport
Each transport implements several operations in a vtbl (may change to actual
virtual functions as transport moves to idiomatic C++).
The most important and common one is `perform_stream_op`. This function
processes a single stream op batch on a specific stream that is associated with
a specific transport:
* Gets the 6 ops/cancel passed down from the surface
* Pass metadata from one side to the other as described above
* Transform messages between slice buffer structure and stream of bytes to pass
to other side
- May require insertion of extra bytes (e.g., per-message headers in HTTP/2)
* React to metadata to preserve expected orderings (*)
* Schedule invocation of completion callbacks
There are other functions in the vtbl as well.
* `perform_transport_op`
- Configure the transport instance for the connectivity state change notifier
or the server-side accept callback
- Disconnect transport or set up a goaway for later streams
* `init_stream`
- Starts a stream from the client-side
- (*) Server-side of the transport must call `accept_stream_cb` when a new
stream is available
* Triggers request-matcher
* `destroy_stream`, `destroy_transport`
- Free up data related to a stream or transport
* `set_pollset`, `set_pollset_set`, `get_endpoint`
- Map each specific instance of the transport to FDs being used by iomgr (for
HTTP/2)
- Get a pointer to the endpoint structure that actually moves the data
(wrapper around a socket for HTTP/2)
## Book-keeping responsibilities of the transport layer
A given transport must keep all of its transport and streams ref-counted. This
is essential to make sure that no struct disappears before it is done being
used.
A transport must also preserve relevant orders for the different categories of
ops on a stream, as described above. A transport must also make sure that all
relevant batch operations have completed before scheduling the `on_complete`
closure for a batch. Further examples include the idea that the server logic
expects to not complete recv\_trailing\_metadata until after it actually sends
trailing metadata since it would have already found this out by seeing a NULL’ed
recv\_message. This is considered part of the transport's duties in preserving
orders.

@ -12,3 +12,4 @@ future), and the corresponding version numbers that used them:
- 1.6 'g' stands for 'garcia'
- 1.7 'g' stands for 'gambit'
- 1.8 'g' stands for 'generous'
- 1.9 'g' stands for 'glossy'

@ -42,12 +42,12 @@ cc_binary(
name = "greeter_client",
srcs = ["cpp/helloworld/greeter_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld"],
deps = [":helloworld", "//:grpc++"],
)
cc_binary(
name = "greeter_server",
srcs = ["cpp/helloworld/greeter_server.cc"],
defines = ["BAZEL_BUILD"],
deps = [":helloworld"],
deps = [":helloworld", "//:grpc++"],
)

@ -17,7 +17,6 @@
from __future__ import print_function
import random
import time
import grpc
@ -66,7 +65,6 @@ def generate_route(feature_list):
random_feature = feature_list[random.randint(0, len(feature_list) - 1)]
print("Visiting point %s" % random_feature.location)
yield random_feature.location
time.sleep(random.uniform(0.5, 1.5))
def guide_record_route(stub):
@ -91,7 +89,6 @@ def generate_messages():
for msg in messages:
print("Sending %s at %s" % (msg.message, msg.location))
yield msg
time.sleep(random.uniform(0.5, 1.0))
def guide_route_chat(stub):

@ -22,7 +22,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-Core'
version = '1.7.2'
version = '1.9.0-dev'
s.version = version
s.summary = 'Core cross-platform gRPC library, written in C'
s.homepage = 'https://grpc.io'
@ -191,6 +191,7 @@ Pod::Spec.new do |s|
# To save you from scrolling, this is the last part of the podspec.
ss.source_files = 'src/core/lib/profiling/timers.h',
'src/core/lib/support/abstract.h',
'src/core/lib/support/arena.h',
'src/core/lib/support/atomic.h',
'src/core/lib/support/atomic_with_atm.h',
@ -202,7 +203,6 @@ Pod::Spec.new do |s|
'src/core/lib/support/mpscq.h',
'src/core/lib/support/murmur_hash.h',
'src/core/lib/support/spinlock.h',
'src/core/lib/support/stack_lockfree.h',
'src/core/lib/support/string.h',
'src/core/lib/support/string_windows.h',
'src/core/lib/support/thd_internal.h',
@ -232,7 +232,6 @@ Pod::Spec.new do |s|
'src/core/lib/support/log_windows.cc',
'src/core/lib/support/mpscq.cc',
'src/core/lib/support/murmur_hash.cc',
'src/core/lib/support/stack_lockfree.cc',
'src/core/lib/support/string.cc',
'src/core/lib/support/string_posix.cc',
'src/core/lib/support/string_util_windows.cc',
@ -419,7 +418,6 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/support/vector.h',
'src/core/lib/surface/alarm_internal.h',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/call.h',
@ -715,6 +713,7 @@ Pod::Spec.new do |s|
'src/core/plugin_registry/grpc_plugin_registry.cc'
ss.private_header_files = 'src/core/lib/profiling/timers.h',
'src/core/lib/support/abstract.h',
'src/core/lib/support/arena.h',
'src/core/lib/support/atomic.h',
'src/core/lib/support/atomic_with_atm.h',
@ -726,7 +725,6 @@ Pod::Spec.new do |s|
'src/core/lib/support/mpscq.h',
'src/core/lib/support/murmur_hash.h',
'src/core/lib/support/spinlock.h',
'src/core/lib/support/stack_lockfree.h',
'src/core/lib/support/string.h',
'src/core/lib/support/string_windows.h',
'src/core/lib/support/thd_internal.h',
@ -897,7 +895,6 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/support/vector.h',
'src/core/lib/surface/alarm_internal.h',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/call.h',

@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-ProtoRPC'
version = '1.7.2'
version = '1.9.0-dev'
s.version = version
s.summary = 'RPC library for Protocol Buffers, based on gRPC'
s.homepage = 'https://grpc.io'

@ -21,7 +21,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-RxLibrary'
version = '1.7.2'
version = '1.9.0-dev'
s.version = version
s.summary = 'Reactive Extensions library for iOS/OSX.'
s.homepage = 'https://grpc.io'

@ -20,7 +20,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
version = '1.7.2'
version = '1.9.0-dev'
s.version = version
s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'https://grpc.io'

@ -85,6 +85,7 @@ Gem::Specification.new do |s|
s.files += %w( include/grpc/impl/codegen/sync_posix.h )
s.files += %w( include/grpc/impl/codegen/sync_windows.h )
s.files += %w( src/core/lib/profiling/timers.h )
s.files += %w( src/core/lib/support/abstract.h )
s.files += %w( src/core/lib/support/arena.h )
s.files += %w( src/core/lib/support/atomic.h )
s.files += %w( src/core/lib/support/atomic_with_atm.h )
@ -96,7 +97,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/mpscq.h )
s.files += %w( src/core/lib/support/murmur_hash.h )
s.files += %w( src/core/lib/support/spinlock.h )
s.files += %w( src/core/lib/support/stack_lockfree.h )
s.files += %w( src/core/lib/support/string.h )
s.files += %w( src/core/lib/support/string_windows.h )
s.files += %w( src/core/lib/support/thd_internal.h )
@ -126,7 +126,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/log_windows.cc )
s.files += %w( src/core/lib/support/mpscq.cc )
s.files += %w( src/core/lib/support/murmur_hash.cc )
s.files += %w( src/core/lib/support/stack_lockfree.cc )
s.files += %w( src/core/lib/support/string.cc )
s.files += %w( src/core/lib/support/string_posix.cc )
s.files += %w( src/core/lib/support/string_util_windows.cc )
@ -349,7 +348,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/slice/slice_hash_table.h )
s.files += %w( src/core/lib/slice/slice_internal.h )
s.files += %w( src/core/lib/slice/slice_string_helpers.h )
s.files += %w( src/core/lib/support/vector.h )
s.files += %w( src/core/lib/surface/alarm_internal.h )
s.files += %w( src/core/lib/surface/api_trace.h )
s.files += %w( src/core/lib/surface/call.h )

@ -57,7 +57,6 @@
'-Wno-long-long',
'-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
],
'ldflags': [
'-g',
@ -135,7 +134,6 @@
'-Wno-long-long',
'-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
],
'OTHER_CPLUSPLUSFLAGS': [
'-g',
@ -145,7 +143,6 @@
'-Wno-long-long',
'-Wno-unused-parameter',
'-DOSATOMIC_USE_INLINED=1',
'-Ithird_party/abseil-cpp',
'-stdlib=libc++',
'-std=c++11',
'-Wno-error=deprecated-declarations'
@ -185,7 +182,6 @@
'src/core/lib/support/log_windows.cc',
'src/core/lib/support/mpscq.cc',
'src/core/lib/support/murmur_hash.cc',
'src/core/lib/support/stack_lockfree.cc',
'src/core/lib/support/string.cc',
'src/core/lib/support/string_posix.cc',
'src/core/lib/support/string_util_windows.cc',

@ -313,11 +313,6 @@ class CallOpSendMessage {
WriteOptions write_options_;
};
namespace internal {
template <class T>
T Example();
} // namespace internal
template <class M>
Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
write_options_ = options;
@ -579,6 +574,7 @@ class CallOpClientRecvStatus {
op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
op->data.recv_status_on_client.status = &status_code_;
op->data.recv_status_on_client.status_details = &error_message_;
op->data.recv_status_on_client.error_string = nullptr;
op->flags = 0;
op->reserved = NULL;
}

@ -185,7 +185,7 @@ GRPCAPI grpc_call_credentials* grpc_composite_call_credentials_create(
GRPCAPI grpc_call_credentials* grpc_google_compute_engine_credentials_create(
void* reserved);
GRPCAPI gpr_timespec grpc_max_auth_token_lifetime();
GRPCAPI gpr_timespec grpc_max_auth_token_lifetime(void);
/** Creates a JWT credentials object. May return NULL if the input is invalid.
- json_key is the JSON key string containing the client's private key.

@ -558,6 +558,10 @@ typedef struct grpc_op {
grpc_metadata_array* trailing_metadata;
grpc_status_code* status;
grpc_slice* status_details;
/** If this is not nullptr, it will be populated with the full fidelity
* error string for debugging purposes. The application is responsible
* for freeing the data. */
const char** error_string;
} recv_status_on_client;
struct grpc_op_recv_close_on_server {
/** out argument, set to 1 if the call failed in any way (seen as a

@ -297,6 +297,27 @@
#endif
#endif /* GPR_NO_AUTODETECT_PLATFORM */
/*
* There are platforms for which TLS should not be used even though the
* compiler makes it seem like it's supported (Android NDK < r12b for example).
* This is primarily because of linker problems and toolchain misconfiguration:
* TLS isn't supported until NDK r12b per
* https://developer.android.com/ndk/downloads/revision_history.html
* Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in
* <android/ndk-version.h>. For NDK < r16, users should define these macros,
* e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11. */
#if defined(__ANDROID__) && defined(__clang__) && defined(GPR_GCC_TLS)
#if __has_include(<android/ndk-version.h>)
#include <android/ndk-version.h>
#endif /* __has_include(<android/ndk-version.h>) */
#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
defined(__NDK_MINOR__) && \
((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
#undef GPR_GCC_TLS
#define GPR_PTHREAD_TLS 1
#endif
#endif /*defined(__ANDROID__) && defined(__clang__) && defined(GPR_GCC_TLS) */
#if defined(__has_include)
#if __has_include(<atomic>)
#define GRPC_HAS_CXX11_ATOMIC

@ -58,7 +58,7 @@ GPRAPI void gpr_free_aligned(void* ptr);
GPRAPI void gpr_set_allocation_functions(gpr_allocation_functions functions);
/** Return the family of allocation functions currently in effect. */
GPRAPI gpr_allocation_functions gpr_get_allocation_functions();
GPRAPI gpr_allocation_functions gpr_get_allocation_functions(void);
#ifdef __cplusplus
}

@ -68,7 +68,7 @@ GPRAPI void gpr_log_message(const char* file, int line,
/** Set global log verbosity */
GPRAPI void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print);
GPRAPI void gpr_log_verbosity_init();
GPRAPI void gpr_log_verbosity_init(void);
/** Log overrides: applications can use this API to intercept logging calls
and use their own implementations */

@ -13,8 +13,8 @@
<date>2017-08-24</date>
<time>16:06:07</time>
<version>
<release>1.7.2</release>
<api>1.7.2</api>
<release>1.9.0dev</release>
<api>1.9.0dev</api>
</version>
<stability>
<release>beta</release>
@ -97,6 +97,7 @@
<file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" />
<file baseinstalldir="/" name="include/grpc/impl/codegen/sync_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/abstract.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/arena.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/atomic.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/atomic_with_atm.h" role="src" />
@ -108,7 +109,6 @@
<file baseinstalldir="/" name="src/core/lib/support/mpscq.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/murmur_hash.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/spinlock.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/stack_lockfree.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/thd_internal.h" role="src" />
@ -138,7 +138,6 @@
<file baseinstalldir="/" name="src/core/lib/support/log_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/mpscq.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/murmur_hash.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/stack_lockfree.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string_util_windows.cc" role="src" />
@ -361,7 +360,6 @@
<file baseinstalldir="/" name="src/core/lib/slice/slice_hash_table.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/vector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/alarm_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" />

@ -3,6 +3,6 @@ coverage>=4.0
cython>=0.23
enum34>=1.0.4
futures>=2.2.0
protobuf>=3.2.0
protobuf>=3.5.0.post1
six>=1.10
wheel>=0.29

@ -237,7 +237,7 @@ INSTALL_REQUIRES = (
'six>=1.5.2',
# TODO(atash): eventually split the grpcio package into a metapackage
# depending on protobuf and the runtime component (independent of protobuf)
'protobuf>=3.3.0',
'protobuf>=3.5.0.post1',
)
if not PY3:

@ -104,7 +104,7 @@ grpc::string GetHeaderPrologue(grpc_generator::File* file,
grpc::string leading_comments = file->GetLeadingComments("//");
if (!leading_comments.empty()) {
printer->Print(vars, "// Original file comments:\n");
printer->Print(leading_comments.c_str());
printer->PrintRaw(leading_comments.c_str());
}
printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");

@ -666,7 +666,7 @@ grpc::string GetServices(const FileDescriptor* file, bool generate_client,
grpc::string leading_comments = GetCsharpComments(file, true);
if (!leading_comments.empty()) {
out.Print("// Original file comments:\n");
out.Print(leading_comments.c_str());
out.PrintRaw(leading_comments.c_str());
}
out.Print("#pragma warning disable 1591\n");

@ -250,7 +250,7 @@ grpc::string GenerateFile(const FileDescriptor* file) {
grpc::string leading_comments = GetNodeComments(file, true);
if (!leading_comments.empty()) {
out.Print("// Original file comments:\n");
out.Print(leading_comments.c_str());
out.PrintRaw(leading_comments.c_str());
}
out.Print("'use strict';\n");

@ -66,7 +66,7 @@ static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
printer->Print(" * ");
size_t start_pos = it->find_first_not_of(' ');
if (start_pos != grpc::string::npos) {
printer->Print(it->c_str() + start_pos);
printer->PrintRaw(it->c_str() + start_pos);
}
printer->Print("\n");
}

@ -51,8 +51,11 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
{
// Generate .pbrpc.h
::grpc::string imports = ::grpc::string("#import \"") + file_name +
".pbobjc.h\"\n\n"
::grpc::string imports =
::grpc::string("#if !GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO\n") +
"#import \"" + file_name +
".pbobjc.h\"\n"
"#endif\n\n"
"#import <ProtoRPC/ProtoService.h>\n"
"#import <ProtoRPC/ProtoRPC.h>\n"
"#import <RxLibrary/GRXWriteable.h>\n"
@ -105,7 +108,10 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
// Generate .pbrpc.m
::grpc::string imports = ::grpc::string("#import \"") + file_name +
".pbrpc.h\"\n\n"
".pbrpc.h\"\n"
"#import \"" +
file_name +
".pbobjc.h\"\n\n"
"#import <ProtoRPC/ProtoRPC.h>\n"
"#import <RxLibrary/GRXWriter+Immediate.h>\n";
for (int i = 0; i < file->dependency_count(); i++) {

@ -164,7 +164,7 @@ grpc::string GenerateFile(const FileDescriptor* file,
grpc::string leading_comments = GetPHPComments(file, "//");
if (!leading_comments.empty()) {
out.Print("// Original file comments:\n");
out.Print(leading_comments.c_str());
out.PrintRaw(leading_comments.c_str());
}
map<grpc::string, grpc::string> vars;

@ -141,6 +141,7 @@ class ProtoBufPrinter : public grpc_generator::Printer {
}
void Print(const char* string) { printer_.Print(string); }
void PrintRaw(const char* string) { printer_.PrintRaw(string); }
void Indent() { printer_.Indent(); }
void Outdent() { printer_.Outdent(); }

@ -101,7 +101,7 @@ void PrivateGenerator::PrintAllComments(StringVector comments,
++it) {
size_t start_pos = it->find_first_not_of(' ');
if (start_pos != grpc::string::npos) {
out->Print(it->c_str() + start_pos);
out->PrintRaw(it->c_str() + start_pos);
}
out->Print("\n");
}

@ -174,7 +174,7 @@ grpc::string GetServices(const FileDescriptor* file) {
grpc::string leading_comments = GetRubyComments(file, true);
if (!leading_comments.empty()) {
out.Print("# Original file comments:\n");
out.Print(leading_comments.c_str());
out.PrintRaw(leading_comments.c_str());
}
out.Print("\n");

@ -86,6 +86,7 @@ struct Printer {
virtual void Print(const std::map<grpc::string, grpc::string>& vars,
const char* template_string) = 0;
virtual void Print(const char* string) = 0;
virtual void PrintRaw(const char* string) = 0;
virtual void Indent() = 0;
virtual void Outdent() = 0;
};

@ -163,7 +163,7 @@ grpc_subchannel* grpc_subchannel_index_register(grpc_exec_ctx* exec_ctx,
grpc_subchannel_key* key,
grpc_subchannel* constructed) {
grpc_subchannel* c = nullptr;
bool need_to_unref_constructed;
bool need_to_unref_constructed = false;
while (c == nullptr) {
need_to_unref_constructed = false;

@ -139,7 +139,7 @@ static bool parse_user_agent(grpc_mdelem md) {
bool grpc_objc_specifier_seen = false;
bool cronet_specifier_seen = false;
char *major_version_str = user_agent_str, *minor_version_str;
long major_version, minor_version;
long major_version = 0, minor_version = 0;
char* head = strtok(user_agent_str, " ");
while (head != nullptr) {

@ -1758,7 +1758,7 @@ static void send_goaway(grpc_exec_ctx* exec_ctx, grpc_chttp2_transport* t,
grpc_http2_error_code http_error;
grpc_slice slice;
grpc_error_get_status(exec_ctx, error, GRPC_MILLIS_INF_FUTURE, nullptr,
&slice, &http_error);
&slice, &http_error, nullptr);
grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)http_error,
grpc_slice_ref_internal(slice), &t->qbuf);
grpc_chttp2_initiate_write(exec_ctx, t,
@ -2061,7 +2061,7 @@ void grpc_chttp2_cancel_stream(grpc_exec_ctx* exec_ctx,
if (s->id != 0) {
grpc_http2_error_code http_error;
grpc_error_get_status(exec_ctx, due_to_error, s->deadline, nullptr,
nullptr, &http_error);
nullptr, &http_error, nullptr);
grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error,
&s->stats.outgoing));
@ -2079,7 +2079,8 @@ void grpc_chttp2_fake_status(grpc_exec_ctx* exec_ctx, grpc_chttp2_transport* t,
grpc_chttp2_stream* s, grpc_error* error) {
grpc_status_code status;
grpc_slice slice;
grpc_error_get_status(exec_ctx, error, s->deadline, &status, &slice, nullptr);
grpc_error_get_status(exec_ctx, error, s->deadline, &status, &slice, nullptr,
nullptr);
if (status != GRPC_STATUS_OK) {
s->seen_error = true;
}
@ -2244,7 +2245,7 @@ static void close_from_api(grpc_exec_ctx* exec_ctx, grpc_chttp2_transport* t,
grpc_status_code grpc_status;
grpc_slice slice;
grpc_error_get_status(exec_ctx, error, s->deadline, &grpc_status, &slice,
nullptr);
nullptr, nullptr);
GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100);

@ -19,6 +19,7 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FLOW_CONTROL_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FLOW_CONTROL_H
#include <grpc/support/port_platform.h>
#include <stdint.h>
#include <grpc/support/useful.h>

@ -84,6 +84,7 @@ typedef struct {
typedef struct {
grpc_call_stats stats;
grpc_status_code final_status;
const char** error_string;
} grpc_call_final_info;
/* Channel filters specify:

@ -75,8 +75,8 @@ void TraceFlagList::LogAllTracers() {
}
// Flags register themselves on the list during construction
TraceFlag::TraceFlag(bool default_enabled, const char* name)
: name_(name), value_(default_enabled) {
TraceFlag::TraceFlag(bool default_enabled, const char* name) : name_(name) {
set_enabled(default_enabled);
TraceFlagList::Add(this);
}

@ -263,11 +263,13 @@ static grpc_fd* fd_create(int fd, const char* name) {
if (new_fd == nullptr) {
new_fd = (grpc_fd*)gpr_malloc(sizeof(grpc_fd));
new_fd->read_closure.Init();
new_fd->write_closure.Init();
}
new_fd->fd = fd;
new_fd->read_closure.Init();
new_fd->write_closure.Init();
new_fd->read_closure->InitEvent();
new_fd->write_closure->InitEvent();
gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
new_fd->freelist_next = nullptr;
@ -336,8 +338,8 @@ static void fd_orphan(grpc_exec_ctx* exec_ctx, grpc_fd* fd,
GRPC_CLOSURE_SCHED(exec_ctx, on_done, GRPC_ERROR_REF(error));
grpc_iomgr_unregister_object(&fd->iomgr_object);
fd->read_closure.Destroy();
fd->write_closure.Destroy();
fd->read_closure->DestroyEvent();
fd->write_closure->DestroyEvent();
gpr_mu_lock(&fd_freelist_mu);
fd->freelist_next = fd_freelist;

@ -286,8 +286,8 @@ static void fd_destroy(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
fd->freelist_next = fd_freelist;
fd_freelist = fd;
fd->read_closure.Destroy();
fd->write_closure.Destroy();
fd->read_closure->DestroyEvent();
fd->write_closure->DestroyEvent();
gpr_mu_unlock(&fd_freelist_mu);
}
@ -340,6 +340,8 @@ static grpc_fd* fd_create(int fd, const char* name) {
if (new_fd == nullptr) {
new_fd = (grpc_fd*)gpr_malloc(sizeof(grpc_fd));
new_fd->read_closure.Init();
new_fd->write_closure.Init();
}
gpr_mu_init(&new_fd->pollable_mu);
@ -347,8 +349,8 @@ static grpc_fd* fd_create(int fd, const char* name) {
new_fd->pollable_obj = nullptr;
gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
new_fd->fd = fd;
new_fd->read_closure.Init();
new_fd->write_closure.Init();
new_fd->read_closure->InitEvent();
new_fd->write_closure->InitEvent();
gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
new_fd->freelist_next = nullptr;

@ -767,8 +767,8 @@ static void unref_by(grpc_fd* fd, int n) {
fd_freelist = fd;
grpc_iomgr_unregister_object(&fd->iomgr_object);
fd->read_closure.Destroy();
fd->write_closure.Destroy();
fd->read_closure->DestroyEvent();
fd->write_closure->DestroyEvent();
gpr_mu_unlock(&fd_freelist_mu);
} else {
@ -819,6 +819,8 @@ static grpc_fd* fd_create(int fd, const char* name) {
if (new_fd == nullptr) {
new_fd = (grpc_fd*)gpr_malloc(sizeof(grpc_fd));
gpr_mu_init(&new_fd->po.mu);
new_fd->read_closure.Init();
new_fd->write_closure.Init();
}
/* Note: It is not really needed to get the new_fd->po.mu lock here. If this
@ -833,8 +835,8 @@ static grpc_fd* fd_create(int fd, const char* name) {
gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
new_fd->fd = fd;
new_fd->orphaned = false;
new_fd->read_closure.Init();
new_fd->write_closure.Init();
new_fd->read_closure->InitEvent();
new_fd->write_closure->InitEvent();
gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
new_fd->freelist_next = nullptr;

@ -57,7 +57,9 @@ extern grpc_core::TraceFlag grpc_polling_trace;
namespace grpc_core {
LockfreeEvent::LockfreeEvent() {
LockfreeEvent::LockfreeEvent() { InitEvent(); }
void LockfreeEvent::InitEvent() {
/* Perform an atomic store to start the state machine.
Note carefully that LockfreeEvent *MAY* be used whilst in a destroyed
@ -67,7 +69,7 @@ LockfreeEvent::LockfreeEvent() {
gpr_atm_no_barrier_store(&state_, kClosureNotReady);
}
LockfreeEvent::~LockfreeEvent() {
void LockfreeEvent::DestroyEvent() {
gpr_atm curr;
do {
curr = gpr_atm_no_barrier_load(&state_);

@ -30,11 +30,16 @@ namespace grpc_core {
class LockfreeEvent {
public:
LockfreeEvent();
~LockfreeEvent();
LockfreeEvent(const LockfreeEvent&) = delete;
LockfreeEvent& operator=(const LockfreeEvent&) = delete;
// These methods are used to initialize and destroy the internal state. These
// cannot be done in constructor and destructor because SetReady may be called
// when the event is destroyed and put in a freelist.
void InitEvent();
void DestroyEvent();
bool IsShutdown() const {
return (gpr_atm_no_barrier_load(&state_) & kShutdownBit) != 0;
}

@ -148,7 +148,7 @@ int grpc_sockaddr_to_string(char** out,
grpc_resolved_address addr_normalized;
char ntop_buf[INET6_ADDRSTRLEN];
const void* ip = nullptr;
int port;
int port = 0;
uint32_t sin6_scope_id = 0;
int ret;

@ -0,0 +1,29 @@
/*
*
* Copyright 2017 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_SUPPORT_ABSTRACT_H
#define GRPC_CORE_LIB_SUPPORT_ABSTRACT_H
// This is needed to support abstract base classes in the c core. Since gRPC
// doesn't have a c++ runtime, it will hit a linker error on delete unless
// we define a virtual operator delete. See this blog for more info:
// https://eli.thegreenplace.net/2015/c-deleting-destructors-and-virtual-operator-delete/
#define GRPC_ABSTRACT_BASE_CLASS \
static void operator delete(void* p) { abort(); }
#endif /* GRPC_CORE_LIB_SUPPORT_ABSTRACT_H */

@ -18,21 +18,23 @@
#include <grpc/support/port_platform.h>
#ifdef GPR_CPU_POSIX
#if defined(GPR_CPU_POSIX)
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <grpc/support/alloc.h>
#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
static __thread char magic_thread_local;
static long ncpus = 0;
static pthread_key_t thread_id_key;
static void init_ncpus() {
ncpus = sysconf(_SC_NPROCESSORS_ONLN);
if (ncpus < 1 || ncpus > INT32_MAX) {
@ -47,12 +49,32 @@ unsigned gpr_cpu_num_cores(void) {
return (unsigned)ncpus;
}
static void delete_thread_id(void* value) {
if (value) {
gpr_free(value);
}
}
static void init_thread_id_key(void) {
pthread_key_create(&thread_id_key, delete_thread_id);
}
unsigned gpr_cpu_current_cpu(void) {
/* NOTE: there's no way I know to return the actual cpu index portably...
most code that's using this is using it to shard across work queues though,
so here we use thread identity instead to achieve a similar though not
identical effect */
return (unsigned)GPR_HASH_POINTER(&magic_thread_local, gpr_cpu_num_cores());
static gpr_once once = GPR_ONCE_INIT;
gpr_once_init(&once, init_thread_id_key);
unsigned int* thread_id =
static_cast<unsigned int*>(pthread_getspecific(thread_id_key));
if (thread_id == nullptr) {
thread_id = static_cast<unsigned int*>(gpr_malloc(sizeof(unsigned int)));
pthread_setspecific(thread_id_key, thread_id);
}
return (unsigned)GPR_HASH_POINTER(thread_id, gpr_cpu_num_cores());
}
#endif /* GPR_CPU_POSIX */

@ -22,12 +22,147 @@
// manually construct a region of memory with some type
#include <stddef.h>
#include <stdlib.h>
#include <new>
#include <type_traits>
#include <utility>
#include <grpc/support/log.h>
namespace grpc_core {
// this contains templated helpers needed to implement the ManualConstructors
// in this file.
namespace manual_ctor_impl {
// is_one_of returns true it a class, Member, is present in a variadic list of
// classes, List.
template <class Member, class... List>
class is_one_of;
template <class Member, class... List>
class is_one_of<Member, Member, List...> {
public:
static constexpr const bool value = true;
};
template <class Member, class A, class... List>
class is_one_of<Member, A, List...> {
public:
static constexpr const bool value = is_one_of<Member, List...>::value;
};
template <class Member>
class is_one_of<Member> {
public:
static constexpr const bool value = false;
};
// max_size_of returns sizeof(Type) for the largest type in the variadic list
// of classes, Types.
template <class... Types>
class max_size_of;
template <class A>
class max_size_of<A> {
public:
static constexpr const size_t value = sizeof(A);
};
template <class A, class... B>
class max_size_of<A, B...> {
public:
static constexpr const size_t value = sizeof(A) > max_size_of<B...>::value
? sizeof(A)
: max_size_of<B...>::value;
};
// max_size_of returns alignof(Type) for the largest type in the variadic list
// of classes, Types.
template <class... Types>
class max_align_of;
template <class A>
class max_align_of<A> {
public:
static constexpr const size_t value = alignof(A);
};
template <class A, class... B>
class max_align_of<A, B...> {
public:
static constexpr const size_t value = alignof(A) > max_align_of<B...>::value
? alignof(A)
: max_align_of<B...>::value;
};
} // namespace manual_ctor_impl
template <class BaseType, class... DerivedTypes>
class PolymorphicManualConstructor {
public:
// No constructor or destructor because one of the most useful uses of
// this class is as part of a union, and members of a union could not have
// constructors or destructors till C++11. And, anyway, the whole point of
// this class is to bypass constructor and destructor.
BaseType* get() { return reinterpret_cast<BaseType*>(&space_); }
const BaseType* get() const {
return reinterpret_cast<const BaseType*>(&space_);
}
BaseType* operator->() { return get(); }
const BaseType* operator->() const { return get(); }
BaseType& operator*() { return *get(); }
const BaseType& operator*() const { return *get(); }
template <class DerivedType>
void Init() {
FinishInit(new (&space_) DerivedType);
}
// Init() constructs the Type instance using the given arguments
// (which are forwarded to Type's constructor).
//
// Note that Init() with no arguments performs default-initialization,
// not zero-initialization (i.e it behaves the same as "new Type;", not
// "new Type();"), so it will leave non-class types uninitialized.
template <class DerivedType, typename... Ts>
void Init(Ts&&... args) {
FinishInit(new (&space_) DerivedType(std::forward<Ts>(args)...));
}
// Init() that is equivalent to copy and move construction.
// Enables usage like this:
// ManualConstructor<std::vector<int>> v;
// v.Init({1, 2, 3});
template <class DerivedType>
void Init(const DerivedType& x) {
FinishInit(new (&space_) DerivedType(x));
}
template <class DerivedType>
void Init(DerivedType&& x) {
FinishInit(new (&space_) DerivedType(std::move(x)));
}
void Destroy() { get()->~BaseType(); }
private:
template <class DerivedType>
void FinishInit(DerivedType* p) {
static_assert(
manual_ctor_impl::is_one_of<DerivedType, DerivedTypes...>::value,
"DerivedType must be one of the predeclared DerivedTypes");
GPR_ASSERT(reinterpret_cast<BaseType*>(static_cast<DerivedType*>(p)) == p);
}
typename std::aligned_storage<
grpc_core::manual_ctor_impl::max_size_of<DerivedTypes...>::value,
grpc_core::manual_ctor_impl::max_align_of<DerivedTypes...>::value>::type
space_;
};
template <typename Type>
class ManualConstructor {
public:

@ -30,22 +30,19 @@
(h) ^= (h) >> 16;
uint32_t gpr_murmur_hash3(const void* key, size_t len, uint32_t seed) {
const uint8_t* data = (const uint8_t*)key;
const size_t nblocks = len / 4;
int i;
uint32_t h1 = seed;
uint32_t k1;
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
const uint32_t* blocks = ((const uint32_t*)key) + nblocks;
const uint8_t* tail = (const uint8_t*)(data + nblocks * 4);
const uint8_t* keyptr = (const uint8_t*)key;
const size_t bsize = sizeof(k1);
const size_t nblocks = len / bsize;
/* body */
for (i = -(int)nblocks; i; i++) {
memcpy(&k1, blocks + i, sizeof(uint32_t));
for (size_t i = 0; i < nblocks; i++, keyptr += bsize) {
memcpy(&k1, keyptr, bsize);
k1 *= c1;
k1 = ROTL32(k1, 15);
@ -61,13 +58,13 @@ uint32_t gpr_murmur_hash3(const void* key, size_t len, uint32_t seed) {
/* tail */
switch (len & 3) {
case 3:
k1 ^= ((uint32_t)tail[2]) << 16;
k1 ^= ((uint32_t)keyptr[2]) << 16;
/* fallthrough */
case 2:
k1 ^= ((uint32_t)tail[1]) << 8;
k1 ^= ((uint32_t)keyptr[1]) << 8;
/* fallthrough */
case 1:
k1 ^= tail[0];
k1 ^= keyptr[0];
k1 *= c1;
k1 = ROTL32(k1, 15);
k1 *= c2;

@ -1,137 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "src/core/lib/support/stack_lockfree.h"
#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
/* The lockfree node structure is a single architecture-level
word that allows for an atomic CAS to set it up. */
struct lockfree_node_contents {
/* next thing to look at. Actual index for head, next index otherwise */
uint16_t index;
#ifdef GPR_ARCH_64
uint16_t pad;
uint32_t aba_ctr;
#else
#ifdef GPR_ARCH_32
uint16_t aba_ctr;
#else
#error Unsupported bit width architecture
#endif
#endif
};
/* Use a union to make sure that these are in the same bits as an atm word */
typedef union lockfree_node {
gpr_atm atm;
struct lockfree_node_contents contents;
} lockfree_node;
/* make sure that entries aligned to 8-bytes */
#define ENTRY_ALIGNMENT_BITS 3
/* reserve this entry as invalid */
#define INVALID_ENTRY_INDEX ((1 << 16) - 1)
struct gpr_stack_lockfree {
lockfree_node* entries;
lockfree_node head; /* An atomic entry describing curr head */
};
gpr_stack_lockfree* gpr_stack_lockfree_create(size_t entries) {
gpr_stack_lockfree* stack;
stack = (gpr_stack_lockfree*)gpr_malloc(sizeof(*stack));
/* Since we only allocate 16 bits to represent an entry number,
* make sure that we are within the desired range */
/* Reserve the highest entry number as a dummy */
GPR_ASSERT(entries < INVALID_ENTRY_INDEX);
stack->entries = (lockfree_node*)gpr_malloc_aligned(
entries * sizeof(stack->entries[0]), ENTRY_ALIGNMENT_BITS);
/* Clear out all entries */
memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
memset(&stack->head, 0, sizeof(stack->head));
GPR_ASSERT(sizeof(stack->entries->atm) == sizeof(stack->entries->contents));
/* Point the head at reserved dummy entry */
stack->head.contents.index = INVALID_ENTRY_INDEX;
/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
#ifdef GPR_ARCH_64
stack->head.contents.pad = 0;
#endif
stack->head.contents.aba_ctr = 0;
return stack;
}
void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack) {
gpr_free_aligned(stack->entries);
gpr_free(stack);
}
int gpr_stack_lockfree_push(gpr_stack_lockfree* stack, int entry) {
lockfree_node head;
lockfree_node newhead;
lockfree_node curent;
lockfree_node newent;
/* First fill in the entry's index and aba ctr for new head */
newhead.contents.index = (uint16_t)entry;
#ifdef GPR_ARCH_64
/* Fill in the pad to avoid confusing memcheck tools */
newhead.contents.pad = 0;
#endif
/* Also post-increment the aba_ctr */
curent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
newhead.contents.aba_ctr = ++curent.contents.aba_ctr;
gpr_atm_no_barrier_store(&stack->entries[entry].atm, curent.atm);
do {
/* Atomically get the existing head value for use */
head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
/* Point to it */
newent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
newent.contents.index = head.contents.index;
gpr_atm_no_barrier_store(&stack->entries[entry].atm, newent.atm);
} while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm));
/* Use rel_cas above to make sure that entry index is set properly */
return head.contents.index == INVALID_ENTRY_INDEX;
}
int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack) {
lockfree_node head;
lockfree_node newhead;
do {
head.atm = gpr_atm_acq_load(&(stack->head.atm));
if (head.contents.index == INVALID_ENTRY_INDEX) {
return -1;
}
newhead.atm =
gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm));
} while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm));
return head.contents.index;
}

@ -1,46 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H
#define GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct gpr_stack_lockfree gpr_stack_lockfree;
/* This stack must specify the maximum number of entries to track.
The current implementation only allows up to 65534 entries */
gpr_stack_lockfree* gpr_stack_lockfree_create(size_t entries);
void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack);
/* Pass in a valid entry number for the next stack entry */
/* Returns 1 if this is the first element on the stack, 0 otherwise */
int gpr_stack_lockfree_push(gpr_stack_lockfree*, int entry);
/* Returns -1 on empty or the actual entry number */
int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack);
#ifdef __cplusplus
}
#endif
#endif /* GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H */

@ -234,6 +234,7 @@ struct grpc_call {
struct {
grpc_status_code* status;
grpc_slice* status_details;
const char** error_string;
} client;
struct {
int* cancelled;
@ -284,7 +285,8 @@ static void receiving_slice_ready(grpc_exec_ctx* exec_ctx, void* bctlp,
static void get_final_status(grpc_exec_ctx* exec_ctx, grpc_call* call,
void (*set_value)(grpc_status_code code,
void* user_data),
void* set_value_user_data, grpc_slice* details);
void* set_value_user_data, grpc_slice* details,
const char** error_string);
static void set_status_value_directly(grpc_status_code status, void* dest);
static void set_status_from_error(grpc_exec_ctx* exec_ctx, grpc_call* call,
status_source source, grpc_error* error);
@ -546,7 +548,8 @@ static void destroy_call(grpc_exec_ctx* exec_ctx, void* call,
}
get_final_status(exec_ctx, c, set_status_value_directly,
&c->final_info.final_status, nullptr);
&c->final_info.final_status, nullptr,
c->final_info.error_string);
c->final_info.stats.latency =
gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
@ -733,16 +736,15 @@ static void cancel_with_status(grpc_exec_ctx* exec_ctx, grpc_call* c,
* FINAL STATUS CODE MANIPULATION
*/
static bool get_final_status_from(grpc_exec_ctx* exec_ctx, grpc_call* call,
grpc_error* error, bool allow_ok_status,
void (*set_value)(grpc_status_code code,
void* user_data),
void* set_value_user_data,
grpc_slice* details) {
static bool get_final_status_from(
grpc_exec_ctx* exec_ctx, grpc_call* call, grpc_error* error,
bool allow_ok_status,
void (*set_value)(grpc_status_code code, void* user_data),
void* set_value_user_data, grpc_slice* details, const char** error_string) {
grpc_status_code code;
grpc_slice slice = grpc_empty_slice();
grpc_error_get_status(exec_ctx, error, call->send_deadline, &code, &slice,
nullptr);
nullptr, error_string);
if (code == GRPC_STATUS_OK && !allow_ok_status) {
return false;
}
@ -757,7 +759,8 @@ static bool get_final_status_from(grpc_exec_ctx* exec_ctx, grpc_call* call,
static void get_final_status(grpc_exec_ctx* exec_ctx, grpc_call* call,
void (*set_value)(grpc_status_code code,
void* user_data),
void* set_value_user_data, grpc_slice* details) {
void* set_value_user_data, grpc_slice* details,
const char** error_string) {
int i;
received_status status[STATUS_SOURCE_COUNT];
for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
@ -781,7 +784,7 @@ static void get_final_status(grpc_exec_ctx* exec_ctx, grpc_call* call,
grpc_error_has_clear_grpc_status(status[i].error)) {
if (get_final_status_from(exec_ctx, call, status[i].error,
allow_ok_status != 0, set_value,
set_value_user_data, details)) {
set_value_user_data, details, error_string)) {
return;
}
}
@ -791,7 +794,7 @@ static void get_final_status(grpc_exec_ctx* exec_ctx, grpc_call* call,
if (status[i].is_set) {
if (get_final_status_from(exec_ctx, call, status[i].error,
allow_ok_status != 0, set_value,
set_value_user_data, details)) {
set_value_user_data, details, error_string)) {
return;
}
}
@ -1332,10 +1335,11 @@ static void post_batch_completion(grpc_exec_ctx* exec_ctx,
if (call->is_client) {
get_final_status(exec_ctx, call, set_status_value_directly,
call->final_op.client.status,
call->final_op.client.status_details);
call->final_op.client.status_details,
call->final_op.client.error_string);
} else {
get_final_status(exec_ctx, call, set_cancelled_value,
call->final_op.server.cancelled, nullptr);
call->final_op.server.cancelled, nullptr, nullptr);
}
GRPC_ERROR_UNREF(error);
@ -1992,6 +1996,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx* exec_ctx,
call->final_op.client.status = op->data.recv_status_on_client.status;
call->final_op.client.status_details =
op->data.recv_status_on_client.status_details;
call->final_op.client.error_string =
op->data.recv_status_on_client.error_string;
stream_op->recv_trailing_metadata = true;
stream_op->collect_stats = true;
stream_op_payload->recv_trailing_metadata.recv_trailing_metadata =

@ -21,6 +21,6 @@
#include <grpc/grpc.h>
const char* grpc_version_string(void) { return "5.0.0"; }
const char* grpc_version_string(void) { return "5.0.0-dev"; }
const char* grpc_g_stands_for(void) { return "gambit"; }
const char* grpc_g_stands_for(void) { return "glossy"; }

@ -18,6 +18,7 @@
#include "src/core/lib/transport/error_utils.h"
#include <grpc/support/string_util.h>
#include "src/core/lib/iomgr/error_internal.h"
#include "src/core/lib/transport/status_conversion.h"
@ -41,8 +42,8 @@ static grpc_error* recursively_find_error_with_field(grpc_error* error,
void grpc_error_get_status(grpc_exec_ctx* exec_ctx, grpc_error* error,
grpc_millis deadline, grpc_status_code* code,
grpc_slice* slice,
grpc_http2_error_code* http_error) {
grpc_slice* slice, grpc_http2_error_code* http_error,
const char** error_string) {
// 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 =
@ -69,6 +70,10 @@ void grpc_error_get_status(grpc_exec_ctx* exec_ctx, grpc_error* error,
}
if (code != nullptr) *code = status;
if (error_string != NULL && status != GRPC_STATUS_OK) {
*error_string = gpr_strdup(grpc_error_string(error));
}
if (http_error != nullptr) {
if (grpc_error_get_int(found_error, GRPC_ERROR_INT_HTTP2_ERROR, &integer)) {
*http_error = (grpc_http2_error_code)integer;

@ -30,13 +30,15 @@ extern "C" {
/// A utility function to get the status code and message to be returned
/// to the application. If not set in the top-level message, looks
/// through child errors until it finds the first one with these attributes.
/// All attributes are pulled from the same child error. If any of the
/// attributes (code, msg, http_status) are unneeded, they can be passed as
/// All attributes are pulled from the same child error. error_string will
/// be populated with the entire error string. If any of the attributes (code,
/// msg, http_status, error_string) are unneeded, they can be passed as
/// NULL.
void grpc_error_get_status(grpc_exec_ctx* exec_ctx, grpc_error* error,
grpc_millis deadline, grpc_status_code* code,
grpc_slice* slice,
grpc_http2_error_code* http_status);
grpc_http2_error_code* http_status,
const char** error_string);
/// A utility function to check whether there is a clear status code that
/// doesn't need to be guessed in \a error. This means that \a error or some

@ -22,5 +22,5 @@
#include <grpc++/grpc++.h>
namespace grpc {
grpc::string Version() { return "1.7.2"; }
grpc::string Version() { return "1.9.0-dev"; }
} // namespace grpc

@ -64,7 +64,7 @@ namespace Grpc.Core.Internal.Tests
public void CancelNotificationAfterStartDisposes()
{
var finishedTask = asyncCallServer.ServerSideCallAsync();
fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
AssertFinished(asyncCallServer, fakeCall, finishedTask);
}
@ -76,8 +76,8 @@ namespace Grpc.Core.Internal.Tests
var moveNextTask = requestStream.MoveNext();
fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
Assert.IsFalse(moveNextTask.Result);
AssertFinished(asyncCallServer, fakeCall, finishedTask);
@ -89,7 +89,7 @@ namespace Grpc.Core.Internal.Tests
var finishedTask = asyncCallServer.ServerSideCallAsync();
var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
// Check that starting a read after cancel notification has been processed is legal.
var moveNextTask = requestStream.MoveNext();
@ -107,10 +107,10 @@ 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.ReceivedMessageHandler(false, null);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, null);
Assert.IsFalse(moveNextTask.Result);
fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
AssertFinished(asyncCallServer, fakeCall, finishedTask);
}
@ -120,7 +120,7 @@ namespace Grpc.Core.Internal.Tests
var finishedTask = asyncCallServer.ServerSideCallAsync();
var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
// TODO(jtattermusch): should we throw a different exception type instead?
Assert.Throws(typeof(InvalidOperationException), () => responseStream.WriteAsync("request1"));
@ -134,10 +134,10 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
var writeTask = responseStream.WriteAsync("request1");
fakeCall.SendCompletionHandler(false);
fakeCall.SendCompletionCallback.OnSendCompletion(false);
Assert.ThrowsAsync(typeof(IOException), async () => await writeTask);
fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
AssertFinished(asyncCallServer, fakeCall, finishedTask);
}
@ -150,13 +150,13 @@ namespace Grpc.Core.Internal.Tests
var writeTask = responseStream.WriteAsync("request1");
var writeStatusTask = asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata(), null);
fakeCall.SendCompletionHandler(true);
fakeCall.SendStatusFromServerHandler(true);
fakeCall.SendCompletionCallback.OnSendCompletion(true);
fakeCall.SendStatusFromServerCallback.OnSendStatusFromServerCompletion(true);
Assert.DoesNotThrowAsync(async () => await writeTask);
Assert.DoesNotThrowAsync(async () => await writeStatusTask);
fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
AssertFinished(asyncCallServer, fakeCall, finishedTask);
}
@ -170,8 +170,8 @@ namespace Grpc.Core.Internal.Tests
asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata(), null);
Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await responseStream.WriteAsync("request1"));
fakeCall.SendStatusFromServerHandler(true);
fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
fakeCall.SendStatusFromServerCallback.OnSendStatusFromServerCompletion(true);
fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
AssertFinished(asyncCallServer, fakeCall, finishedTask);
}

@ -73,7 +73,7 @@ namespace Grpc.Core.Internal.Tests
public void AsyncUnary_Success()
{
var resultTask = asyncCall.UnaryCallAsync("request1");
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
CreateResponsePayload(),
new Metadata());
@ -85,7 +85,7 @@ namespace Grpc.Core.Internal.Tests
public void AsyncUnary_NonSuccessStatusCode()
{
var resultTask = asyncCall.UnaryCallAsync("request1");
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.InvalidArgument),
null,
new Metadata());
@ -97,7 +97,7 @@ namespace Grpc.Core.Internal.Tests
public void AsyncUnary_NullResponsePayload()
{
var resultTask = asyncCall.UnaryCallAsync("request1");
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
null,
new Metadata());
@ -118,7 +118,7 @@ namespace Grpc.Core.Internal.Tests
public void ClientStreaming_NoRequest_Success()
{
var resultTask = asyncCall.ClientStreamingCallAsync();
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
CreateResponsePayload(),
new Metadata());
@ -130,7 +130,7 @@ namespace Grpc.Core.Internal.Tests
public void ClientStreaming_NoRequest_NonSuccessStatusCode()
{
var resultTask = asyncCall.ClientStreamingCallAsync();
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.InvalidArgument),
null,
new Metadata());
@ -145,18 +145,18 @@ namespace Grpc.Core.Internal.Tests
var requestStream = new ClientRequestStream<string, string>(asyncCall);
var writeTask = requestStream.WriteAsync("request1");
fakeCall.SendCompletionHandler(true);
fakeCall.SendCompletionCallback.OnSendCompletion(true);
writeTask.Wait();
var writeTask2 = requestStream.WriteAsync("request2");
fakeCall.SendCompletionHandler(true);
fakeCall.SendCompletionCallback.OnSendCompletion(true);
writeTask2.Wait();
var completeTask = requestStream.CompleteAsync();
fakeCall.SendCompletionHandler(true);
fakeCall.SendCompletionCallback.OnSendCompletion(true);
completeTask.Wait();
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
CreateResponsePayload(),
new Metadata());
@ -171,12 +171,12 @@ namespace Grpc.Core.Internal.Tests
var requestStream = new ClientRequestStream<string, string>(asyncCall);
var writeTask = requestStream.WriteAsync("request1");
fakeCall.SendCompletionHandler(false);
fakeCall.SendCompletionCallback.OnSendCompletion(false);
// The write will wait for call to finish to receive the status code.
Assert.IsFalse(writeTask.IsCompleted);
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.Internal),
null,
new Metadata());
@ -195,12 +195,12 @@ namespace Grpc.Core.Internal.Tests
var writeTask = requestStream.WriteAsync("request1");
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.Internal),
null,
new Metadata());
fakeCall.SendCompletionHandler(false);
fakeCall.SendCompletionCallback.OnSendCompletion(false);
var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
@ -215,13 +215,13 @@ namespace Grpc.Core.Internal.Tests
var requestStream = new ClientRequestStream<string, string>(asyncCall);
var writeTask = requestStream.WriteAsync("request1");
fakeCall.SendCompletionHandler(false);
fakeCall.SendCompletionCallback.OnSendCompletion(false);
// Until the delayed write completion has been triggered,
// we still act as if there was an active write.
Assert.Throws(typeof(InvalidOperationException), () => requestStream.WriteAsync("request2"));
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.Internal),
null,
new Metadata());
@ -242,7 +242,7 @@ namespace Grpc.Core.Internal.Tests
var resultTask = asyncCall.ClientStreamingCallAsync();
var requestStream = new ClientRequestStream<string, string>(asyncCall);
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
CreateResponsePayload(),
new Metadata());
@ -260,7 +260,7 @@ namespace Grpc.Core.Internal.Tests
var resultTask = asyncCall.ClientStreamingCallAsync();
var requestStream = new ClientRequestStream<string, string>(asyncCall);
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
new ClientSideStatus(new Status(StatusCode.OutOfRange, ""), new Metadata()),
CreateResponsePayload(),
new Metadata());
@ -282,9 +282,9 @@ namespace Grpc.Core.Internal.Tests
Assert.Throws(typeof(InvalidOperationException), () => requestStream.WriteAsync("request1"));
fakeCall.SendCompletionHandler(true);
fakeCall.SendCompletionCallback.OnSendCompletion(true);
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
CreateResponsePayload(),
new Metadata());
@ -298,7 +298,7 @@ namespace Grpc.Core.Internal.Tests
var resultTask = asyncCall.ClientStreamingCallAsync();
var requestStream = new ClientRequestStream<string, string>(asyncCall);
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
CreateResponsePayload(),
new Metadata());
@ -319,7 +319,7 @@ namespace Grpc.Core.Internal.Tests
var writeTask = requestStream.WriteAsync("request1");
Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await writeTask);
fakeCall.UnaryResponseClientHandler(true,
fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
CreateClientSideStatus(StatusCode.Cancelled),
null,
new Metadata());
@ -342,11 +342,11 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedResponseHeadersHandler(true, new Metadata());
fakeCall.ReceivedResponseHeadersCallback.OnReceivedResponseHeaders(true, new Metadata());
Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count);
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
}
@ -359,8 +359,8 @@ namespace Grpc.Core.Internal.Tests
var readTask = responseStream.MoveNext();
// try alternative order of completions
fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
}
@ -372,8 +372,8 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(false, null); // after a failed read, we rely on C core to deliver appropriate status code.
fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Internal));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, null); // 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);
}
@ -385,18 +385,18 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var readTask1 = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateResponsePayload());
Assert.IsTrue(readTask1.Result);
Assert.AreEqual("response1", responseStream.Current);
var readTask2 = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateResponsePayload());
Assert.IsTrue(readTask2.Result);
Assert.AreEqual("response1", responseStream.Current);
var readTask3 = responseStream.MoveNext();
fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask3);
}
@ -409,12 +409,12 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var writeTask1 = requestStream.CompleteAsync();
fakeCall.SendCompletionHandler(true);
fakeCall.SendCompletionCallback.OnSendCompletion(true);
Assert.DoesNotThrowAsync(async () => await writeTask1);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
}
@ -427,8 +427,8 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
@ -445,8 +445,8 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
@ -461,14 +461,14 @@ namespace Grpc.Core.Internal.Tests
var responseStream = new ClientResponseStream<string, string>(asyncCall);
var writeTask = requestStream.WriteAsync("request1");
fakeCall.SendCompletionHandler(false);
fakeCall.SendCompletionCallback.OnSendCompletion(false);
// The write will wait for call to finish to receive the status code.
Assert.IsFalse(writeTask.IsCompleted);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.PermissionDenied));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.PermissionDenied));
var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
Assert.AreEqual(StatusCode.PermissionDenied, ex.Status.StatusCode);
@ -486,9 +486,9 @@ namespace Grpc.Core.Internal.Tests
var writeTask = requestStream.WriteAsync("request1");
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.PermissionDenied));
fakeCall.SendCompletionHandler(false);
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.PermissionDenied));
fakeCall.SendCompletionCallback.OnSendCompletion(false);
var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
Assert.AreEqual(StatusCode.PermissionDenied, ex.Status.StatusCode);
@ -510,8 +510,8 @@ namespace Grpc.Core.Internal.Tests
Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await writeTask);
var readTask = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled));
AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Cancelled);
}
@ -526,13 +526,13 @@ namespace Grpc.Core.Internal.Tests
Assert.IsTrue(fakeCall.IsCancelled);
var readTask1 = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateResponsePayload());
Assert.IsTrue(readTask1.Result);
Assert.AreEqual("response1", responseStream.Current);
var readTask2 = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled));
AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
}
@ -547,13 +547,13 @@ namespace Grpc.Core.Internal.Tests
asyncCall.Cancel();
Assert.IsTrue(fakeCall.IsCancelled);
fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateResponsePayload());
Assert.IsTrue(readTask1.Result);
Assert.AreEqual("response1", responseStream.Current);
var readTask2 = responseStream.MoveNext();
fakeCall.ReceivedMessageHandler(true, null);
fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled));
AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
}

@ -31,43 +31,43 @@ namespace Grpc.Core.Internal.Tests
/// </summary>
internal class FakeNativeCall : INativeCall
{
public UnaryResponseClientHandler UnaryResponseClientHandler
public IUnaryResponseClientCallback UnaryResponseClientCallback
{
get;
set;
}
public ReceivedStatusOnClientHandler ReceivedStatusOnClientHandler
public IReceivedStatusOnClientCallback ReceivedStatusOnClientCallback
{
get;
set;
}
public ReceivedMessageHandler ReceivedMessageHandler
public IReceivedMessageCallback ReceivedMessageCallback
{
get;
set;
}
public ReceivedResponseHeadersHandler ReceivedResponseHeadersHandler
public IReceivedResponseHeadersCallback ReceivedResponseHeadersCallback
{
get;
set;
}
public SendCompletionHandler SendCompletionHandler
public ISendCompletionCallback SendCompletionCallback
{
get;
set;
}
public SendCompletionHandler SendStatusFromServerHandler
public ISendStatusFromServerCompletionCallback SendStatusFromServerCallback
{
get;
set;
}
public ReceivedCloseOnServerHandler ReceivedCloseOnServerHandler
public IReceivedCloseOnServerCallback ReceivedCloseOnServerCallback
{
get;
set;
@ -100,9 +100,9 @@ namespace Grpc.Core.Internal.Tests
return "PEER";
}
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
public void StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
UnaryResponseClientHandler = callback;
UnaryResponseClientCallback = callback;
}
public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
@ -110,55 +110,55 @@ namespace Grpc.Core.Internal.Tests
throw new NotImplementedException();
}
public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
public void StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
UnaryResponseClientHandler = callback;
UnaryResponseClientCallback = callback;
}
public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
public void StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
ReceivedStatusOnClientHandler = callback;
ReceivedStatusOnClientCallback = callback;
}
public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
public void StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
ReceivedStatusOnClientHandler = callback;
ReceivedStatusOnClientCallback = callback;
}
public void StartReceiveMessage(ReceivedMessageHandler callback)
public void StartReceiveMessage(IReceivedMessageCallback callback)
{
ReceivedMessageHandler = callback;
ReceivedMessageCallback = callback;
}
public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback)
public void StartReceiveInitialMetadata(IReceivedResponseHeadersCallback callback)
{
ReceivedResponseHeadersHandler = callback;
ReceivedResponseHeadersCallback = callback;
}
public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray)
public void StartSendInitialMetadata(ISendCompletionCallback callback, MetadataArraySafeHandle metadataArray)
{
SendCompletionHandler = callback;
SendCompletionCallback = callback;
}
public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
public void StartSendMessage(ISendCompletionCallback callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
{
SendCompletionHandler = callback;
SendCompletionCallback = callback;
}
public void StartSendCloseFromClient(SendCompletionHandler callback)
public void StartSendCloseFromClient(ISendCompletionCallback callback)
{
SendCompletionHandler = callback;
SendCompletionCallback = callback;
}
public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
public void StartSendStatusFromServer(ISendStatusFromServerCompletionCallback callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
byte[] optionalPayload, WriteFlags writeFlags)
{
SendStatusFromServerHandler = callback;
SendStatusFromServerCallback = callback;
}
public void StartServerSide(ReceivedCloseOnServerHandler callback)
public void StartServerSide(IReceivedCloseOnServerCallback callback)
{
ReceivedCloseOnServerHandler = callback;
ReceivedCloseOnServerCallback = callback;
}
public void Dispose()

@ -63,7 +63,7 @@ namespace Grpc.Core.Tests
[Ignore("Prevent running on Jenkins")]
public void NativeCallbackBenchmark()
{
OpCompletionDelegate handler = Handler;
NativeCallbackTestDelegate handler = Handler;
counter = 0;
BenchmarkUtil.RunBenchmark(
@ -91,7 +91,7 @@ namespace Grpc.Core.Tests
10000, 10000,
() =>
{
Native.grpcsharp_test_callback(new OpCompletionDelegate(Handler));
Native.grpcsharp_test_callback(new NativeCallbackTestDelegate(Handler));
});
Assert.AreNotEqual(0, counter);
}

@ -127,6 +127,20 @@ namespace Grpc.Core
}
}
// cached handler for watch connectivity state
static readonly BatchCompletionDelegate WatchConnectivityStateHandler = (success, ctx, state) =>
{
var tcs = (TaskCompletionSource<object>) state;
if (success)
{
tcs.SetResult(null);
}
else
{
tcs.SetCanceled();
}
};
/// <summary>
/// Returned tasks completes once channel state has become different from
/// given lastObservedState.
@ -138,18 +152,8 @@ namespace Grpc.Core
"Shutdown is a terminal state. No further state changes can occur.");
var tcs = new TaskCompletionSource<object>();
var deadlineTimespec = deadline.HasValue ? Timespec.FromDateTime(deadline.Value) : Timespec.InfFuture;
var handler = new BatchCompletionDelegate((success, ctx) =>
{
if (success)
{
tcs.SetResult(null);
}
else
{
tcs.SetCanceled();
}
});
handle.WatchConnectivityState(lastObservedState, deadlineTimespec, completionQueue, handler);
// pass "tcs" as "state" for WatchConnectivityStateHandler.
handle.WatchConnectivityState(lastObservedState, deadlineTimespec, completionQueue, WatchConnectivityStateHandler, tcs);
return tcs.Task;
}

@ -27,7 +27,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Manages client side native call lifecycle.
/// </summary>
internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>
internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>, IUnaryResponseClientCallback, IReceivedStatusOnClientCallback, IReceivedResponseHeadersCallback
{
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCall<TRequest, TResponse>>();
@ -138,7 +138,7 @@ namespace Grpc.Core.Internal
unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
call.StartUnary(HandleUnaryResponse, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
call.StartUnary(UnaryResponseClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
}
return unaryResponseTcs.Task;
}
@ -162,7 +162,7 @@ namespace Grpc.Core.Internal
unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
call.StartClientStreaming(HandleUnaryResponse, metadataArray, details.Options.Flags);
call.StartClientStreaming(UnaryResponseClientCallback, metadataArray, details.Options.Flags);
}
return unaryResponseTcs.Task;
@ -188,9 +188,9 @@ namespace Grpc.Core.Internal
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
call.StartServerStreaming(HandleFinished, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
call.StartServerStreaming(ReceivedStatusOnClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
}
call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders);
call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback);
}
}
@ -210,9 +210,9 @@ namespace Grpc.Core.Internal
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
call.StartDuplexStreaming(HandleFinished, metadataArray, details.Options.Flags);
call.StartDuplexStreaming(ReceivedStatusOnClientCallback, metadataArray, details.Options.Flags);
}
call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders);
call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback);
}
}
@ -256,7 +256,7 @@ namespace Grpc.Core.Internal
halfcloseRequested = true;
return TaskUtils.CompletedTask;
}
call.StartSendCloseFromClient(HandleSendFinished);
call.StartSendCloseFromClient(SendCompletionCallback);
halfcloseRequested = true;
streamingWriteTcs = new TaskCompletionSource<object>();
@ -516,5 +516,26 @@ namespace Grpc.Core.Internal
streamingResponseCallFinishedTcs.SetResult(null);
}
IUnaryResponseClientCallback UnaryResponseClientCallback => this;
void IUnaryResponseClientCallback.OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders)
{
HandleUnaryResponse(success, receivedStatus, receivedMessage, responseHeaders);
}
IReceivedStatusOnClientCallback ReceivedStatusOnClientCallback => this;
void IReceivedStatusOnClientCallback.OnReceivedStatusOnClient(bool success, ClientSideStatus receivedStatus)
{
HandleFinished(success, receivedStatus);
}
IReceivedResponseHeadersCallback ReceivedResponseHeadersCallback => this;
void IReceivedResponseHeadersCallback.OnReceivedResponseHeaders(bool success, Metadata responseHeaders)
{
HandleReceivedResponseHeaders(success, responseHeaders);
}
}
}

@ -35,7 +35,7 @@ namespace Grpc.Core.Internal
/// Base for handling both client side and server side calls.
/// Manages native call lifecycle and provides convenience methods.
/// </summary>
internal abstract class AsyncCallBase<TWrite, TRead>
internal abstract class AsyncCallBase<TWrite, TRead> : IReceivedMessageCallback, ISendCompletionCallback
{
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCallBase<TWrite, TRead>>();
protected static readonly Status DeserializeResponseFailureStatus = new Status(StatusCode.Internal, "Failed to deserialize response message.");
@ -126,7 +126,7 @@ namespace Grpc.Core.Internal
return earlyResult;
}
call.StartSendMessage(HandleSendFinished, payload, writeFlags, !initialMetadataSent);
call.StartSendMessage(SendCompletionCallback, payload, writeFlags, !initialMetadataSent);
initialMetadataSent = true;
streamingWritesCounter++;
@ -154,7 +154,7 @@ namespace Grpc.Core.Internal
GrpcPreconditions.CheckState(streamingReadTcs == null, "Only one read can be pending at a time");
GrpcPreconditions.CheckState(!disposed);
call.StartReceiveMessage(HandleReadFinished);
call.StartReceiveMessage(ReceivedMessageCallback);
streamingReadTcs = new TaskCompletionSource<TRead>();
return streamingReadTcs.Task;
}
@ -342,5 +342,19 @@ namespace Grpc.Core.Internal
}
origTcs.SetResult(msg);
}
protected ISendCompletionCallback SendCompletionCallback => this;
void ISendCompletionCallback.OnSendCompletion(bool success)
{
HandleSendFinished(success);
}
IReceivedMessageCallback ReceivedMessageCallback => this;
void IReceivedMessageCallback.OnReceivedMessage(bool success, byte[] receivedMessage)
{
HandleReadFinished(success, receivedMessage);
}
}
}

@ -31,7 +31,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Manages server side native call lifecycle.
/// </summary>
internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>
internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>, IReceivedCloseOnServerCallback, ISendStatusFromServerCompletionCallback
{
readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>();
readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
@ -70,7 +70,7 @@ namespace Grpc.Core.Internal
started = true;
call.StartServerSide(HandleFinishedServerside);
call.StartServerSide(ReceiveCloseOnServerCallback);
return finishedServersideTcs.Task;
}
}
@ -114,7 +114,7 @@ namespace Grpc.Core.Internal
using (var metadataArray = MetadataArraySafeHandle.Create(headers))
{
call.StartSendInitialMetadata(HandleSendFinished, metadataArray);
call.StartSendInitialMetadata(SendCompletionCallback, metadataArray);
}
this.initialMetadataSent = true;
@ -127,10 +127,10 @@ namespace Grpc.Core.Internal
/// Sends call result status, indicating we are done with writes.
/// Sending a status different from StatusCode.OK will also implicitly cancel the call.
/// </summary>
public Task SendStatusFromServerAsync(Status status, Metadata trailers, Tuple<TResponse, WriteFlags> optionalWrite)
public Task SendStatusFromServerAsync(Status status, Metadata trailers, ResponseWithFlags? optionalWrite)
{
byte[] payload = optionalWrite != null ? UnsafeSerialize(optionalWrite.Item1) : null;
var writeFlags = optionalWrite != null ? optionalWrite.Item2 : default(WriteFlags);
byte[] payload = optionalWrite.HasValue ? UnsafeSerialize(optionalWrite.Value.Response) : null;
var writeFlags = optionalWrite.HasValue ? optionalWrite.Value.WriteFlags : default(WriteFlags);
lock (myLock)
{
@ -140,13 +140,13 @@ namespace Grpc.Core.Internal
using (var metadataArray = MetadataArraySafeHandle.Create(trailers))
{
call.StartSendStatusFromServer(HandleSendStatusFromServerFinished, status, metadataArray, !initialMetadataSent,
call.StartSendStatusFromServer(SendStatusFromServerCompletionCallback, status, metadataArray, !initialMetadataSent,
payload, writeFlags);
}
halfcloseRequested = true;
initialMetadataSent = true;
sendStatusFromServerTcs = new TaskCompletionSource<object>();
if (optionalWrite != null)
if (optionalWrite.HasValue)
{
streamingWritesCounter++;
}
@ -227,5 +227,31 @@ namespace Grpc.Core.Internal
finishedServersideTcs.SetResult(null);
}
IReceivedCloseOnServerCallback ReceiveCloseOnServerCallback => this;
void IReceivedCloseOnServerCallback.OnReceivedCloseOnServer(bool success, bool cancelled)
{
HandleFinishedServerside(success, cancelled);
}
ISendStatusFromServerCompletionCallback SendStatusFromServerCompletionCallback => this;
void ISendStatusFromServerCompletionCallback.OnSendStatusFromServerCompletion(bool success)
{
HandleSendStatusFromServerFinished(success);
}
public struct ResponseWithFlags
{
public ResponseWithFlags(TResponse response, WriteFlags writeFlags)
{
this.Response = response;
this.WriteFlags = writeFlags;
}
public TResponse Response { get; }
public WriteFlags WriteFlags { get; }
}
}
}

@ -20,15 +20,25 @@ using System;
using System.Runtime.InteropServices;
using System.Text;
using Grpc.Core;
using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
internal interface IOpCompletionCallback
{
void OnComplete(bool success);
}
/// <summary>
/// grpcsharp_batch_context
/// </summary>
internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid
internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback
{
static readonly NativeMethods Native = NativeMethods.Get();
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<BatchContextSafeHandle>();
CompletionCallbackData completionCallbackData;
private BatchContextSafeHandle()
{
@ -47,6 +57,13 @@ namespace Grpc.Core.Internal
}
}
public void SetCompletionCallback(BatchCompletionDelegate callback, object state)
{
GrpcPreconditions.CheckState(completionCallbackData.Callback == null);
GrpcPreconditions.CheckNotNull(callback, nameof(callback));
completionCallbackData = new CompletionCallbackData(callback, state);
}
// Gets data of recv_initial_metadata completion.
public Metadata GetReceivedInitialMetadata()
{
@ -92,5 +109,34 @@ namespace Grpc.Core.Internal
Native.grpcsharp_batch_context_destroy(handle);
return true;
}
void IOpCompletionCallback.OnComplete(bool success)
{
try
{
completionCallbackData.Callback(success, this, completionCallbackData.State);
}
catch (Exception e)
{
Logger.Error(e, "Exception occured while invoking batch completion delegate.");
}
finally
{
completionCallbackData = default(CompletionCallbackData);
Dispose();
}
}
struct CompletionCallbackData
{
public CompletionCallbackData(BatchCompletionDelegate callback, object state)
{
this.Callback = callback;
this.State = state;
}
public BatchCompletionDelegate Callback { get; }
public object State { get; }
}
}
}

@ -32,6 +32,23 @@ namespace Grpc.Core.Internal
public static readonly CallSafeHandle NullInstance = new CallSafeHandle();
static readonly NativeMethods Native = NativeMethods.Get();
// 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());
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());
static readonly BatchCompletionDelegate CompletionHandler_IReceivedResponseHeadersCallback =
(success, context, state) => ((IReceivedResponseHeadersCallback)state).OnReceivedResponseHeaders(success, context.GetReceivedInitialMetadata());
static readonly BatchCompletionDelegate CompletionHandler_ISendCompletionCallback =
(success, context, state) => ((ISendCompletionCallback)state).OnSendCompletion(success);
static readonly BatchCompletionDelegate CompletionHandler_ISendStatusFromServerCompletionCallback =
(success, context, state) => ((ISendStatusFromServerCompletionCallback)state).OnSendStatusFromServerCompletion(success);
static readonly BatchCompletionDelegate CompletionHandler_IReceivedCloseOnServerCallback =
(success, context, state) => ((IReceivedCloseOnServerCallback)state).OnReceivedCloseOnServer(success, context.GetReceivedCloseOnServerCancelled());
const uint GRPC_WRITE_BUFFER_HINT = 1;
CompletionQueueSafeHandle completionQueue;
@ -49,12 +66,12 @@ namespace Grpc.Core.Internal
Native.grpcsharp_call_set_credentials(this, credentials).CheckOk();
}
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
public void StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_IUnaryResponseClientCallback, callback);
Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags)
.CheckOk();
}
@ -66,106 +83,106 @@ namespace Grpc.Core.Internal
.CheckOk();
}
public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
public void StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_IUnaryResponseClientCallback, callback);
Native.grpcsharp_call_start_client_streaming(this, ctx, metadataArray, callFlags).CheckOk();
}
}
public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
public void StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_IReceivedStatusOnClientCallback, callback);
Native.grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags).CheckOk();
}
}
public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
public void StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_IReceivedStatusOnClientCallback, callback);
Native.grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray, callFlags).CheckOk();
}
}
public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
public void StartSendMessage(ISendCompletionCallback callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_ISendCompletionCallback, callback);
Native.grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, sendEmptyInitialMetadata ? 1 : 0).CheckOk();
}
}
public void StartSendCloseFromClient(SendCompletionHandler callback)
public void StartSendCloseFromClient(ISendCompletionCallback callback)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_ISendCompletionCallback, callback);
Native.grpcsharp_call_send_close_from_client(this, ctx).CheckOk();
}
}
public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
public void StartSendStatusFromServer(ISendStatusFromServerCompletionCallback callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
byte[] optionalPayload, WriteFlags writeFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
var optionalPayloadLength = optionalPayload != null ? new UIntPtr((ulong)optionalPayload.Length) : UIntPtr.Zero;
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_ISendStatusFromServerCompletionCallback, callback);
var statusDetailBytes = MarshalUtils.GetBytesUTF8(status.Detail);
Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, statusDetailBytes, new UIntPtr((ulong)statusDetailBytes.Length), metadataArray, sendEmptyInitialMetadata ? 1 : 0,
optionalPayload, optionalPayloadLength, writeFlags).CheckOk();
}
}
public void StartReceiveMessage(ReceivedMessageHandler callback)
public void StartReceiveMessage(IReceivedMessageCallback callback)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedMessage()));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_IReceivedMessageCallback, callback);
Native.grpcsharp_call_recv_message(this, ctx).CheckOk();
}
}
public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback)
public void StartReceiveInitialMetadata(IReceivedResponseHeadersCallback callback)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedInitialMetadata()));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_IReceivedResponseHeadersCallback, callback);
Native.grpcsharp_call_recv_initial_metadata(this, ctx).CheckOk();
}
}
public void StartServerSide(ReceivedCloseOnServerHandler callback)
public void StartServerSide(IReceivedCloseOnServerCallback callback)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedCloseOnServerCancelled()));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_IReceivedCloseOnServerCallback, callback);
Native.grpcsharp_call_start_serverside(this, ctx).CheckOk();
}
}
public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray)
public void StartSendInitialMetadata(ISendCompletionCallback callback, MetadataArraySafeHandle metadataArray)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, CompletionHandler_ISendCompletionCallback, callback);
Native.grpcsharp_call_send_initial_metadata(this, ctx, metadataArray).CheckOk();
}
}

@ -64,10 +64,10 @@ namespace Grpc.Core.Internal
return Native.grpcsharp_channel_check_connectivity_state(this, tryToConnect ? 1 : 0);
}
public void WatchConnectivityState(ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
public void WatchConnectivityState(ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchCompletionDelegate callback, object callbackState)
{
var ctx = BatchContextSafeHandle.Create();
cq.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
cq.CompletionRegistry.RegisterBatchCompletion(ctx, callback, callbackState);
Native.grpcsharp_channel_watch_connectivity_state(this, lastObservedState, deadline, cq, ctx);
}

@ -19,15 +19,15 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Grpc.Core.Logging;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
internal delegate void OpCompletionDelegate(bool success);
internal delegate void BatchCompletionDelegate(bool success, BatchContextSafeHandle ctx);
internal delegate void BatchCompletionDelegate(bool success, BatchContextSafeHandle ctx, object state);
internal delegate void RequestCallCompletionDelegate(bool success, RequestCallContextSafeHandle ctx);
@ -36,8 +36,8 @@ namespace Grpc.Core.Internal
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<CompletionRegistry>();
readonly GrpcEnvironment environment;
readonly Dictionary<IntPtr, OpCompletionDelegate> dict = new Dictionary<IntPtr, OpCompletionDelegate>(new IntPtrComparer());
readonly object myLock = new object();
readonly Dictionary<IntPtr, IOpCompletionCallback> dict = new Dictionary<IntPtr, IOpCompletionCallback>(new IntPtrComparer());
SpinLock spinLock = new SpinLock(Debugger.IsAttached);
IntPtr lastRegisteredKey; // only for testing
public CompletionRegistry(GrpcEnvironment environment)
@ -45,38 +45,51 @@ namespace Grpc.Core.Internal
this.environment = environment;
}
public void Register(IntPtr key, OpCompletionDelegate callback)
public void Register(IntPtr key, IOpCompletionCallback callback)
{
environment.DebugStats.PendingBatchCompletions.Increment();
lock (myLock)
bool lockTaken = false;
try
{
spinLock.Enter(ref lockTaken);
dict.Add(key, callback);
this.lastRegisteredKey = key;
}
finally
{
if (lockTaken) spinLock.Exit();
}
}
public void RegisterBatchCompletion(BatchContextSafeHandle ctx, BatchCompletionDelegate callback)
public void RegisterBatchCompletion(BatchContextSafeHandle ctx, BatchCompletionDelegate callback, object state)
{
// TODO(jtattermusch): get rid of new delegate creation here
OpCompletionDelegate opCallback = ((success) => HandleBatchCompletion(success, ctx, callback));
Register(ctx.Handle, opCallback);
ctx.SetCompletionCallback(callback, state);
Register(ctx.Handle, ctx);
}
public void RegisterRequestCallCompletion(RequestCallContextSafeHandle ctx, RequestCallCompletionDelegate callback)
{
// TODO(jtattermusch): get rid of new delegate creation here
OpCompletionDelegate opCallback = ((success) => HandleRequestCallCompletion(success, ctx, callback));
Register(ctx.Handle, opCallback);
ctx.CompletionCallback = callback;
Register(ctx.Handle, ctx);
}
public OpCompletionDelegate Extract(IntPtr key)
public IOpCompletionCallback Extract(IntPtr key)
{
OpCompletionDelegate value = null;
lock (myLock)
IOpCompletionCallback value = null;
bool lockTaken = false;
try
{
spinLock.Enter(ref lockTaken);
value = dict[key];
dict.Remove(key);
}
finally
{
if (lockTaken) spinLock.Exit();
}
environment.DebugStats.PendingBatchCompletions.Decrement();
return value;
}
@ -89,44 +102,6 @@ namespace Grpc.Core.Internal
get { return this.lastRegisteredKey; }
}
private static void HandleBatchCompletion(bool success, BatchContextSafeHandle ctx, BatchCompletionDelegate callback)
{
try
{
callback(success, ctx);
}
catch (Exception e)
{
Logger.Error(e, "Exception occured while invoking batch completion delegate.");
}
finally
{
if (ctx != null)
{
ctx.Dispose();
}
}
}
private static void HandleRequestCallCompletion(bool success, RequestCallContextSafeHandle ctx, RequestCallCompletionDelegate callback)
{
try
{
callback(success, ctx);
}
catch (Exception e)
{
Logger.Error(e, "Exception occured while invoking request call completion delegate.");
}
finally
{
if (ctx != null)
{
ctx.Dispose();
}
}
}
/// <summary>
/// IntPtr doesn't implement <c>IEquatable{IntPtr}</c> so we need to use custom comparer to avoid boxing.
/// </summary>

@ -68,8 +68,8 @@ namespace Grpc.Core.Internal
GrpcPreconditions.CheckArgument(poolSize >= completionQueueCount,
"Thread pool size cannot be smaller than the number of completion queues used.");
this.runCompletionQueueEventCallbackSuccess = new WaitCallback((callback) => RunCompletionQueueEventCallback((OpCompletionDelegate) callback, true));
this.runCompletionQueueEventCallbackFailure = new WaitCallback((callback) => RunCompletionQueueEventCallback((OpCompletionDelegate) callback, false));
this.runCompletionQueueEventCallbackSuccess = new WaitCallback((callback) => RunCompletionQueueEventCallback((IOpCompletionCallback) callback, true));
this.runCompletionQueueEventCallbackFailure = new WaitCallback((callback) => RunCompletionQueueEventCallback((IOpCompletionCallback) callback, false));
}
public void Start()
@ -225,11 +225,11 @@ namespace Grpc.Core.Internal
return list.AsReadOnly();
}
private void RunCompletionQueueEventCallback(OpCompletionDelegate callback, bool success)
private void RunCompletionQueueEventCallback(IOpCompletionCallback callback, bool success)
{
try
{
callback(success);
callback.OnComplete(success);
}
catch (Exception e)
{

@ -20,18 +20,41 @@ using Grpc.Core;
namespace Grpc.Core.Internal
{
internal delegate void UnaryResponseClientHandler(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders);
internal interface IUnaryResponseClientCallback
{
void OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders);
}
// Received status for streaming response calls.
internal delegate void ReceivedStatusOnClientHandler(bool success, ClientSideStatus receivedStatus);
internal interface IReceivedStatusOnClientCallback
{
void OnReceivedStatusOnClient(bool success, ClientSideStatus receivedStatus);
}
internal delegate void ReceivedMessageHandler(bool success, byte[] receivedMessage);
internal interface IReceivedMessageCallback
{
void OnReceivedMessage(bool success, byte[] receivedMessage);
}
internal delegate void ReceivedResponseHeadersHandler(bool success, Metadata responseHeaders);
internal interface IReceivedResponseHeadersCallback
{
void OnReceivedResponseHeaders(bool success, Metadata responseHeaders);
}
internal delegate void SendCompletionHandler(bool success);
internal interface ISendCompletionCallback
{
void OnSendCompletion(bool success);
}
internal delegate void ReceivedCloseOnServerHandler(bool success, bool cancelled);
internal interface ISendStatusFromServerCompletionCallback
{
void OnSendStatusFromServerCompletion(bool success);
}
internal interface IReceivedCloseOnServerCallback
{
void OnReceivedCloseOnServer(bool success, bool cancelled);
}
/// <summary>
/// Abstraction of a native call object.
@ -44,28 +67,28 @@ namespace Grpc.Core.Internal
string GetPeer();
void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartReceiveMessage(ReceivedMessageHandler callback);
void StartReceiveMessage(IReceivedMessageCallback callback);
void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback);
void StartReceiveInitialMetadata(IReceivedResponseHeadersCallback callback);
void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray);
void StartSendInitialMetadata(ISendCompletionCallback callback, MetadataArraySafeHandle metadataArray);
void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
void StartSendMessage(ISendCompletionCallback callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
void StartSendCloseFromClient(SendCompletionHandler callback);
void StartSendCloseFromClient(ISendCompletionCallback callback);
void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, WriteFlags writeFlags);
void StartSendStatusFromServer(ISendStatusFromServerCompletionCallback callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, WriteFlags writeFlags);
void StartServerSide(ReceivedCloseOnServerHandler callback);
void StartServerSide(IReceivedCloseOnServerCallback callback);
}
}

@ -29,6 +29,8 @@ using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
internal delegate void NativeCallbackTestDelegate(bool success);
/// <summary>
/// Provides access to all native methods provided by <c>NativeExtension</c>.
/// An extra level of indirection is added to P/Invoke calls to allow intelligent loading
@ -420,7 +422,7 @@ namespace Grpc.Core.Internal
public delegate Timespec gprsharp_convert_clock_type_delegate(Timespec t, ClockType targetClock);
public delegate int gprsharp_sizeof_timespec_delegate();
public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback);
public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] NativeCallbackTestDelegate callback);
public delegate IntPtr grpcsharp_test_nop_delegate(IntPtr ptr);
public delegate void grpcsharp_test_override_method_delegate(string methodName, string variant);
}

@ -19,15 +19,17 @@
using System;
using System.Runtime.InteropServices;
using Grpc.Core;
using Grpc.Core.Logging;
namespace Grpc.Core.Internal
{
/// <summary>
/// grpcsharp_request_call_context
/// </summary>
internal class RequestCallContextSafeHandle : SafeHandleZeroIsInvalid
internal class RequestCallContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback
{
static readonly NativeMethods Native = NativeMethods.Get();
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<RequestCallContextSafeHandle>();
private RequestCallContextSafeHandle()
{
@ -46,6 +48,8 @@ namespace Grpc.Core.Internal
}
}
public RequestCallCompletionDelegate CompletionCallback { get; set; }
// Gets data of server_rpc_new completion.
public ServerRpcNew GetServerRpcNew(Server server)
{
@ -72,5 +76,22 @@ namespace Grpc.Core.Internal
Native.grpcsharp_request_call_context_destroy(handle);
return true;
}
void IOpCompletionCallback.OnComplete(bool success)
{
try
{
CompletionCallback(success, this);
}
catch (Exception e)
{
Logger.Error(e, "Exception occured while invoking request call completion delegate.");
}
finally
{
CompletionCallback = null;
Dispose();
}
}
}
}

@ -60,7 +60,7 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
Tuple<TResponse,WriteFlags> responseTuple = null;
AsyncCallServer<TRequest,TResponse>.ResponseWithFlags? responseWithFlags = null;
var context = HandlerUtils.NewContext(newRpc, responseStream, asyncCall.CancellationToken);
try
{
@ -68,7 +68,7 @@ namespace Grpc.Core.Internal
var request = requestStream.Current;
var response = await handler(request, context).ConfigureAwait(false);
status = context.Status;
responseTuple = Tuple.Create(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
responseWithFlags = new AsyncCallServer<TRequest, TResponse>.ResponseWithFlags(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
}
catch (Exception e)
{
@ -80,7 +80,7 @@ namespace Grpc.Core.Internal
}
try
{
await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseTuple).ConfigureAwait(false);
await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseWithFlags).ConfigureAwait(false);
}
catch (Exception)
{
@ -177,13 +177,13 @@ namespace Grpc.Core.Internal
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status;
Tuple<TResponse,WriteFlags> responseTuple = null;
AsyncCallServer<TRequest, TResponse>.ResponseWithFlags? responseWithFlags = null;
var context = HandlerUtils.NewContext(newRpc, responseStream, asyncCall.CancellationToken);
try
{
var response = await handler(requestStream, context).ConfigureAwait(false);
status = context.Status;
responseTuple = Tuple.Create(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
responseWithFlags = new AsyncCallServer<TRequest, TResponse>.ResponseWithFlags(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
}
catch (Exception e)
{
@ -196,7 +196,7 @@ namespace Grpc.Core.Internal
try
{
await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseTuple).ConfigureAwait(false);
await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseWithFlags).ConfigureAwait(false);
}
catch (Exception)
{

@ -65,7 +65,9 @@ namespace Grpc.Core.Internal
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
// TODO(jtattermusch): delegate allocation by caller can be avoided by utilizing the "state" object,
// but server shutdown isn't worth optimizing right now.
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, callback, null);
Native.grpcsharp_server_shutdown_and_notify_callback(this, completionQueue, ctx);
}
}

@ -387,7 +387,7 @@ namespace Grpc.Core
/// <summary>
/// Handles native callback.
/// </summary>
private void HandleServerShutdown(bool success, BatchContextSafeHandle ctx)
private void HandleServerShutdown(bool success, BatchContextSafeHandle ctx, object state)
{
shutdownTcs.SetResult(null);
}

@ -1,7 +1,7 @@
<!-- This file is generated -->
<Project>
<PropertyGroup>
<GrpcCsharpVersion>1.7.2</GrpcCsharpVersion>
<GrpcCsharpVersion>1.9.0-dev</GrpcCsharpVersion>
<GoogleProtobufVersion>3.3.0</GoogleProtobufVersion>
</PropertyGroup>
</Project>

@ -33,11 +33,11 @@ namespace Grpc.Core
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
public const string CurrentAssemblyFileVersion = "1.7.2.0";
public const string CurrentAssemblyFileVersion = "1.9.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
public const string CurrentVersion = "1.7.2";
public const string CurrentVersion = "1.9.0-dev";
}
}

@ -0,0 +1,78 @@
#region Copyright notice and license
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Grpc.Core;
using Grpc.Core.Internal;
using System.Collections.Generic;
using System.Diagnostics;
namespace Grpc.Microbenchmarks
{
public class CompletionRegistryBenchmark
{
GrpcEnvironment environment;
public void Init()
{
environment = GrpcEnvironment.AddRef();
}
public void Cleanup()
{
GrpcEnvironment.ReleaseAsync().Wait();
}
public void Run(int threadCount, int iterations, bool useSharedRegistry)
{
Console.WriteLine(string.Format("CompletionRegistryBenchmark: threads={0}, iterations={1}, useSharedRegistry={2}", threadCount, iterations, useSharedRegistry));
CompletionRegistry sharedRegistry = useSharedRegistry ? new CompletionRegistry(environment) : null;
var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, sharedRegistry));
threadedBenchmark.Run();
// TODO: parametrize by number of pending completions
}
private void ThreadBody(int iterations, CompletionRegistry optionalSharedRegistry)
{
var completionRegistry = optionalSharedRegistry ?? new CompletionRegistry(environment);
var ctx = BatchContextSafeHandle.Create();
var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
completionRegistry.Register(ctx.Handle, ctx);
var callback = completionRegistry.Extract(ctx.Handle);
// NOTE: we are not calling the callback to avoid disposing ctx.
}
stopwatch.Stop();
Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds);
ctx.Dispose();
}
private class NopCompletionCallback : IOpCompletionCallback
{
public void OnComplete(bool success)
{
}
}
}
}

@ -0,0 +1,69 @@
#region Copyright notice and license
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
using System;
using Grpc.Core;
using Grpc.Core.Internal;
namespace Grpc.Microbenchmarks
{
internal class GCStats
{
readonly object myLock = new object();
GCStatsSnapshot lastSnapshot;
public GCStats()
{
lastSnapshot = new GCStatsSnapshot(GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2));
}
public GCStatsSnapshot GetSnapshot(bool reset = false)
{
lock (myLock)
{
var newSnapshot = new GCStatsSnapshot(GC.CollectionCount(0) - lastSnapshot.Gen0,
GC.CollectionCount(1) - lastSnapshot.Gen1,
GC.CollectionCount(2) - lastSnapshot.Gen2);
if (reset)
{
lastSnapshot = newSnapshot;
}
return newSnapshot;
}
}
}
public class GCStatsSnapshot
{
public GCStatsSnapshot(int gen0, int gen1, int gen2)
{
this.Gen0 = gen0;
this.Gen1 = gen1;
this.Gen2 = gen2;
}
public int Gen0 { get; }
public int Gen1 { get; }
public int Gen2 { get; }
public override string ToString()
{
return string.Format("[GCCollectionCount: gen0 {0}, gen1 {1}, gen2 {2}]", Gen0, Gen1, Gen2);
}
}
}

@ -15,6 +15,10 @@
<ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />

@ -0,0 +1,64 @@
#region Copyright notice and license
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Grpc.Core;
using Grpc.Core.Internal;
using System.Collections.Generic;
using System.Diagnostics;
namespace Grpc.Microbenchmarks
{
public class PInvokeByteArrayBenchmark
{
static readonly NativeMethods Native = NativeMethods.Get();
public void Init()
{
}
public void Cleanup()
{
}
public void Run(int threadCount, int iterations, int payloadSize)
{
Console.WriteLine(string.Format("PInvokeByteArrayBenchmark: threads={0}, iterations={1}, payloadSize={2}", threadCount, iterations, payloadSize));
var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, payloadSize));
threadedBenchmark.Run();
}
private void ThreadBody(int iterations, int payloadSize)
{
var payload = new byte[payloadSize];
var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
var gcHandle = GCHandle.Alloc(payload, GCHandleType.Pinned);
var payloadPtr = gcHandle.AddrOfPinnedObject();
Native.grpcsharp_test_nop(payloadPtr);
gcHandle.Free();
}
stopwatch.Stop();
Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds);
}
}
}

@ -20,14 +20,84 @@ using System;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Logging;
using CommandLine;
using CommandLine.Text;
namespace Grpc.Microbenchmarks
{
class Program
{
public enum MicrobenchmarkType
{
CompletionRegistry,
PInvokeByteArray,
SendMessage
}
private class BenchmarkOptions
{
[Option("benchmark", Required = true, HelpText = "Benchmark to run")]
public MicrobenchmarkType Benchmark { get; set; }
}
public static void Main(string[] args)
{
GrpcEnvironment.SetLogger(new ConsoleLogger());
var parserResult = Parser.Default.ParseArguments<BenchmarkOptions>(args)
.WithNotParsed(errors => {
Console.WriteLine("Supported benchmarks:");
foreach (var enumValue in Enum.GetValues(typeof(MicrobenchmarkType)))
{
Console.WriteLine(" " + enumValue);
}
Environment.Exit(1);
})
.WithParsed(options =>
{
switch (options.Benchmark)
{
case MicrobenchmarkType.CompletionRegistry:
RunCompletionRegistryBenchmark();
break;
case MicrobenchmarkType.PInvokeByteArray:
RunPInvokeByteArrayBenchmark();
break;
case MicrobenchmarkType.SendMessage:
RunSendMessageBenchmark();
break;
default:
throw new ArgumentException("Unsupported benchmark.");
}
});
}
static void RunCompletionRegistryBenchmark()
{
var benchmark = new CompletionRegistryBenchmark();
benchmark.Init();
foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12})
{
foreach (bool useSharedRegistry in new bool[] {false, true})
{
benchmark.Run(threadCount, 4 * 1000 * 1000, useSharedRegistry);
}
}
benchmark.Cleanup();
}
static void RunPInvokeByteArrayBenchmark()
{
var benchmark = new PInvokeByteArrayBenchmark();
benchmark.Init();
foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12})
{
benchmark.Run(threadCount, 4 * 1000 * 1000, 0);
}
benchmark.Cleanup();
}
static void RunSendMessageBenchmark()
{
var benchmark = new SendMessageBenchmark();
benchmark.Init();
foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12})

@ -59,16 +59,16 @@ namespace Grpc.Microbenchmarks
var cq = CompletionQueueSafeHandle.CreateAsync(completionRegistry);
var call = CreateFakeCall(cq);
var sendCompletionHandler = new SendCompletionHandler((success) => { });
var sendCompletionCallback = new NopSendCompletionCallback();
var payload = new byte[payloadSize];
var writeFlags = default(WriteFlags);
var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
call.StartSendMessage(sendCompletionHandler, payload, writeFlags, false);
call.StartSendMessage(sendCompletionCallback, payload, writeFlags, false);
var callback = completionRegistry.Extract(completionRegistry.LastRegisteredKey);
callback(true);
callback.OnComplete(true);
}
stopwatch.Stop();
Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds);
@ -87,5 +87,13 @@ namespace Grpc.Microbenchmarks
}
return call;
}
private class NopSendCompletionCallback : ISendCompletionCallback
{
public void OnSendCompletion(bool success)
{
// NOP
}
}
}
}

@ -46,6 +46,7 @@ namespace Grpc.Microbenchmarks
public void Run()
{
Console.WriteLine("Running threads.");
var gcStats = new GCStats();
var threads = new List<Thread>();
for (int i = 0; i < runners.Count; i++)
{
@ -58,7 +59,7 @@ namespace Grpc.Microbenchmarks
{
thread.Join();
}
Console.WriteLine("All threads finished.");
Console.WriteLine("All threads finished (GC Stats Delta: " + gcStats.GetSnapshot() + ")");
}
}
}

@ -13,7 +13,7 @@
@rem limitations under the License.
@rem Current package versions
set VERSION=1.7.2
set VERSION=1.9.0-dev
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe

@ -39,7 +39,7 @@ dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts
dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
nuget pack Grpc.nuspec -Version "1.7.2" -OutputDirectory ../../artifacts
nuget pack Grpc.Tools.nuspec -Version "1.7.2" -OutputDirectory ../../artifacts
nuget pack Grpc.nuspec -Version "1.9.0-dev" -OutputDirectory ../../artifacts
nuget pack Grpc.Tools.nuspec -Version "1.9.0-dev" -OutputDirectory ../../artifacts
(cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg)

@ -42,7 +42,7 @@ Pod::Spec.new do |s|
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCPlugin'
v = '1.7.2'
v = '1.9.0-dev'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
s.description = <<-DESC

@ -299,7 +299,7 @@ static NSString * const kBearerPrefix = @"Bearer ";
// network queue if the write didn't succeed.
// If the call is a unary call, parameter \a errorHandler will be ignored and
// the error handler of GRPCOpSendClose will be executed in case of error.
- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)())errorHandler {
- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)(void))errorHandler {
__weak GRPCCall *weakSelf = self;
void(^resumingHandler)(void) = ^{
@ -345,7 +345,7 @@ static NSString * const kBearerPrefix = @"Bearer ";
// Only called from the call queue. The error handler will be called from the
// network queue if the requests stream couldn't be closed successfully.
- (void)finishRequestWithErrorHandler:(void (^)())errorHandler {
- (void)finishRequestWithErrorHandler:(void (^)(void))errorHandler {
if (!_unaryCall) {
[_wrappedCall startBatchWithOperations:@[[[GRPCOpSendClose alloc] init]]
errorHandler:errorHandler];
@ -441,7 +441,7 @@ static NSString * const kBearerPrefix = @"Bearer ";
}
_connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
__weak typeof(self) weakSelf = self;
void (^handler)() = ^{
void (^handler)(void) = ^{
typeof(self) strongSelf = weakSelf;
[strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable

@ -57,6 +57,6 @@
* Only one handler is active at a time, so if this method is called again before the previous
* handler has been called, it might never be called at all (or yes, if it has already been queued).
*/
- (void)handleLossWithHandler:(nullable void (^)())lossHandler
wifiStatusChangeHandler:(nullable void (^)())wifiStatusChangeHandler;
- (void)handleLossWithHandler:(nullable void (^)(void))lossHandler
wifiStatusChangeHandler:(nullable void (^)(void))wifiStatusChangeHandler;
@end

@ -136,8 +136,8 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
return returnValue;
}
- (void)handleLossWithHandler:(nullable void (^)())lossHandler
wifiStatusChangeHandler:(nullable void (^)())wifiStatusChangeHandler {
- (void)handleLossWithHandler:(nullable void (^)(void))lossHandler
wifiStatusChangeHandler:(nullable void (^)(void))wifiStatusChangeHandler {
__weak typeof(self) weakSelf = self;
[self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
typeof(self) strongSelf = weakSelf;

@ -93,7 +93,7 @@ static GRPCConnectivityMonitor *connectivityMonitor = nil;
if (!connectivityMonitor) {
connectivityMonitor =
[GRPCConnectivityMonitor monitorWithHost:hostURL.host];
void (^handler)() = ^{
void (^handler)(void) = ^{
[GRPCHost flushChannelCache];
};
[connectivityMonitor handleLossWithHandler:handler

@ -30,24 +30,24 @@
@interface GRPCOpSendMetadata : GRPCOperation
- (instancetype)initWithMetadata:(NSDictionary *)metadata
handler:(void(^)())handler;
handler:(void(^)(void))handler;
- (instancetype)initWithMetadata:(NSDictionary *)metadata
flags:(uint32_t)flags
handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
@end
@interface GRPCOpSendMessage : GRPCOperation
- (instancetype)initWithMessage:(NSData *)message
handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
@end
@interface GRPCOpSendClose : GRPCOperation
- (instancetype)initWithHandler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithHandler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
@end
@ -79,7 +79,7 @@
path:(NSString *)path
timeout:(NSTimeInterval)timeout NS_DESIGNATED_INITIALIZER;
- (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void(^)())errorHandler;
- (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void(^)(void))errorHandler;
- (void)startBatchWithOperations:(NSArray *)ops;

@ -36,12 +36,12 @@
// Most operation subclasses don't set any flags in the grpc_op, and rely on the flag member being
// initialized to zero.
grpc_op _op;
void(^_handler)();
void(^_handler)(void);
}
- (void)finish {
if (_handler) {
void(^handler)() = _handler;
void(^handler)(void) = _handler;
_handler = nil;
handler();
}
@ -55,13 +55,13 @@
}
- (instancetype)initWithMetadata:(NSDictionary *)metadata
handler:(void (^)())handler {
handler:(void (^)(void))handler {
return [self initWithMetadata:metadata flags:0 handler:handler];
}
- (instancetype)initWithMetadata:(NSDictionary *)metadata
flags:(uint32_t)flags
handler:(void (^)())handler {
handler:(void (^)(void))handler {
if (self = [super init]) {
_op.op = GRPC_OP_SEND_INITIAL_METADATA;
_op.data.send_initial_metadata.count = metadata.count;
@ -92,7 +92,7 @@
return [self initWithMessage:nil handler:nil];
}
- (instancetype)initWithMessage:(NSData *)message handler:(void (^)())handler {
- (instancetype)initWithMessage:(NSData *)message handler:(void (^)(void))handler {
if (!message) {
[NSException raise:NSInvalidArgumentException format:@"message cannot be nil"];
}
@ -116,7 +116,7 @@
return [self initWithHandler:nil];
}
- (instancetype)initWithHandler:(void (^)())handler {
- (instancetype)initWithHandler:(void (^)(void))handler {
if (self = [super init]) {
_op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
_handler = handler;
@ -271,7 +271,7 @@
[self startBatchWithOperations:operations errorHandler:nil];
}
- (void)startBatchWithOperations:(NSArray *)operations errorHandler:(void (^)())errorHandler {
- (void)startBatchWithOperations:(NSArray *)operations errorHandler:(void (^)(void))errorHandler {
// Keep logs of op batches when we are running tests. Disabled when in production for improved
// performance.
#ifdef GRPC_TEST_OBJC

@ -23,4 +23,4 @@
// `tools/buildgen/generate_projects.sh`.
#define GRPC_OBJC_VERSION_STRING @"1.7.2"
#define GRPC_OBJC_VERSION_STRING @"1.9.0-dev"

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

Loading…
Cancel
Save