Merge commit '4e57e8be3911e3030e2ccfd6478be75a3c2b0250' into p0-archive-fix

pull/7448/head
Jorge Canizales 8 years ago
commit a9b1c5cbe1
  1. 48
      .travis.yml
  2. 2
      CMakeLists.txt
  3. 52
      INSTALL.md
  4. 38
      Makefile
  5. 2
      Rakefile
  6. 17
      build.yaml
  7. 2
      composer.json
  8. 2
      doc/.gitignore
  9. 1293
      etc/roots.pem
  10. 4
      examples/cpp/helloworld/Makefile
  11. 4
      examples/cpp/route_guide/Makefile
  12. 4
      examples/csharp/helloworld/.nuget/packages.config
  13. 5
      examples/csharp/helloworld/Greeter.sln
  14. 1
      examples/csharp/helloworld/Greeter/packages.config
  15. 4
      examples/csharp/route_guide/.nuget/packages.config
  16. 5
      examples/csharp/route_guide/RouteGuide.sln
  17. 8
      examples/csharp/route_guide/RouteGuide/RouteGuide.csproj
  18. 8
      examples/csharp/route_guide/RouteGuideServer/RouteGuideServer.csproj
  19. 1
      examples/csharp/route_guide/RouteGuideServer/packages.config
  20. 2
      examples/objective-c/auth_sample/AuthTestService.podspec
  21. 32
      examples/objective-c/auth_sample/Misc/GoogleService-Info.plist
  22. 2
      examples/objective-c/helloworld/HelloWorld.podspec
  23. 2
      examples/objective-c/route_guide/RouteGuide.podspec
  24. 2
      examples/php/composer.json
  25. 10
      examples/python/helloworld/greeter_client.py
  26. 8
      examples/python/helloworld/greeter_server.py
  27. 63
      examples/python/helloworld/helloworld_pb2.py
  28. 16
      examples/python/helloworld/run_codegen.py
  29. 1
      examples/python/multiplex/.gitignore
  30. 1
      examples/python/multiplex/README.md
  31. 204
      examples/python/multiplex/helloworld_pb2.py
  32. 139
      examples/python/multiplex/multiplex_client.py
  33. 149
      examples/python/multiplex/multiplex_server.py
  34. 601
      examples/python/multiplex/route_guide_db.json
  35. 516
      examples/python/multiplex/route_guide_pb2.py
  36. 53
      examples/python/multiplex/route_guide_resources.py
  37. 51
      examples/python/multiplex/run_codegen.py
  38. 26
      examples/python/route_guide/route_guide_client.py
  39. 172
      examples/python/route_guide/route_guide_pb2.py
  40. 0
      examples/python/route_guide/route_guide_resources.py
  41. 7
      examples/python/route_guide/route_guide_server.py
  42. 23
      examples/python/route_guide/run_codegen.py
  43. 6
      gRPC-Core.podspec
  44. 4
      gRPC-ProtoRPC.podspec
  45. 4
      gRPC-RxLibrary.podspec
  46. 4
      gRPC.podspec
  47. 27
      include/grpc++/impl/codegen/async_stream.h
  48. 9
      include/grpc++/impl/codegen/async_unary_call.h
  49. 12
      include/grpc++/impl/codegen/call.h
  50. 15
      include/grpc++/impl/codegen/method_handler_impl.h
  51. 9
      include/grpc++/impl/codegen/server_context.h
  52. 15
      include/grpc++/impl/codegen/sync_stream.h
  53. 3
      include/grpc++/server.h
  54. 17
      include/grpc/impl/codegen/compression_types.h
  55. 38
      include/grpc/impl/codegen/grpc_types.h
  56. 2
      include/grpc/impl/codegen/port_platform.h
  57. 10
      include/grpc/module.modulemap
  58. 2
      package.json
  59. 40
      package.xml
  60. 4
      requirements.txt
  61. 2
      setup.cfg
  62. 34
      setup.py
  63. 4
      src/compiler/ruby_generator_helpers-inl.h
  64. 6
      src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
  65. 3
      src/core/ext/transport/chttp2/transport/chttp2_plugin.c
  66. 369
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  67. 65
      src/core/ext/transport/chttp2/transport/internal.h
  68. 11
      src/core/ext/transport/chttp2/transport/parsing.c
  69. 20
      src/core/ext/transport/chttp2/transport/stream_lists.c
  70. 16
      src/core/ext/transport/chttp2/transport/writing.c
  71. 4
      src/core/lib/iomgr/endpoint.c
  72. 4
      src/core/lib/iomgr/endpoint.h
  73. 277
      src/core/lib/iomgr/ev_epoll_linux.c
  74. 3
      src/core/lib/iomgr/ev_poll_and_epoll_posix.c
  75. 3
      src/core/lib/iomgr/ev_poll_posix.c
  76. 4
      src/core/lib/iomgr/ev_posix.c
  77. 4
      src/core/lib/iomgr/ev_posix.h
  78. 10
      src/core/lib/iomgr/exec_ctx.c
  79. 6
      src/core/lib/iomgr/exec_ctx.h
  80. 3
      src/core/lib/iomgr/iomgr.c
  81. 15
      src/core/lib/iomgr/network_status_tracker.c
  82. 4
      src/core/lib/iomgr/network_status_tracker.h
  83. 18
      src/core/lib/iomgr/tcp_posix.c
  84. 3
      src/core/lib/iomgr/tcp_server_posix.c
  85. 13
      src/core/lib/iomgr/tcp_windows.c
  86. 40
      src/core/lib/iomgr/udp_server.c
  87. 39
      src/core/lib/iomgr/workqueue.h
  88. 8
      src/core/lib/iomgr/workqueue_posix.c
  89. 5
      src/core/lib/iomgr/workqueue_posix.h
  90. 22
      src/core/lib/iomgr/workqueue_windows.c
  91. 18
      src/core/lib/security/transport/secure_endpoint.c
  92. 19
      src/core/lib/support/log.c
  93. 76
      src/core/lib/surface/server.c
  94. 2
      src/core/lib/surface/version.c
  95. 3
      src/core/lib/transport/connectivity_state.c
  96. 8
      src/cpp/server/server.cc
  97. 15
      src/cpp/server/server_context.cc
  98. 6
      src/csharp/.nuget/packages.config
  99. 10
      src/csharp/Grpc.Auth/project.json
  100. 2
      src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
  101. Some files were not shown because too many files have changed in this diff Show More

@ -8,33 +8,37 @@ env:
- TEST=objc - TEST=objc
- JOBS=1 - JOBS=1
matrix: matrix:
- SCHEME="RxLibraryUnitTests" WORKSPACE="Tests.xcworkspace" - SCHEME="RxLibraryUnitTests"
TEST_PATH="src/objective-c/tests" BUILD_ONLY="false" WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
INTEROP_SERVER="false" INTEROP_SERVER="false"
- SCHEME="InteropTestsLocalSSL" WORKSPACE="Tests.xcworkspace" - SCHEME="InteropTestsLocalSSL"
TEST_PATH="src/objective-c/tests" BUILD_ONLY="false" INTEROP_SERVER="true" WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
- SCHEME="InteropTestsLocalCleartext" WORKSPACE="Tests.xcworkspace" INTEROP_SERVER="true"
TEST_PATH="src/objective-c/tests" BUILD_ONLY="false" - SCHEME="InteropTestsLocalCleartext"
WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
INTEROP_SERVER="true" INTEROP_SERVER="true"
# TODO(jcanizales): Make tests an app project (instead of library), so the following will work. # TODO(jcanizales): Make tests an app project (instead of library), so the following will work.
# - SCHEME="InteropTestsRemote" WORKSPACE="Tests.xcworkspace" # - SCHEME="InteropTestsRemote"
# TEST_PATH="src/objective-c/tests" BUILD_ONLY="false" # WORKSPACE="Tests.xcworkspace" TEST_PATH="src/objective-c/tests" BUILD_ONLY="false"
# INTEROP_SERVER="true" # INTEROP_SERVER="true"
- SCHEME="HelloWorld" WORKSPACE="HelloWorld.xcworkspace" - SCHEME="HelloWorld"
TEST_PATH="examples/objective-c/helloworld" BUILD_ONLY="true" WORKSPACE="HelloWorld.xcworkspace" TEST_PATH="examples/objective-c/helloworld"
INTEROP_SERVER="false" BUILD_ONLY="true" INTEROP_SERVER="false"
- SCHEME="RouteGuideClient" WORKSPACE="RouteGuideClient.xcworkspace" - SCHEME="RouteGuideClient"
TEST_PATH="examples/objective-c/route_guide" BUILD_ONLY="true" WORKSPACE="RouteGuideClient.xcworkspace" TEST_PATH="examples/objective-c/route_guide"
INTEROP_SERVER="false" BUILD_ONLY="true" INTEROP_SERVER="false"
- SCHEME="AuthSample" WORKSPACE="AuthSample.xcworkspace" - SCHEME="AuthSample"
TEST_PATH="examples/objective-c/auth_sample" BUILD_ONLY="true" WORKSPACE="AuthSample.xcworkspace" TEST_PATH="examples/objective-c/auth_sample"
INTEROP_SERVER="false" BUILD_ONLY="true" INTEROP_SERVER="false"
- SCHEME="Sample" WORKSPACE="Sample.xcworkspace" - SCHEME="Sample"
TEST_PATH="src/objective-c/examples/Sample" BUILD_ONLY="true" WORKSPACE="Sample.xcworkspace" TEST_PATH="src/objective-c/examples/Sample" BUILD_ONLY="true"
INTEROP_SERVER="false"
- SCHEME="SwiftSample" WORKSPACE="SwiftSample.xcworkspace"
TEST_PATH="src/objective-c/examples/SwiftSample" BUILD_ONLY="true"
INTEROP_SERVER="false" INTEROP_SERVER="false"
- SCHEME="Sample"
WORKSPACE="Sample.xcworkspace" TEST_PATH="src/objective-c/examples/Sample" BUILD_ONLY="true"
INTEROP_SERVER="false" FRAMEWORKS="YES"
- SCHEME="SwiftSample"
WORKSPACE="SwiftSample.xcworkspace" TEST_PATH="src/objective-c/examples/SwiftSample"
BUILD_ONLY="true" INTEROP_SERVER="false"
before_install: before_install:
# Until Travis upgrades from Cocoapods 0.39, we need to do it here. # Until Travis upgrades from Cocoapods 0.39, we need to do it here.
- pod --version - pod --version

@ -42,7 +42,7 @@
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
set(PACKAGE_NAME "grpc") set(PACKAGE_NAME "grpc")
set(PACKAGE_VERSION "1.0.0-pre1") set(PACKAGE_VERSION "1.0.0-pre2")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")

@ -55,3 +55,55 @@ gRPC C Core library.
$ make $ make
$ [sudo] make install $ [sudo] make install
``` ```
##Windows
There are several ways to build under Windows, of varying complexity depending
on experience with the tools involved.
<!--
###Visual Studio
Versions 2013 and 2015 are both supported. You can use [their respective
community
editions](https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx).
Building the C Core:
- Open [grpc.sln](https://github.com/grpc/grpc/blob/master/vsprojects/grpc.sln).
- Select your build target.
- Build the `grpc` project.
Building the C++ runtime:
- You need [CMake](https://cmake.org/) on your path to build protobuf (see below
for building using solely CMake).
- Run `vsprojects/build_protos.bat` (needs `cmake.exe` in your path).
- Open [buildtests_cxx.sln]()
- Select your build target.
- build the `grpc++` project.
-->
###msys2
This approach requires having [msys2](https://msys2.github.io/) installed.
- The Makefile (and source code) should support msys2's mingw32 and mingw64
compilers. Building with msys2's native compiler is also possible, but
difficult.
- The Makefile is expecting the Windows versions of OpenSSL (see
https://slproweb.com/products/Win32OpenSSL.html). It's also possible to build
the Windows version of OpenSSL from scratch. The output should be `libeay32`
and `ssleay32`.
- If you are not installing the above files under msys2's path, you may specify
it, for instance, in the following way:
```CPPFLAGS=”-I/c/OpenSSL-Win32/include” LDFLAGS=”-L/c/OpenSSL-Win32/lib” make static_c```
- [protobuf3](https://github.com/google/protobuf/blob/master/src/README.md#c-installation---windows)
must be installed on the msys2 path.
###Cmake (experimental)
- Install [CMake](https://cmake.org/download/).
- Run it over [grpc's
CMakeLists.txt](https://github.com/grpc/grpc/blob/master/CMakeLists.txt) to
generate "projects" for your compiler.
- Build with your compiler of choice. The generated build files should have the
protobuf3 dependency baked in.

@ -415,7 +415,7 @@ E = @echo
Q = @ Q = @
endif endif
VERSION = 1.0.0-pre1 VERSION = 1.0.0-pre2
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@ -991,7 +991,6 @@ transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test
udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test
uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test uri_fuzzer_test: $(BINDIR)/$(CONFIG)/uri_fuzzer_test
uri_parser_test: $(BINDIR)/$(CONFIG)/uri_parser_test uri_parser_test: $(BINDIR)/$(CONFIG)/uri_parser_test
workqueue_test: $(BINDIR)/$(CONFIG)/workqueue_test
alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test
async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test auth_property_iterator_test: $(BINDIR)/$(CONFIG)/auth_property_iterator_test
@ -1295,7 +1294,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/transport_security_test \ $(BINDIR)/$(CONFIG)/transport_security_test \
$(BINDIR)/$(CONFIG)/udp_server_test \ $(BINDIR)/$(CONFIG)/udp_server_test \
$(BINDIR)/$(CONFIG)/uri_parser_test \ $(BINDIR)/$(CONFIG)/uri_parser_test \
$(BINDIR)/$(CONFIG)/workqueue_test \
$(BINDIR)/$(CONFIG)/public_headers_must_be_c89 \ $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 \
$(BINDIR)/$(CONFIG)/badreq_bad_client_test \ $(BINDIR)/$(CONFIG)/badreq_bad_client_test \
$(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \ $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \
@ -1674,8 +1672,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/udp_server_test || ( echo test udp_server_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/udp_server_test || ( echo test udp_server_test failed ; exit 1 )
$(E) "[RUN] Testing uri_parser_test" $(E) "[RUN] Testing uri_parser_test"
$(Q) $(BINDIR)/$(CONFIG)/uri_parser_test || ( echo test uri_parser_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/uri_parser_test || ( echo test uri_parser_test failed ; exit 1 )
$(E) "[RUN] Testing workqueue_test"
$(Q) $(BINDIR)/$(CONFIG)/workqueue_test || ( echo test workqueue_test failed ; exit 1 )
$(E) "[RUN] Testing public_headers_must_be_c89" $(E) "[RUN] Testing public_headers_must_be_c89"
$(Q) $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 || ( echo test public_headers_must_be_c89 failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/public_headers_must_be_c89 || ( echo test public_headers_must_be_c89 failed ; exit 1 )
$(E) "[RUN] Testing badreq_bad_client_test" $(E) "[RUN] Testing badreq_bad_client_test"
@ -10175,38 +10171,6 @@ endif
endif endif
WORKQUEUE_TEST_SRC = \
test/core/iomgr/workqueue_test.c \
WORKQUEUE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(WORKQUEUE_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/workqueue_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/workqueue_test: $(WORKQUEUE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(WORKQUEUE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/workqueue_test
endif
$(OBJDIR)/$(CONFIG)/test/core/iomgr/workqueue_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_workqueue_test: $(WORKQUEUE_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(WORKQUEUE_TEST_OBJS:.o=.dep)
endif
endif
ALARM_CPP_TEST_SRC = \ ALARM_CPP_TEST_SRC = \
test/cpp/common/alarm_cpp_test.cc \ test/cpp/common/alarm_cpp_test.cc \

@ -83,7 +83,7 @@ task 'dlls' do
env += 'EMBED_ZLIB=true ' env += 'EMBED_ZLIB=true '
env += 'BUILDDIR=/tmp ' env += 'BUILDDIR=/tmp '
env += "V=#{verbose} " env += "V=#{verbose} "
out = '/tmp/libs/opt/grpc-0.dll' out = '/tmp/libs/opt/grpc-1.dll'
w64 = { cross: 'x86_64-w64-mingw32', out: 'grpc_c.64.ruby' } w64 = { cross: 'x86_64-w64-mingw32', out: 'grpc_c.64.ruby' }
w32 = { cross: 'i686-w64-mingw32', out: 'grpc_c.32.ruby' } w32 = { cross: 'i686-w64-mingw32', out: 'grpc_c.32.ruby' }

@ -7,7 +7,7 @@ settings:
'#3': Use "-preN" suffixes to identify pre-release versions '#3': Use "-preN" suffixes to identify pre-release versions
'#4': Per-language overrides are possible with (eg) ruby_version tag here '#4': Per-language overrides are possible with (eg) ruby_version tag here
'#5': See the expand_version.py for all the quirks here '#5': See the expand_version.py for all the quirks here
version: 1.0.0-pre1 version: 1.0.0-pre2
filegroups: filegroups:
- name: census - name: census
public_headers: public_headers:
@ -2430,20 +2430,6 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: workqueue_test
build: test
language: c
src:
- test/core/iomgr/workqueue_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
platforms:
- mac
- linux
- posix
- name: alarm_cpp_test - name: alarm_cpp_test
gtest: true gtest: true
build: test build: test
@ -3367,6 +3353,7 @@ php_config_m4:
- src/php/ext/grpc/channel.h - src/php/ext/grpc/channel.h
- src/php/ext/grpc/channel_credentials.h - src/php/ext/grpc/channel_credentials.h
- src/php/ext/grpc/completion_queue.h - src/php/ext/grpc/completion_queue.h
- src/php/ext/grpc/php7_wrapper.h
- src/php/ext/grpc/php_grpc.h - src/php/ext/grpc/php_grpc.h
- src/php/ext/grpc/server.h - src/php/ext/grpc/server.h
- src/php/ext/grpc/server_credentials.h - src/php/ext/grpc/server_credentials.h

@ -7,7 +7,7 @@
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"require": { "require": {
"php": ">=5.5.0", "php": ">=5.5.0",
"stanley-cheung/protobuf-php": "dev-master" "stanley-cheung/protobuf-php": "v0.6"
}, },
"require-dev": { "require-dev": {
"google/auth": "v0.9" "google/auth": "v0.9"

2
doc/.gitignore vendored

@ -0,0 +1,2 @@
build/
src/

File diff suppressed because it is too large Load Diff

@ -32,7 +32,9 @@
CXX = g++ CXX = g++
CPPFLAGS += -I/usr/local/include -pthread CPPFLAGS += -I/usr/local/include -pthread
CXXFLAGS += -std=c++11 CXXFLAGS += -std=c++11
LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++ grpc` -lprotobuf -lpthread -ldl LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++ grpc` \
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed \
-lprotobuf -lpthread -ldl
PROTOC = protoc PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`

@ -32,7 +32,9 @@
CXX = g++ CXX = g++
CPPFLAGS += -I/usr/local/include -pthread CPPFLAGS += -I/usr/local/include -pthread
CXXFLAGS += -std=c++11 CXXFLAGS += -std=c++11
LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` -lprotobuf -lpthread -ldl LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` \
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed \
-lprotobuf -lpthread -ldl
PROTOC = protoc PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Grpc.Tools" version="0.15.0" />
</packages>

@ -9,11 +9,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreeterServer", "GreeterSer
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreeterClient", "GreeterClient\GreeterClient.csproj", "{ACCF4597-3748-4117-8633-1CB767F8CCC3}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreeterClient", "GreeterClient\GreeterClient.csproj", "{ACCF4597-3748-4117-8633-1CB767F8CCC3}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{FF1EBE95-F20D-4C27-8A61-D0125F3C8152}"
ProjectSection(SolutionItems) = preProject
.nuget\packages.config = .nuget\packages.config
EndProjectSection
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU

@ -4,4 +4,5 @@
<package id="Grpc" version="0.15.0" targetFramework="net45" /> <package id="Grpc" version="0.15.0" targetFramework="net45" />
<package id="Grpc.Core" version="0.15.0" targetFramework="net45" /> <package id="Grpc.Core" version="0.15.0" targetFramework="net45" />
<package id="Ix-Async" version="1.2.5" targetFramework="net45" /> <package id="Ix-Async" version="1.2.5" targetFramework="net45" />
<package id="Grpc.Tools" version="0.15.0" targetFramework="net45" />
</packages> </packages>

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Grpc.Tools" version="0.15.0" />
</packages>

@ -9,11 +9,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RouteGuideClient", "RouteGu
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RouteGuideServer", "RouteGuideServer\RouteGuideServer.csproj", "{4B7C7794-BE24-4477-ACE7-18259EB73D27}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RouteGuideServer", "RouteGuideServer\RouteGuideServer.csproj", "{4B7C7794-BE24-4477-ACE7-18259EB73D27}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2F6B184B-A576-4F21-AF2E-27E73D1FC96E}"
ProjectSection(SolutionItems) = preProject
.nuget\packages.config = .nuget\packages.config
EndProjectSection
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU

@ -45,15 +45,15 @@
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

@ -47,15 +47,15 @@
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Ix-Async.1.2.5\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />

@ -5,4 +5,5 @@
<package id="Grpc.Core" version="0.15.0" targetFramework="net45" /> <package id="Grpc.Core" version="0.15.0" targetFramework="net45" />
<package id="Ix-Async" version="1.2.5" targetFramework="net45" /> <package id="Ix-Async" version="1.2.5" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" /> <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
<package id="Grpc.Tools" version="0.15.0" targetFramework="net45" />
</packages> </packages>

@ -14,7 +14,7 @@ Pod::Spec.new do |s|
src = "../../protos" src = "../../protos"
# Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
s.dependency "!ProtoCompiler-gRPCPlugin", "~> 0.14" s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0.0-pre1"
# Pods directory corresponding to this app's Podfile, relative to the location of this podspec. # Pods directory corresponding to this app's Podfile, relative to the location of this podspec.
pods_root = 'Pods' pods_root = 'Pods'

@ -2,9 +2,39 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>AD_UNIT_ID_FOR_BANNER_TEST</key>
<string>redacted</string>
<key>AD_UNIT_ID_FOR_INTERSTITIAL_TEST</key>
<string>redacted</string>
<key>CLIENT_ID</key> <key>CLIENT_ID</key>
<string>15087385131-lh9bpkiai9nls53uadju0if6k7un3uih.apps.googleusercontent.com</string> <string>15087385131-lh9bpkiai9nls53uadju0if6k7un3uih.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key> <key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih</string> <string>com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih</string>
<key>API_KEY</key>
<string>redacted</string>
<key>GCM_SENDER_ID</key>
<string>redacted</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>io.grpc.AuthSample</string>
<key>PROJECT_ID</key>
<string>grpc-authsample</string>
<key>STORAGE_BUCKET</key>
<string>grpc-authsample.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false/>
<key>IS_ANALYTICS_ENABLED</key>
<false/>
<key>IS_APPINVITE_ENABLED</key>
<false/>
<key>IS_GCM_ENABLED</key>
<false/>
<key>IS_SIGNIN_ENABLED</key>
<true/>
<key>GOOGLE_APP_ID</key>
<string>1:15087385131:ios:d547168abe3c362f</string>
<key>DATABASE_URL</key>
<string>https://grpc-authsample.firebaseio.com</string>
</dict> </dict>
</plist> </plist>

@ -14,7 +14,7 @@ Pod::Spec.new do |s|
src = "../../protos" src = "../../protos"
# Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
s.dependency "!ProtoCompiler-gRPCPlugin", "~> 0.14" s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0.0-pre1"
# Pods directory corresponding to this app's Podfile, relative to the location of this podspec. # Pods directory corresponding to this app's Podfile, relative to the location of this podspec.
pods_root = 'Pods' pods_root = 'Pods'

@ -14,7 +14,7 @@ Pod::Spec.new do |s|
src = "../../protos" src = "../../protos"
# Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
s.dependency "!ProtoCompiler-gRPCPlugin", "~> 0.14" s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0.0-pre1"
# Pods directory corresponding to this app's Podfile, relative to the location of this podspec. # Pods directory corresponding to this app's Podfile, relative to the location of this podspec.
pods_root = 'Pods' pods_root = 'Pods'

@ -3,6 +3,6 @@
"description": "gRPC example for PHP", "description": "gRPC example for PHP",
"minimum-stability": "dev", "minimum-stability": "dev",
"require": { "require": {
"grpc/grpc": "v0.15.0" "grpc/grpc": "v0.15.2"
} }
} }

@ -31,17 +31,15 @@
from __future__ import print_function from __future__ import print_function
from grpc.beta import implementations import grpc
import helloworld_pb2 import helloworld_pb2
_TIMEOUT_SECONDS = 10
def run(): def run():
channel = implementations.insecure_channel('localhost', 50051) channel = grpc.insecure_channel('localhost:50051')
stub = helloworld_pb2.beta_create_Greeter_stub(channel) stub = helloworld_pb2.GreeterStub(channel)
response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS) response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
print("Greeter client received: " + response.message) print("Greeter client received: " + response.message)

@ -29,21 +29,25 @@
"""The Python implementation of the GRPC helloworld.Greeter server.""" """The Python implementation of the GRPC helloworld.Greeter server."""
from concurrent import futures
import time import time
import grpc
import helloworld_pb2 import helloworld_pb2
_ONE_DAY_IN_SECONDS = 60 * 60 * 24 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
class Greeter(helloworld_pb2.BetaGreeterServicer): class Greeter(helloworld_pb2.GreeterServicer):
def SayHello(self, request, context): def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name) return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
def serve(): def serve():
server = helloworld_pb2.beta_create_Greeter_server(Greeter()) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051') server.add_insecure_port('[::]:50051')
server.start() server.start()
try: try:

@ -107,13 +107,55 @@ _sym_db.RegisterMessage(HelloReply)
DESCRIPTOR.has_options = True DESCRIPTOR.has_options = True
DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW')) DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'))
import abc import grpc
import six
from grpc.beta import implementations as beta_implementations from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces from grpc.beta import interfaces as beta_interfaces
from grpc.framework.common import cardinality from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities from grpc.framework.interfaces.face import utilities as face_utilities
class GreeterStub(object):
"""The greeting service definition.
"""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.SayHello = channel.unary_unary(
'/helloworld.Greeter/SayHello',
request_serializer=HelloRequest.SerializeToString,
response_deserializer=HelloReply.FromString,
)
class GreeterServicer(object):
"""The greeting service definition.
"""
def SayHello(self, request, context):
"""Sends a greeting
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_GreeterServicer_to_server(servicer, server):
rpc_method_handlers = {
'SayHello': grpc.unary_unary_rpc_method_handler(
servicer.SayHello,
request_deserializer=HelloRequest.FromString,
response_serializer=HelloReply.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'helloworld.Greeter', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaGreeterServicer(object): class BetaGreeterServicer(object):
"""The greeting service definition. """The greeting service definition.
""" """
@ -122,23 +164,23 @@ class BetaGreeterServicer(object):
""" """
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaGreeterStub(object): class BetaGreeterStub(object):
"""The greeting service definition. """The greeting service definition.
""" """
def SayHello(self, request, timeout): def SayHello(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
"""Sends a greeting """Sends a greeting
""" """
raise NotImplementedError() raise NotImplementedError()
SayHello.future = None SayHello.future = None
def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
import helloworld_pb2
import helloworld_pb2
request_deserializers = { request_deserializers = {
('helloworld.Greeter', 'SayHello'): helloworld_pb2.HelloRequest.FromString, ('helloworld.Greeter', 'SayHello'): HelloRequest.FromString,
} }
response_serializers = { response_serializers = {
('helloworld.Greeter', 'SayHello'): helloworld_pb2.HelloReply.SerializeToString, ('helloworld.Greeter', 'SayHello'): HelloReply.SerializeToString,
} }
method_implementations = { method_implementations = {
('helloworld.Greeter', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello), ('helloworld.Greeter', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello),
@ -146,14 +188,13 @@ def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_time
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout) server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options) return beta_implementations.server(method_implementations, options=server_options)
def beta_create_Greeter_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None): def beta_create_Greeter_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
import helloworld_pb2
import helloworld_pb2
request_serializers = { request_serializers = {
('helloworld.Greeter', 'SayHello'): helloworld_pb2.HelloRequest.SerializeToString, ('helloworld.Greeter', 'SayHello'): HelloRequest.SerializeToString,
} }
response_deserializers = { response_deserializers = {
('helloworld.Greeter', 'SayHello'): helloworld_pb2.HelloReply.FromString, ('helloworld.Greeter', 'SayHello'): HelloReply.FromString,
} }
cardinalities = { cardinalities = {
'SayHello': cardinality.Cardinality.UNARY_UNARY, 'SayHello': cardinality.Cardinality.UNARY_UNARY,

@ -1,4 +1,3 @@
#!/bin/bash
# Copyright 2015, Google Inc. # Copyright 2015, Google Inc.
# All rights reserved. # All rights reserved.
# #
@ -28,5 +27,16 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Runs the protoc with gRPC plugin to generate protocol messages and gRPC stubs. """Runs protoc with the gRPC plugin to generate messages and gRPC stubs."""
python -m grpc.tools.protoc -I../../protos --python_out=. --grpc_python_out=. ../../protos/route_guide.proto
from grpc.tools import protoc
protoc.main(
(
'',
'-I../../protos',
'--python_out=.',
'--grpc_python_out=.',
'../../protos/helloworld.proto',
)
)

@ -0,0 +1 @@
An example showing two stubs sharing a channel and two servicers sharing a server.

@ -0,0 +1,204 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: helloworld.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='helloworld.proto',
package='helloworld',
syntax='proto3',
serialized_pb=_b('\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_HELLOREQUEST = _descriptor.Descriptor(
name='HelloRequest',
full_name='helloworld.HelloRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='helloworld.HelloRequest.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=32,
serialized_end=60,
)
_HELLOREPLY = _descriptor.Descriptor(
name='HelloReply',
full_name='helloworld.HelloReply',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='message', full_name='helloworld.HelloReply.message', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=62,
serialized_end=91,
)
DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST
DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY
HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict(
DESCRIPTOR = _HELLOREQUEST,
__module__ = 'helloworld_pb2'
# @@protoc_insertion_point(class_scope:helloworld.HelloRequest)
))
_sym_db.RegisterMessage(HelloRequest)
HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict(
DESCRIPTOR = _HELLOREPLY,
__module__ = 'helloworld_pb2'
# @@protoc_insertion_point(class_scope:helloworld.HelloReply)
))
_sym_db.RegisterMessage(HelloReply)
DESCRIPTOR.has_options = True
DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'))
import grpc
from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
class GreeterStub(object):
"""The greeting service definition.
"""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.SayHello = channel.unary_unary(
'/helloworld.Greeter/SayHello',
request_serializer=HelloRequest.SerializeToString,
response_deserializer=HelloReply.FromString,
)
class GreeterServicer(object):
"""The greeting service definition.
"""
def SayHello(self, request, context):
"""Sends a greeting
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_GreeterServicer_to_server(servicer, server):
rpc_method_handlers = {
'SayHello': grpc.unary_unary_rpc_method_handler(
servicer.SayHello,
request_deserializer=HelloRequest.FromString,
response_serializer=HelloReply.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'helloworld.Greeter', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaGreeterServicer(object):
"""The greeting service definition.
"""
def SayHello(self, request, context):
"""Sends a greeting
"""
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaGreeterStub(object):
"""The greeting service definition.
"""
def SayHello(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
"""Sends a greeting
"""
raise NotImplementedError()
SayHello.future = None
def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
request_deserializers = {
('helloworld.Greeter', 'SayHello'): HelloRequest.FromString,
}
response_serializers = {
('helloworld.Greeter', 'SayHello'): HelloReply.SerializeToString,
}
method_implementations = {
('helloworld.Greeter', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello),
}
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options)
def beta_create_Greeter_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
request_serializers = {
('helloworld.Greeter', 'SayHello'): HelloRequest.SerializeToString,
}
response_deserializers = {
('helloworld.Greeter', 'SayHello'): HelloReply.FromString,
}
cardinalities = {
'SayHello': cardinality.Cardinality.UNARY_UNARY,
}
stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
return beta_implementations.dynamic_stub(channel, 'helloworld.Greeter', cardinalities, options=stub_options)
# @@protoc_insertion_point(module_scope)

@ -0,0 +1,139 @@
# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""A client that makes both Greeter and RouteGuide RPCs."""
from __future__ import print_function
import random
import time
import grpc
import helloworld_pb2
import route_guide_pb2
import route_guide_resources
def make_route_note(message, latitude, longitude):
return route_guide_pb2.RouteNote(
message=message,
location=route_guide_pb2.Point(latitude=latitude, longitude=longitude))
def guide_get_one_feature(route_guide_stub, point):
feature = route_guide_stub.GetFeature(point)
if not feature.location:
print("Server returned incomplete feature")
return
if feature.name:
print("Feature called %s at %s" % (feature.name, feature.location))
else:
print("Found no feature at %s" % feature.location)
def guide_get_feature(route_guide_stub):
guide_get_one_feature(
route_guide_stub,
route_guide_pb2.Point(latitude=409146138, longitude=-746188906))
guide_get_one_feature(
route_guide_stub, route_guide_pb2.Point(latitude=0, longitude=0))
def guide_list_features(route_guide_stub):
rectangle = route_guide_pb2.Rectangle(
lo=route_guide_pb2.Point(latitude=400000000, longitude=-750000000),
hi=route_guide_pb2.Point(latitude=420000000, longitude=-730000000))
print("Looking for features between 40, -75 and 42, -73")
features = route_guide_stub.ListFeatures(rectangle)
for feature in features:
print("Feature called %s at %s" % (feature.name, feature.location))
def generate_route(feature_list):
for _ in range(0, 10):
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(route_guide_stub):
feature_list = route_guide_resources.read_route_guide_database()
route_iterator = generate_route(feature_list)
route_summary = route_guide_stub.RecordRoute(route_iterator)
print("Finished trip with %s points " % route_summary.point_count)
print("Passed %s features " % route_summary.feature_count)
print("Travelled %s meters " % route_summary.distance)
print("It took %s seconds " % route_summary.elapsed_time)
def generate_messages():
messages = [
make_route_note("First message", 0, 0),
make_route_note("Second message", 0, 1),
make_route_note("Third message", 1, 0),
make_route_note("Fourth message", 0, 0),
make_route_note("Fifth message", 1, 0),
]
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(route_guide_stub):
responses = route_guide_stub.RouteChat(generate_messages())
for response in responses:
print("Received message %s at %s" % (response.message, response.location))
def run():
channel = grpc.insecure_channel('localhost:50051')
greeter_stub = helloworld_pb2.GreeterStub(channel)
route_guide_stub = route_guide_pb2.RouteGuideStub(channel)
greeter_response = greeter_stub.SayHello(
helloworld_pb2.HelloRequest(name='you'))
print("Greeter client received: " + greeter_response.message)
print("-------------- GetFeature --------------")
guide_get_feature(route_guide_stub)
print("-------------- ListFeatures --------------")
guide_list_features(route_guide_stub)
print("-------------- RecordRoute --------------")
guide_record_route(route_guide_stub)
print("-------------- RouteChat --------------")
guide_route_chat(route_guide_stub)
if __name__ == '__main__':
run()

@ -0,0 +1,149 @@
# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""A gRPC server servicing both Greeter and RouteGuide RPCs."""
from concurrent import futures
import time
import math
import grpc
import helloworld_pb2
import route_guide_pb2
import route_guide_resources
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
def _get_feature(feature_db, point):
"""Returns Feature at given location or None."""
for feature in feature_db:
if feature.location == point:
return feature
return None
def _get_distance(start, end):
"""Distance between two points."""
coord_factor = 10000000.0
lat_1 = start.latitude / coord_factor
lat_2 = end.latitude / coord_factor
lon_1 = start.longitude / coord_factor
lon_2 = end.longitude / coord_factor
lat_rad_1 = math.radians(lat_1)
lat_rad_2 = math.radians(lat_2)
delta_lat_rad = math.radians(lat_2 - lat_1)
delta_lon_rad = math.radians(lon_2 - lon_1)
a = (pow(math.sin(delta_lat_rad / 2), 2) +
(math.cos(lat_rad_1) * math.cos(lat_rad_2) *
pow(math.sin(delta_lon_rad / 2), 2)))
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
R = 6371000; # metres
return R * c;
class _GreeterServicer(helloworld_pb2.GreeterServicer):
def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message='Hello, {}!'.format(request.name))
class _RouteGuideServicer(route_guide_pb2.RouteGuideServicer):
"""Provides methods that implement functionality of route guide server."""
def __init__(self):
self.db = route_guide_resources.read_route_guide_database()
def GetFeature(self, request, context):
feature = _get_feature(self.db, request)
if feature is None:
return route_guide_pb2.Feature(name="", location=request)
else:
return feature
def ListFeatures(self, request, context):
left = min(request.lo.longitude, request.hi.longitude)
right = max(request.lo.longitude, request.hi.longitude)
top = max(request.lo.latitude, request.hi.latitude)
bottom = min(request.lo.latitude, request.hi.latitude)
for feature in self.db:
if (feature.location.longitude >= left and
feature.location.longitude <= right and
feature.location.latitude >= bottom and
feature.location.latitude <= top):
yield feature
def RecordRoute(self, request_iterator, context):
point_count = 0
feature_count = 0
distance = 0.0
prev_point = None
start_time = time.time()
for point in request_iterator:
point_count += 1
if _get_feature(self.db, point):
feature_count += 1
if prev_point:
distance += _get_distance(prev_point, point)
prev_point = point
elapsed_time = time.time() - start_time
return route_guide_pb2.RouteSummary(point_count=point_count,
feature_count=feature_count,
distance=int(distance),
elapsed_time=int(elapsed_time))
def RouteChat(self, request_iterator, context):
prev_notes = []
for new_note in request_iterator:
for prev_note in prev_notes:
if prev_note.location == new_note.location:
yield prev_note
prev_notes.append(new_note)
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2.add_GreeterServicer_to_server(_GreeterServicer(), server)
route_guide_pb2.add_RouteGuideServicer_to_server(
_RouteGuideServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
serve()

@ -0,0 +1,601 @@
[{
"location": {
"latitude": 407838351,
"longitude": -746143763
},
"name": "Patriots Path, Mendham, NJ 07945, USA"
}, {
"location": {
"latitude": 408122808,
"longitude": -743999179
},
"name": "101 New Jersey 10, Whippany, NJ 07981, USA"
}, {
"location": {
"latitude": 413628156,
"longitude": -749015468
},
"name": "U.S. 6, Shohola, PA 18458, USA"
}, {
"location": {
"latitude": 419999544,
"longitude": -740371136
},
"name": "5 Conners Road, Kingston, NY 12401, USA"
}, {
"location": {
"latitude": 414008389,
"longitude": -743951297
},
"name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
}, {
"location": {
"latitude": 419611318,
"longitude": -746524769
},
"name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
}, {
"location": {
"latitude": 406109563,
"longitude": -742186778
},
"name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
}, {
"location": {
"latitude": 416802456,
"longitude": -742370183
},
"name": "352 South Mountain Road, Wallkill, NY 12589, USA"
}, {
"location": {
"latitude": 412950425,
"longitude": -741077389
},
"name": "Bailey Turn Road, Harriman, NY 10926, USA"
}, {
"location": {
"latitude": 412144655,
"longitude": -743949739
},
"name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
}, {
"location": {
"latitude": 415736605,
"longitude": -742847522
},
"name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA"
}, {
"location": {
"latitude": 413843930,
"longitude": -740501726
},
"name": "162 Merrill Road, Highland Mills, NY 10930, USA"
}, {
"location": {
"latitude": 410873075,
"longitude": -744459023
},
"name": "Clinton Road, West Milford, NJ 07480, USA"
}, {
"location": {
"latitude": 412346009,
"longitude": -744026814
},
"name": "16 Old Brook Lane, Warwick, NY 10990, USA"
}, {
"location": {
"latitude": 402948455,
"longitude": -747903913
},
"name": "3 Drake Lane, Pennington, NJ 08534, USA"
}, {
"location": {
"latitude": 406337092,
"longitude": -740122226
},
"name": "6324 8th Avenue, Brooklyn, NY 11220, USA"
}, {
"location": {
"latitude": 406421967,
"longitude": -747727624
},
"name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA"
}, {
"location": {
"latitude": 416318082,
"longitude": -749677716
},
"name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA"
}, {
"location": {
"latitude": 415301720,
"longitude": -748416257
},
"name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA"
}, {
"location": {
"latitude": 402647019,
"longitude": -747071791
},
"name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA"
}, {
"location": {
"latitude": 412567807,
"longitude": -741058078
},
"name": "New York State Reference Route 987E, Southfields, NY 10975, USA"
}, {
"location": {
"latitude": 416855156,
"longitude": -744420597
},
"name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA"
}, {
"location": {
"latitude": 404663628,
"longitude": -744820157
},
"name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA"
}, {
"location": {
"latitude": 407113723,
"longitude": -749746483
},
"name": ""
}, {
"location": {
"latitude": 402133926,
"longitude": -743613249
},
"name": ""
}, {
"location": {
"latitude": 400273442,
"longitude": -741220915
},
"name": ""
}, {
"location": {
"latitude": 411236786,
"longitude": -744070769
},
"name": ""
}, {
"location": {
"latitude": 411633782,
"longitude": -746784970
},
"name": "211-225 Plains Road, Augusta, NJ 07822, USA"
}, {
"location": {
"latitude": 415830701,
"longitude": -742952812
},
"name": ""
}, {
"location": {
"latitude": 413447164,
"longitude": -748712898
},
"name": "165 Pedersen Ridge Road, Milford, PA 18337, USA"
}, {
"location": {
"latitude": 405047245,
"longitude": -749800722
},
"name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA"
}, {
"location": {
"latitude": 418858923,
"longitude": -746156790
},
"name": ""
}, {
"location": {
"latitude": 417951888,
"longitude": -748484944
},
"name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA"
}, {
"location": {
"latitude": 407033786,
"longitude": -743977337
},
"name": "26 East 3rd Street, New Providence, NJ 07974, USA"
}, {
"location": {
"latitude": 417548014,
"longitude": -740075041
},
"name": ""
}, {
"location": {
"latitude": 410395868,
"longitude": -744972325
},
"name": ""
}, {
"location": {
"latitude": 404615353,
"longitude": -745129803
},
"name": ""
}, {
"location": {
"latitude": 406589790,
"longitude": -743560121
},
"name": "611 Lawrence Avenue, Westfield, NJ 07090, USA"
}, {
"location": {
"latitude": 414653148,
"longitude": -740477477
},
"name": "18 Lannis Avenue, New Windsor, NY 12553, USA"
}, {
"location": {
"latitude": 405957808,
"longitude": -743255336
},
"name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA"
}, {
"location": {
"latitude": 411733589,
"longitude": -741648093
},
"name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA"
}, {
"location": {
"latitude": 412676291,
"longitude": -742606606
},
"name": "1270 Lakes Road, Monroe, NY 10950, USA"
}, {
"location": {
"latitude": 409224445,
"longitude": -748286738
},
"name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA"
}, {
"location": {
"latitude": 406523420,
"longitude": -742135517
},
"name": "652 Garden Street, Elizabeth, NJ 07202, USA"
}, {
"location": {
"latitude": 401827388,
"longitude": -740294537
},
"name": "349 Sea Spray Court, Neptune City, NJ 07753, USA"
}, {
"location": {
"latitude": 410564152,
"longitude": -743685054
},
"name": "13-17 Stanley Street, West Milford, NJ 07480, USA"
}, {
"location": {
"latitude": 408472324,
"longitude": -740726046
},
"name": "47 Industrial Avenue, Teterboro, NJ 07608, USA"
}, {
"location": {
"latitude": 412452168,
"longitude": -740214052
},
"name": "5 White Oak Lane, Stony Point, NY 10980, USA"
}, {
"location": {
"latitude": 409146138,
"longitude": -746188906
},
"name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA"
}, {
"location": {
"latitude": 404701380,
"longitude": -744781745
},
"name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA"
}, {
"location": {
"latitude": 409642566,
"longitude": -746017679
},
"name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA"
}, {
"location": {
"latitude": 408031728,
"longitude": -748645385
},
"name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA"
}, {
"location": {
"latitude": 413700272,
"longitude": -742135189
},
"name": "367 Prospect Road, Chester, NY 10918, USA"
}, {
"location": {
"latitude": 404310607,
"longitude": -740282632
},
"name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA"
}, {
"location": {
"latitude": 409319800,
"longitude": -746201391
},
"name": "11 Ward Street, Mount Arlington, NJ 07856, USA"
}, {
"location": {
"latitude": 406685311,
"longitude": -742108603
},
"name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA"
}, {
"location": {
"latitude": 419018117,
"longitude": -749142781
},
"name": "43 Dreher Road, Roscoe, NY 12776, USA"
}, {
"location": {
"latitude": 412856162,
"longitude": -745148837
},
"name": "Swan Street, Pine Island, NY 10969, USA"
}, {
"location": {
"latitude": 416560744,
"longitude": -746721964
},
"name": "66 Pleasantview Avenue, Monticello, NY 12701, USA"
}, {
"location": {
"latitude": 405314270,
"longitude": -749836354
},
"name": ""
}, {
"location": {
"latitude": 414219548,
"longitude": -743327440
},
"name": ""
}, {
"location": {
"latitude": 415534177,
"longitude": -742900616
},
"name": "565 Winding Hills Road, Montgomery, NY 12549, USA"
}, {
"location": {
"latitude": 406898530,
"longitude": -749127080
},
"name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA"
}, {
"location": {
"latitude": 407586880,
"longitude": -741670168
},
"name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA"
}, {
"location": {
"latitude": 400106455,
"longitude": -742870190
},
"name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA"
}, {
"location": {
"latitude": 400066188,
"longitude": -746793294
},
"name": ""
}, {
"location": {
"latitude": 418803880,
"longitude": -744102673
},
"name": "40 Mountain Road, Napanoch, NY 12458, USA"
}, {
"location": {
"latitude": 414204288,
"longitude": -747895140
},
"name": ""
}, {
"location": {
"latitude": 414777405,
"longitude": -740615601
},
"name": ""
}, {
"location": {
"latitude": 415464475,
"longitude": -747175374
},
"name": "48 North Road, Forestburgh, NY 12777, USA"
}, {
"location": {
"latitude": 404062378,
"longitude": -746376177
},
"name": ""
}, {
"location": {
"latitude": 405688272,
"longitude": -749285130
},
"name": ""
}, {
"location": {
"latitude": 400342070,
"longitude": -748788996
},
"name": ""
}, {
"location": {
"latitude": 401809022,
"longitude": -744157964
},
"name": ""
}, {
"location": {
"latitude": 404226644,
"longitude": -740517141
},
"name": "9 Thompson Avenue, Leonardo, NJ 07737, USA"
}, {
"location": {
"latitude": 410322033,
"longitude": -747871659
},
"name": ""
}, {
"location": {
"latitude": 407100674,
"longitude": -747742727
},
"name": ""
}, {
"location": {
"latitude": 418811433,
"longitude": -741718005
},
"name": "213 Bush Road, Stone Ridge, NY 12484, USA"
}, {
"location": {
"latitude": 415034302,
"longitude": -743850945
},
"name": ""
}, {
"location": {
"latitude": 411349992,
"longitude": -743694161
},
"name": ""
}, {
"location": {
"latitude": 404839914,
"longitude": -744759616
},
"name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA"
}, {
"location": {
"latitude": 414638017,
"longitude": -745957854
},
"name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA"
}, {
"location": {
"latitude": 412127800,
"longitude": -740173578
},
"name": ""
}, {
"location": {
"latitude": 401263460,
"longitude": -747964303
},
"name": ""
}, {
"location": {
"latitude": 412843391,
"longitude": -749086026
},
"name": ""
}, {
"location": {
"latitude": 418512773,
"longitude": -743067823
},
"name": ""
}, {
"location": {
"latitude": 404318328,
"longitude": -740835638
},
"name": "42-102 Main Street, Belford, NJ 07718, USA"
}, {
"location": {
"latitude": 419020746,
"longitude": -741172328
},
"name": ""
}, {
"location": {
"latitude": 404080723,
"longitude": -746119569
},
"name": ""
}, {
"location": {
"latitude": 401012643,
"longitude": -744035134
},
"name": ""
}, {
"location": {
"latitude": 404306372,
"longitude": -741079661
},
"name": ""
}, {
"location": {
"latitude": 403966326,
"longitude": -748519297
},
"name": ""
}, {
"location": {
"latitude": 405002031,
"longitude": -748407866
},
"name": ""
}, {
"location": {
"latitude": 409532885,
"longitude": -742200683
},
"name": ""
}, {
"location": {
"latitude": 416851321,
"longitude": -742674555
},
"name": ""
}, {
"location": {
"latitude": 406411633,
"longitude": -741722051
},
"name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
}, {
"location": {
"latitude": 413069058,
"longitude": -744597778
},
"name": "261 Van Sickle Road, Goshen, NY 10924, USA"
}, {
"location": {
"latitude": 418465462,
"longitude": -746859398
},
"name": ""
}, {
"location": {
"latitude": 411733222,
"longitude": -744228360
},
"name": ""
}, {
"location": {
"latitude": 410248224,
"longitude": -747127767
},
"name": "3 Hasta Way, Newton, NJ 07860, USA"
}]

@ -0,0 +1,516 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: route_guide.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='route_guide.proto',
package='routeguide',
syntax='proto3',
serialized_pb=_b('\n\x11route_guide.proto\x12\nrouteguide\",\n\x05Point\x12\x10\n\x08latitude\x18\x01 \x01(\x05\x12\x11\n\tlongitude\x18\x02 \x01(\x05\"I\n\tRectangle\x12\x1d\n\x02lo\x18\x01 \x01(\x0b\x32\x11.routeguide.Point\x12\x1d\n\x02hi\x18\x02 \x01(\x0b\x32\x11.routeguide.Point\"<\n\x07\x46\x65\x61ture\x12\x0c\n\x04name\x18\x01 \x01(\t\x12#\n\x08location\x18\x02 \x01(\x0b\x32\x11.routeguide.Point\"A\n\tRouteNote\x12#\n\x08location\x18\x01 \x01(\x0b\x32\x11.routeguide.Point\x12\x0f\n\x07message\x18\x02 \x01(\t\"b\n\x0cRouteSummary\x12\x13\n\x0bpoint_count\x18\x01 \x01(\x05\x12\x15\n\rfeature_count\x18\x02 \x01(\x05\x12\x10\n\x08\x64istance\x18\x03 \x01(\x05\x12\x14\n\x0c\x65lapsed_time\x18\x04 \x01(\x05\x32\x85\x02\n\nRouteGuide\x12\x36\n\nGetFeature\x12\x11.routeguide.Point\x1a\x13.routeguide.Feature\"\x00\x12>\n\x0cListFeatures\x12\x15.routeguide.Rectangle\x1a\x13.routeguide.Feature\"\x00\x30\x01\x12>\n\x0bRecordRoute\x12\x11.routeguide.Point\x1a\x18.routeguide.RouteSummary\"\x00(\x01\x12?\n\tRouteChat\x12\x15.routeguide.RouteNote\x1a\x15.routeguide.RouteNote\"\x00(\x01\x30\x01\x42\x36\n\x1bio.grpc.examples.routeguideB\x0fRouteGuideProtoP\x01\xa2\x02\x03RTGb\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_POINT = _descriptor.Descriptor(
name='Point',
full_name='routeguide.Point',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='latitude', full_name='routeguide.Point.latitude', index=0,
number=1, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='longitude', full_name='routeguide.Point.longitude', index=1,
number=2, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=33,
serialized_end=77,
)
_RECTANGLE = _descriptor.Descriptor(
name='Rectangle',
full_name='routeguide.Rectangle',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='lo', full_name='routeguide.Rectangle.lo', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='hi', full_name='routeguide.Rectangle.hi', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=79,
serialized_end=152,
)
_FEATURE = _descriptor.Descriptor(
name='Feature',
full_name='routeguide.Feature',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='name', full_name='routeguide.Feature.name', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='location', full_name='routeguide.Feature.location', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=154,
serialized_end=214,
)
_ROUTENOTE = _descriptor.Descriptor(
name='RouteNote',
full_name='routeguide.RouteNote',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='location', full_name='routeguide.RouteNote.location', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='message', full_name='routeguide.RouteNote.message', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=216,
serialized_end=281,
)
_ROUTESUMMARY = _descriptor.Descriptor(
name='RouteSummary',
full_name='routeguide.RouteSummary',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='point_count', full_name='routeguide.RouteSummary.point_count', index=0,
number=1, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='feature_count', full_name='routeguide.RouteSummary.feature_count', index=1,
number=2, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='distance', full_name='routeguide.RouteSummary.distance', index=2,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='elapsed_time', full_name='routeguide.RouteSummary.elapsed_time', index=3,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=283,
serialized_end=381,
)
_RECTANGLE.fields_by_name['lo'].message_type = _POINT
_RECTANGLE.fields_by_name['hi'].message_type = _POINT
_FEATURE.fields_by_name['location'].message_type = _POINT
_ROUTENOTE.fields_by_name['location'].message_type = _POINT
DESCRIPTOR.message_types_by_name['Point'] = _POINT
DESCRIPTOR.message_types_by_name['Rectangle'] = _RECTANGLE
DESCRIPTOR.message_types_by_name['Feature'] = _FEATURE
DESCRIPTOR.message_types_by_name['RouteNote'] = _ROUTENOTE
DESCRIPTOR.message_types_by_name['RouteSummary'] = _ROUTESUMMARY
Point = _reflection.GeneratedProtocolMessageType('Point', (_message.Message,), dict(
DESCRIPTOR = _POINT,
__module__ = 'route_guide_pb2'
# @@protoc_insertion_point(class_scope:routeguide.Point)
))
_sym_db.RegisterMessage(Point)
Rectangle = _reflection.GeneratedProtocolMessageType('Rectangle', (_message.Message,), dict(
DESCRIPTOR = _RECTANGLE,
__module__ = 'route_guide_pb2'
# @@protoc_insertion_point(class_scope:routeguide.Rectangle)
))
_sym_db.RegisterMessage(Rectangle)
Feature = _reflection.GeneratedProtocolMessageType('Feature', (_message.Message,), dict(
DESCRIPTOR = _FEATURE,
__module__ = 'route_guide_pb2'
# @@protoc_insertion_point(class_scope:routeguide.Feature)
))
_sym_db.RegisterMessage(Feature)
RouteNote = _reflection.GeneratedProtocolMessageType('RouteNote', (_message.Message,), dict(
DESCRIPTOR = _ROUTENOTE,
__module__ = 'route_guide_pb2'
# @@protoc_insertion_point(class_scope:routeguide.RouteNote)
))
_sym_db.RegisterMessage(RouteNote)
RouteSummary = _reflection.GeneratedProtocolMessageType('RouteSummary', (_message.Message,), dict(
DESCRIPTOR = _ROUTESUMMARY,
__module__ = 'route_guide_pb2'
# @@protoc_insertion_point(class_scope:routeguide.RouteSummary)
))
_sym_db.RegisterMessage(RouteSummary)
DESCRIPTOR.has_options = True
DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.routeguideB\017RouteGuideProtoP\001\242\002\003RTG'))
import grpc
from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities
class RouteGuideStub(object):
"""Interface exported by the server.
"""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.GetFeature = channel.unary_unary(
'/routeguide.RouteGuide/GetFeature',
request_serializer=Point.SerializeToString,
response_deserializer=Feature.FromString,
)
self.ListFeatures = channel.unary_stream(
'/routeguide.RouteGuide/ListFeatures',
request_serializer=Rectangle.SerializeToString,
response_deserializer=Feature.FromString,
)
self.RecordRoute = channel.stream_unary(
'/routeguide.RouteGuide/RecordRoute',
request_serializer=Point.SerializeToString,
response_deserializer=RouteSummary.FromString,
)
self.RouteChat = channel.stream_stream(
'/routeguide.RouteGuide/RouteChat',
request_serializer=RouteNote.SerializeToString,
response_deserializer=RouteNote.FromString,
)
class RouteGuideServicer(object):
"""Interface exported by the server.
"""
def GetFeature(self, request, context):
"""A simple RPC.
Obtains the feature at a given position.
A feature with an empty name is returned if there's no feature at the given
position.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ListFeatures(self, request, context):
"""A server-to-client streaming RPC.
Obtains the Features available within the given Rectangle. Results are
streamed rather than returned at once (e.g. in a response message with a
repeated field), as the rectangle may cover a large area and contain a
huge number of features.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RecordRoute(self, request_iterator, context):
"""A client-to-server streaming RPC.
Accepts a stream of Points on a route being traversed, returning a
RouteSummary when traversal is completed.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RouteChat(self, request_iterator, context):
"""A Bidirectional streaming RPC.
Accepts a stream of RouteNotes sent while a route is being traversed,
while receiving other RouteNotes (e.g. from other users).
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_RouteGuideServicer_to_server(servicer, server):
rpc_method_handlers = {
'GetFeature': grpc.unary_unary_rpc_method_handler(
servicer.GetFeature,
request_deserializer=Point.FromString,
response_serializer=Feature.SerializeToString,
),
'ListFeatures': grpc.unary_stream_rpc_method_handler(
servicer.ListFeatures,
request_deserializer=Rectangle.FromString,
response_serializer=Feature.SerializeToString,
),
'RecordRoute': grpc.stream_unary_rpc_method_handler(
servicer.RecordRoute,
request_deserializer=Point.FromString,
response_serializer=RouteSummary.SerializeToString,
),
'RouteChat': grpc.stream_stream_rpc_method_handler(
servicer.RouteChat,
request_deserializer=RouteNote.FromString,
response_serializer=RouteNote.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'routeguide.RouteGuide', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaRouteGuideServicer(object):
"""Interface exported by the server.
"""
def GetFeature(self, request, context):
"""A simple RPC.
Obtains the feature at a given position.
A feature with an empty name is returned if there's no feature at the given
position.
"""
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def ListFeatures(self, request, context):
"""A server-to-client streaming RPC.
Obtains the Features available within the given Rectangle. Results are
streamed rather than returned at once (e.g. in a response message with a
repeated field), as the rectangle may cover a large area and contain a
huge number of features.
"""
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def RecordRoute(self, request_iterator, context):
"""A client-to-server streaming RPC.
Accepts a stream of Points on a route being traversed, returning a
RouteSummary when traversal is completed.
"""
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
def RouteChat(self, request_iterator, context):
"""A Bidirectional streaming RPC.
Accepts a stream of RouteNotes sent while a route is being traversed,
while receiving other RouteNotes (e.g. from other users).
"""
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaRouteGuideStub(object):
"""Interface exported by the server.
"""
def GetFeature(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
"""A simple RPC.
Obtains the feature at a given position.
A feature with an empty name is returned if there's no feature at the given
position.
"""
raise NotImplementedError()
GetFeature.future = None
def ListFeatures(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
"""A server-to-client streaming RPC.
Obtains the Features available within the given Rectangle. Results are
streamed rather than returned at once (e.g. in a response message with a
repeated field), as the rectangle may cover a large area and contain a
huge number of features.
"""
raise NotImplementedError()
def RecordRoute(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
"""A client-to-server streaming RPC.
Accepts a stream of Points on a route being traversed, returning a
RouteSummary when traversal is completed.
"""
raise NotImplementedError()
RecordRoute.future = None
def RouteChat(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
"""A Bidirectional streaming RPC.
Accepts a stream of RouteNotes sent while a route is being traversed,
while receiving other RouteNotes (e.g. from other users).
"""
raise NotImplementedError()
def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
request_deserializers = {
('routeguide.RouteGuide', 'GetFeature'): Point.FromString,
('routeguide.RouteGuide', 'ListFeatures'): Rectangle.FromString,
('routeguide.RouteGuide', 'RecordRoute'): Point.FromString,
('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
}
response_serializers = {
('routeguide.RouteGuide', 'GetFeature'): Feature.SerializeToString,
('routeguide.RouteGuide', 'ListFeatures'): Feature.SerializeToString,
('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.SerializeToString,
('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
}
method_implementations = {
('routeguide.RouteGuide', 'GetFeature'): face_utilities.unary_unary_inline(servicer.GetFeature),
('routeguide.RouteGuide', 'ListFeatures'): face_utilities.unary_stream_inline(servicer.ListFeatures),
('routeguide.RouteGuide', 'RecordRoute'): face_utilities.stream_unary_inline(servicer.RecordRoute),
('routeguide.RouteGuide', 'RouteChat'): face_utilities.stream_stream_inline(servicer.RouteChat),
}
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options)
def beta_create_RouteGuide_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
request_serializers = {
('routeguide.RouteGuide', 'GetFeature'): Point.SerializeToString,
('routeguide.RouteGuide', 'ListFeatures'): Rectangle.SerializeToString,
('routeguide.RouteGuide', 'RecordRoute'): Point.SerializeToString,
('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
}
response_deserializers = {
('routeguide.RouteGuide', 'GetFeature'): Feature.FromString,
('routeguide.RouteGuide', 'ListFeatures'): Feature.FromString,
('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.FromString,
('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
}
cardinalities = {
'GetFeature': cardinality.Cardinality.UNARY_UNARY,
'ListFeatures': cardinality.Cardinality.UNARY_STREAM,
'RecordRoute': cardinality.Cardinality.STREAM_UNARY,
'RouteChat': cardinality.Cardinality.STREAM_STREAM,
}
stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
return beta_implementations.dynamic_stub(channel, 'routeguide.RouteGuide', cardinalities, options=stub_options)
# @@protoc_insertion_point(module_scope)

@ -0,0 +1,53 @@
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Common resources used in the gRPC route guide example."""
import json
import route_guide_pb2
def read_route_guide_database():
"""Reads the route guide database.
Returns:
The full contents of the route guide database as a sequence of
route_guide_pb2.Features.
"""
feature_list = []
with open("route_guide_db.json") as route_guide_db_file:
for item in json.load(route_guide_db_file):
feature = route_guide_pb2.Feature(
name=item["name"],
location=route_guide_pb2.Point(
latitude=item["location"]["latitude"],
longitude=item["location"]["longitude"]))
feature_list.append(feature)
return feature_list

@ -0,0 +1,51 @@
# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Generates protocol messages and gRPC stubs."""
from grpc.tools import protoc
protoc.main(
(
'',
'-I../../protos',
'--python_out=.',
'--grpc_python_out=.',
'../../protos/helloworld.proto',
)
)
protoc.main(
(
'',
'-I../../protos',
'--python_out=.',
'--grpc_python_out=.',
'../../protos/route_guide.proto',
)
)

@ -34,13 +34,11 @@ from __future__ import print_function
import random import random
import time import time
from grpc.beta import implementations import grpc
import route_guide_pb2 import route_guide_pb2
import route_guide_resources import route_guide_resources
_TIMEOUT_SECONDS = 30
def make_route_note(message, latitude, longitude): def make_route_note(message, latitude, longitude):
return route_guide_pb2.RouteNote( return route_guide_pb2.RouteNote(
@ -49,7 +47,7 @@ def make_route_note(message, latitude, longitude):
def guide_get_one_feature(stub, point): def guide_get_one_feature(stub, point):
feature = stub.GetFeature(point, _TIMEOUT_SECONDS) feature = stub.GetFeature(point)
if not feature.location: if not feature.location:
print("Server returned incomplete feature") print("Server returned incomplete feature")
return return
@ -66,14 +64,12 @@ def guide_get_feature(stub):
def guide_list_features(stub): def guide_list_features(stub):
rect = route_guide_pb2.Rectangle( rectangle = route_guide_pb2.Rectangle(
lo=route_guide_pb2.Point( lo=route_guide_pb2.Point(latitude=400000000, longitude=-750000000),
latitude=400000000, longitude = -750000000), hi=route_guide_pb2.Point(latitude=420000000, longitude=-730000000))
hi=route_guide_pb2.Point(
latitude = 420000000, longitude = -730000000))
print("Looking for features between 40, -75 and 42, -73") print("Looking for features between 40, -75 and 42, -73")
features = stub.ListFeatures(rect, _TIMEOUT_SECONDS) features = stub.ListFeatures(rectangle)
for feature in features: for feature in features:
print("Feature called %s at %s" % (feature.name, feature.location)) print("Feature called %s at %s" % (feature.name, feature.location))
@ -90,8 +86,8 @@ def generate_route(feature_list):
def guide_record_route(stub): def guide_record_route(stub):
feature_list = route_guide_resources.read_route_guide_database() feature_list = route_guide_resources.read_route_guide_database()
route_iter = generate_route(feature_list) route_iterator = generate_route(feature_list)
route_summary = stub.RecordRoute(route_iter, _TIMEOUT_SECONDS) route_summary = stub.RecordRoute(route_iterator)
print("Finished trip with %s points " % route_summary.point_count) print("Finished trip with %s points " % route_summary.point_count)
print("Passed %s features " % route_summary.feature_count) print("Passed %s features " % route_summary.feature_count)
print("Travelled %s meters " % route_summary.distance) print("Travelled %s meters " % route_summary.distance)
@ -113,14 +109,14 @@ def generate_messages():
def guide_route_chat(stub): def guide_route_chat(stub):
responses = stub.RouteChat(generate_messages(), _TIMEOUT_SECONDS) responses = stub.RouteChat(generate_messages())
for response in responses: for response in responses:
print("Received message %s at %s" % (response.message, response.location)) print("Received message %s at %s" % (response.message, response.location))
def run(): def run():
channel = implementations.insecure_channel('localhost', 50051) channel = grpc.insecure_channel('localhost:50051')
stub = route_guide_pb2.beta_create_RouteGuide_stub(channel) stub = route_guide_pb2.RouteGuideStub(channel)
print("-------------- GetFeature --------------") print("-------------- GetFeature --------------")
guide_get_feature(stub) guide_get_feature(stub)
print("-------------- ListFeatures --------------") print("-------------- ListFeatures --------------")

@ -277,13 +277,122 @@ _sym_db.RegisterMessage(RouteSummary)
DESCRIPTOR.has_options = True DESCRIPTOR.has_options = True
DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.routeguideB\017RouteGuideProtoP\001\242\002\003RTG')) DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.routeguideB\017RouteGuideProtoP\001\242\002\003RTG'))
import abc import grpc
import six
from grpc.beta import implementations as beta_implementations from grpc.beta import implementations as beta_implementations
from grpc.beta import interfaces as beta_interfaces from grpc.beta import interfaces as beta_interfaces
from grpc.framework.common import cardinality from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities as face_utilities from grpc.framework.interfaces.face import utilities as face_utilities
class RouteGuideStub(object):
"""Interface exported by the server.
"""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.GetFeature = channel.unary_unary(
'/routeguide.RouteGuide/GetFeature',
request_serializer=Point.SerializeToString,
response_deserializer=Feature.FromString,
)
self.ListFeatures = channel.unary_stream(
'/routeguide.RouteGuide/ListFeatures',
request_serializer=Rectangle.SerializeToString,
response_deserializer=Feature.FromString,
)
self.RecordRoute = channel.stream_unary(
'/routeguide.RouteGuide/RecordRoute',
request_serializer=Point.SerializeToString,
response_deserializer=RouteSummary.FromString,
)
self.RouteChat = channel.stream_stream(
'/routeguide.RouteGuide/RouteChat',
request_serializer=RouteNote.SerializeToString,
response_deserializer=RouteNote.FromString,
)
class RouteGuideServicer(object):
"""Interface exported by the server.
"""
def GetFeature(self, request, context):
"""A simple RPC.
Obtains the feature at a given position.
A feature with an empty name is returned if there's no feature at the given
position.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ListFeatures(self, request, context):
"""A server-to-client streaming RPC.
Obtains the Features available within the given Rectangle. Results are
streamed rather than returned at once (e.g. in a response message with a
repeated field), as the rectangle may cover a large area and contain a
huge number of features.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RecordRoute(self, request_iterator, context):
"""A client-to-server streaming RPC.
Accepts a stream of Points on a route being traversed, returning a
RouteSummary when traversal is completed.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def RouteChat(self, request_iterator, context):
"""A Bidirectional streaming RPC.
Accepts a stream of RouteNotes sent while a route is being traversed,
while receiving other RouteNotes (e.g. from other users).
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_RouteGuideServicer_to_server(servicer, server):
rpc_method_handlers = {
'GetFeature': grpc.unary_unary_rpc_method_handler(
servicer.GetFeature,
request_deserializer=Point.FromString,
response_serializer=Feature.SerializeToString,
),
'ListFeatures': grpc.unary_stream_rpc_method_handler(
servicer.ListFeatures,
request_deserializer=Rectangle.FromString,
response_serializer=Feature.SerializeToString,
),
'RecordRoute': grpc.stream_unary_rpc_method_handler(
servicer.RecordRoute,
request_deserializer=Point.FromString,
response_serializer=RouteSummary.SerializeToString,
),
'RouteChat': grpc.stream_stream_rpc_method_handler(
servicer.RouteChat,
request_deserializer=RouteNote.FromString,
response_serializer=RouteNote.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'routeguide.RouteGuide', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
class BetaRouteGuideServicer(object): class BetaRouteGuideServicer(object):
"""Interface exported by the server. """Interface exported by the server.
""" """
@ -320,10 +429,11 @@ class BetaRouteGuideServicer(object):
""" """
context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
class BetaRouteGuideStub(object): class BetaRouteGuideStub(object):
"""Interface exported by the server. """Interface exported by the server.
""" """
def GetFeature(self, request, timeout): def GetFeature(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
"""A simple RPC. """A simple RPC.
Obtains the feature at a given position. Obtains the feature at a given position.
@ -333,7 +443,7 @@ class BetaRouteGuideStub(object):
""" """
raise NotImplementedError() raise NotImplementedError()
GetFeature.future = None GetFeature.future = None
def ListFeatures(self, request, timeout): def ListFeatures(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
"""A server-to-client streaming RPC. """A server-to-client streaming RPC.
Obtains the Features available within the given Rectangle. Results are Obtains the Features available within the given Rectangle. Results are
@ -342,7 +452,7 @@ class BetaRouteGuideStub(object):
huge number of features. huge number of features.
""" """
raise NotImplementedError() raise NotImplementedError()
def RecordRoute(self, request_iterator, timeout): def RecordRoute(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
"""A client-to-server streaming RPC. """A client-to-server streaming RPC.
Accepts a stream of Points on a route being traversed, returning a Accepts a stream of Points on a route being traversed, returning a
@ -350,7 +460,7 @@ class BetaRouteGuideStub(object):
""" """
raise NotImplementedError() raise NotImplementedError()
RecordRoute.future = None RecordRoute.future = None
def RouteChat(self, request_iterator, timeout): def RouteChat(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
"""A Bidirectional streaming RPC. """A Bidirectional streaming RPC.
Accepts a stream of RouteNotes sent while a route is being traversed, Accepts a stream of RouteNotes sent while a route is being traversed,
@ -358,26 +468,19 @@ class BetaRouteGuideStub(object):
""" """
raise NotImplementedError() raise NotImplementedError()
def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
request_deserializers = { request_deserializers = {
('routeguide.RouteGuide', 'GetFeature'): route_guide_pb2.Point.FromString, ('routeguide.RouteGuide', 'GetFeature'): Point.FromString,
('routeguide.RouteGuide', 'ListFeatures'): route_guide_pb2.Rectangle.FromString, ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.FromString,
('routeguide.RouteGuide', 'RecordRoute'): route_guide_pb2.Point.FromString, ('routeguide.RouteGuide', 'RecordRoute'): Point.FromString,
('routeguide.RouteGuide', 'RouteChat'): route_guide_pb2.RouteNote.FromString, ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
} }
response_serializers = { response_serializers = {
('routeguide.RouteGuide', 'GetFeature'): route_guide_pb2.Feature.SerializeToString, ('routeguide.RouteGuide', 'GetFeature'): Feature.SerializeToString,
('routeguide.RouteGuide', 'ListFeatures'): route_guide_pb2.Feature.SerializeToString, ('routeguide.RouteGuide', 'ListFeatures'): Feature.SerializeToString,
('routeguide.RouteGuide', 'RecordRoute'): route_guide_pb2.RouteSummary.SerializeToString, ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.SerializeToString,
('routeguide.RouteGuide', 'RouteChat'): route_guide_pb2.RouteNote.SerializeToString, ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
} }
method_implementations = { method_implementations = {
('routeguide.RouteGuide', 'GetFeature'): face_utilities.unary_unary_inline(servicer.GetFeature), ('routeguide.RouteGuide', 'GetFeature'): face_utilities.unary_unary_inline(servicer.GetFeature),
@ -388,26 +491,19 @@ def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_t
server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout) server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
return beta_implementations.server(method_implementations, options=server_options) return beta_implementations.server(method_implementations, options=server_options)
def beta_create_RouteGuide_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None): def beta_create_RouteGuide_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
import route_guide_pb2
request_serializers = { request_serializers = {
('routeguide.RouteGuide', 'GetFeature'): route_guide_pb2.Point.SerializeToString, ('routeguide.RouteGuide', 'GetFeature'): Point.SerializeToString,
('routeguide.RouteGuide', 'ListFeatures'): route_guide_pb2.Rectangle.SerializeToString, ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.SerializeToString,
('routeguide.RouteGuide', 'RecordRoute'): route_guide_pb2.Point.SerializeToString, ('routeguide.RouteGuide', 'RecordRoute'): Point.SerializeToString,
('routeguide.RouteGuide', 'RouteChat'): route_guide_pb2.RouteNote.SerializeToString, ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
} }
response_deserializers = { response_deserializers = {
('routeguide.RouteGuide', 'GetFeature'): route_guide_pb2.Feature.FromString, ('routeguide.RouteGuide', 'GetFeature'): Feature.FromString,
('routeguide.RouteGuide', 'ListFeatures'): route_guide_pb2.Feature.FromString, ('routeguide.RouteGuide', 'ListFeatures'): Feature.FromString,
('routeguide.RouteGuide', 'RecordRoute'): route_guide_pb2.RouteSummary.FromString, ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.FromString,
('routeguide.RouteGuide', 'RouteChat'): route_guide_pb2.RouteNote.FromString, ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
} }
cardinalities = { cardinalities = {
'GetFeature': cardinality.Cardinality.UNARY_UNARY, 'GetFeature': cardinality.Cardinality.UNARY_UNARY,

@ -29,9 +29,12 @@
"""The Python implementation of the gRPC route guide server.""" """The Python implementation of the gRPC route guide server."""
from concurrent import futures
import time import time
import math import math
import grpc
import route_guide_pb2 import route_guide_pb2
import route_guide_resources import route_guide_resources
@ -121,7 +124,9 @@ class RouteGuideServicer(route_guide_pb2.BetaRouteGuideServicer):
def serve(): def serve():
server = route_guide_pb2.beta_create_RouteGuide_server(RouteGuideServicer()) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
route_guide_pb2.add_RouteGuideServicer_to_server(
RouteGuideServicer(), server)
server.add_insecure_port('[::]:50051') server.add_insecure_port('[::]:50051')
server.start() server.start()
try: try:

@ -1,5 +1,4 @@
#!/usr/bin/env ruby # Copyright 2015, Google Inc.
# Copyright 2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -28,14 +27,16 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'rbconfig' """Runs protoc with the gRPC plugin to generate messages and gRPC stubs."""
require_relative '../os_check' from grpc.tools import protoc
protoc_name = 'protoc' + RbConfig::CONFIG['EXEEXT'] protoc.main(
(
protoc_path = File.join(File.dirname(__FILE__), '',
RbConfig::CONFIG['host_cpu'] + '-' + OS.os_name, '-I../../protos',
protoc_name) '--python_out=.',
'--grpc_python_out=.',
exec([ protoc_path, protoc_path ], *ARGV) '../../protos/route_guide.proto',
)
)

@ -35,7 +35,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'gRPC-Core' s.name = 'gRPC-Core'
version = '0.14.0' version = '1.0.0-pre1'
s.version = version s.version = version
s.summary = 'Core cross-platform gRPC library, written in C' s.summary = 'Core cross-platform gRPC library, written in C'
s.homepage = 'http://www.grpc.io' s.homepage = 'http://www.grpc.io'
@ -44,7 +44,7 @@ Pod::Spec.new do |s|
s.source = { s.source = {
:git => 'https://github.com/grpc/grpc.git', :git => 'https://github.com/grpc/grpc.git',
:tag => "release-#{version.gsub(/\./, '_')}-objectivec-#{version}", :tag => "objective-c-v#{version}",
# TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules. # TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules.
:submodules => true, :submodules => true,
} }
@ -191,7 +191,7 @@ Pod::Spec.new do |s|
ss.header_mappings_dir = '.' ss.header_mappings_dir = '.'
ss.libraries = 'z' ss.libraries = 'z'
ss.dependency "#{s.name}/Interface", version ss.dependency "#{s.name}/Interface", version
ss.dependency 'BoringSSL', '~> 4.0' ss.dependency 'BoringSSL', '~> 5.0'
# To save you from scrolling, this is the last part of the podspec. # To save you from scrolling, this is the last part of the podspec.
ss.source_files = 'src/core/lib/profiling/timers.h', ss.source_files = 'src/core/lib/profiling/timers.h',

@ -36,7 +36,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'gRPC-ProtoRPC' s.name = 'gRPC-ProtoRPC'
version = '0.14.0' version = '1.0.0-pre1'
s.version = version s.version = version
s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.summary = 'RPC library for Protocol Buffers, based on gRPC'
s.homepage = 'http://www.grpc.io' s.homepage = 'http://www.grpc.io'
@ -45,7 +45,7 @@ Pod::Spec.new do |s|
s.source = { s.source = {
:git => 'https://github.com/grpc/grpc.git', :git => 'https://github.com/grpc/grpc.git',
:tag => "release-#{version.gsub(/\./, '_')}-objectivec-#{version}", :tag => "objective-c-v#{version}",
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.1'

@ -36,7 +36,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'gRPC-RxLibrary' s.name = 'gRPC-RxLibrary'
version = '0.14.0' version = '1.0.0-pre1'
s.version = version s.version = version
s.summary = 'Reactive Extensions library for iOS/OSX.' s.summary = 'Reactive Extensions library for iOS/OSX.'
s.homepage = 'http://www.grpc.io' s.homepage = 'http://www.grpc.io'
@ -45,7 +45,7 @@ Pod::Spec.new do |s|
s.source = { s.source = {
:git => 'https://github.com/grpc/grpc.git', :git => 'https://github.com/grpc/grpc.git',
:tag => "release-#{version.gsub(/\./, '_')}-objectivec-#{version}", :tag => "objective-c-v#{version}",
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.1'

@ -36,7 +36,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'gRPC' s.name = 'gRPC'
version = '0.14.0' version = '1.0.0-pre1'
s.version = version s.version = version
s.summary = 'gRPC client library for iOS/OSX' s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'http://www.grpc.io' s.homepage = 'http://www.grpc.io'
@ -45,7 +45,7 @@ Pod::Spec.new do |s|
s.source = { s.source = {
:git => 'https://github.com/grpc/grpc.git', :git => 'https://github.com/grpc/grpc.git',
:tag => "release-#{version.gsub(/\./, '_')}-objectivec-#{version}", :tag => "objective-c-v#{version}",
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.1'

@ -330,6 +330,9 @@ class ServerAsyncReader GRPC_FINAL : public ServerAsyncReaderInterface<W, R> {
meta_ops_.set_output_tag(tag); meta_ops_.set_output_tag(tag);
meta_ops_.SendInitialMetadata(ctx_->initial_metadata_, meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_ops_); call_.PerformOps(&meta_ops_);
} }
@ -345,6 +348,9 @@ class ServerAsyncReader GRPC_FINAL : public ServerAsyncReaderInterface<W, R> {
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_, finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
// The response is dropped if the status is not OK. // The response is dropped if the status is not OK.
@ -363,6 +369,9 @@ class ServerAsyncReader GRPC_FINAL : public ServerAsyncReaderInterface<W, R> {
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_, finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status); finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
@ -400,6 +409,9 @@ class ServerAsyncWriter GRPC_FINAL : public ServerAsyncWriterInterface<W> {
meta_ops_.set_output_tag(tag); meta_ops_.set_output_tag(tag);
meta_ops_.SendInitialMetadata(ctx_->initial_metadata_, meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_ops_); call_.PerformOps(&meta_ops_);
} }
@ -409,6 +421,9 @@ class ServerAsyncWriter GRPC_FINAL : public ServerAsyncWriterInterface<W> {
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
write_ops_.SendInitialMetadata(ctx_->initial_metadata_, write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
write_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
// TODO(ctiller): don't assert // TODO(ctiller): don't assert
@ -421,6 +436,9 @@ class ServerAsyncWriter GRPC_FINAL : public ServerAsyncWriterInterface<W> {
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_, finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status); finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
@ -459,6 +477,9 @@ class ServerAsyncReaderWriter GRPC_FINAL
meta_ops_.set_output_tag(tag); meta_ops_.set_output_tag(tag);
meta_ops_.SendInitialMetadata(ctx_->initial_metadata_, meta_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_ops_); call_.PerformOps(&meta_ops_);
} }
@ -474,6 +495,9 @@ class ServerAsyncReaderWriter GRPC_FINAL
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
write_ops_.SendInitialMetadata(ctx_->initial_metadata_, write_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
write_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
// TODO(ctiller): don't assert // TODO(ctiller): don't assert
@ -486,6 +510,9 @@ class ServerAsyncReaderWriter GRPC_FINAL
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
finish_ops_.SendInitialMetadata(ctx_->initial_metadata_, finish_ops_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_ops_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status); finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);

@ -126,6 +126,9 @@ class ServerAsyncResponseWriter GRPC_FINAL
meta_buf_.set_output_tag(tag); meta_buf_.set_output_tag(tag);
meta_buf_.SendInitialMetadata(ctx_->initial_metadata_, meta_buf_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
meta_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
call_.PerformOps(&meta_buf_); call_.PerformOps(&meta_buf_);
} }
@ -135,6 +138,9 @@ class ServerAsyncResponseWriter GRPC_FINAL
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(ctx_->initial_metadata_, finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
// The response is dropped if the status is not OK. // The response is dropped if the status is not OK.
@ -153,6 +159,9 @@ class ServerAsyncResponseWriter GRPC_FINAL
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
finish_buf_.SendInitialMetadata(ctx_->initial_metadata_, finish_buf_.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
finish_buf_.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status); finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);

@ -180,17 +180,23 @@ class CallNoOp {
class CallOpSendInitialMetadata { class CallOpSendInitialMetadata {
public: public:
CallOpSendInitialMetadata() : send_(false) {} CallOpSendInitialMetadata() : send_(false) {
maybe_compression_level_.is_set = false;
}
void SendInitialMetadata( void SendInitialMetadata(
const std::multimap<grpc::string, grpc::string>& metadata, const std::multimap<grpc::string, grpc::string>& metadata,
uint32_t flags) { uint32_t flags) {
maybe_compression_level_.is_set = false;
send_ = true; send_ = true;
flags_ = flags; flags_ = flags;
initial_metadata_count_ = metadata.size(); initial_metadata_count_ = metadata.size();
initial_metadata_ = FillMetadataArray(metadata); initial_metadata_ = FillMetadataArray(metadata);
// TODO(dgq): expose compression level in API so it can be properly set. }
maybe_compression_level_.is_set = false;
void set_compression_level(grpc_compression_level level) {
maybe_compression_level_.is_set = true;
maybe_compression_level_.level = level;
} }
protected: protected:

@ -65,6 +65,9 @@ class RpcMethodHandler : public MethodHandler {
ops; ops;
ops.SendInitialMetadata(param.server_context->initial_metadata_, ops.SendInitialMetadata(param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags()); param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
if (status.ok()) { if (status.ok()) {
status = ops.SendMessage(rsp); status = ops.SendMessage(rsp);
} }
@ -104,6 +107,9 @@ class ClientStreamingHandler : public MethodHandler {
ops; ops;
ops.SendInitialMetadata(param.server_context->initial_metadata_, ops.SendInitialMetadata(param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags()); param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
if (status.ok()) { if (status.ok()) {
status = ops.SendMessage(rsp); status = ops.SendMessage(rsp);
} }
@ -144,6 +150,9 @@ class ServerStreamingHandler : public MethodHandler {
if (!param.server_context->sent_initial_metadata_) { if (!param.server_context->sent_initial_metadata_) {
ops.SendInitialMetadata(param.server_context->initial_metadata_, ops.SendInitialMetadata(param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags()); param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
} }
ops.ServerSendStatus(param.server_context->trailing_metadata_, status); ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops); param.call->PerformOps(&ops);
@ -177,6 +186,9 @@ class BidiStreamingHandler : public MethodHandler {
if (!param.server_context->sent_initial_metadata_) { if (!param.server_context->sent_initial_metadata_) {
ops.SendInitialMetadata(param.server_context->initial_metadata_, ops.SendInitialMetadata(param.server_context->initial_metadata_,
param.server_context->initial_metadata_flags()); param.server_context->initial_metadata_flags());
if (param.server_context->compression_level_set()) {
ops.set_compression_level(param.server_context->compression_level());
}
} }
ops.ServerSendStatus(param.server_context->trailing_metadata_, status); ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
param.call->PerformOps(&ops); param.call->PerformOps(&ops);
@ -199,6 +211,9 @@ class UnknownMethodHandler : public MethodHandler {
if (!context->sent_initial_metadata_) { if (!context->sent_initial_metadata_) {
ops->SendInitialMetadata(context->initial_metadata_, ops->SendInitialMetadata(context->initial_metadata_,
context->initial_metadata_flags()); context->initial_metadata_flags());
if (context->compression_level_set()) {
ops->set_compression_level(context->compression_level());
}
context->sent_initial_metadata_ = true; context->sent_initial_metadata_ = true;
} }
ops->ServerSendStatus(context->trailing_metadata_, status); ops->ServerSendStatus(context->trailing_metadata_, status);

@ -130,7 +130,13 @@ class ServerContext {
grpc_compression_level compression_level() const { grpc_compression_level compression_level() const {
return compression_level_; return compression_level_;
} }
void set_compression_level(grpc_compression_level level);
void set_compression_level(grpc_compression_level level) {
compression_level_set_ = true;
compression_level_ = level;
}
bool compression_level_set() const { return compression_level_set_; }
grpc_compression_algorithm compression_algorithm() const { grpc_compression_algorithm compression_algorithm() const {
return compression_algorithm_; return compression_algorithm_;
@ -217,6 +223,7 @@ class ServerContext {
std::multimap<grpc::string, grpc::string> initial_metadata_; std::multimap<grpc::string, grpc::string> initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_; std::multimap<grpc::string, grpc::string> trailing_metadata_;
bool compression_level_set_;
grpc_compression_level compression_level_; grpc_compression_level compression_level_;
grpc_compression_algorithm compression_algorithm_; grpc_compression_algorithm compression_algorithm_;
}; };

@ -347,6 +347,9 @@ class ServerReader GRPC_FINAL : public ReaderInterface<R> {
CallOpSet<CallOpSendInitialMetadata> ops; CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(ctx_->initial_metadata_, ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops); call_->PerformOps(&ops);
call_->cq()->Pluck(&ops); call_->cq()->Pluck(&ops);
@ -375,6 +378,9 @@ class ServerWriter GRPC_FINAL : public WriterInterface<W> {
CallOpSet<CallOpSendInitialMetadata> ops; CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(ctx_->initial_metadata_, ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops); call_->PerformOps(&ops);
call_->cq()->Pluck(&ops); call_->cq()->Pluck(&ops);
@ -389,6 +395,9 @@ class ServerWriter GRPC_FINAL : public WriterInterface<W> {
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
ops.SendInitialMetadata(ctx_->initial_metadata_, ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
call_->PerformOps(&ops); call_->PerformOps(&ops);
@ -413,6 +422,9 @@ class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>,
CallOpSet<CallOpSendInitialMetadata> ops; CallOpSet<CallOpSendInitialMetadata> ops;
ops.SendInitialMetadata(ctx_->initial_metadata_, ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
call_->PerformOps(&ops); call_->PerformOps(&ops);
call_->cq()->Pluck(&ops); call_->cq()->Pluck(&ops);
@ -434,6 +446,9 @@ class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>,
if (!ctx_->sent_initial_metadata_) { if (!ctx_->sent_initial_metadata_) {
ops.SendInitialMetadata(ctx_->initial_metadata_, ops.SendInitialMetadata(ctx_->initial_metadata_,
ctx_->initial_metadata_flags()); ctx_->initial_metadata_flags());
if (ctx_->compression_level_set()) {
ops.set_compression_level(ctx_->compression_level());
}
ctx_->sent_initial_metadata_ = true; ctx_->sent_initial_metadata_ = true;
} }
call_->PerformOps(&ops); call_->PerformOps(&ops);

@ -179,10 +179,13 @@ class Server GRPC_FINAL : public ServerInterface, private GrpcLibraryCodegen {
grpc::mutex mu_; grpc::mutex mu_;
bool started_; bool started_;
bool shutdown_; bool shutdown_;
bool shutdown_notified_;
// The number of threads which are running callbacks. // The number of threads which are running callbacks.
int num_running_cb_; int num_running_cb_;
grpc::condition_variable callback_cv_; grpc::condition_variable callback_cv_;
grpc::condition_variable shutdown_cv_;
std::shared_ptr<GlobalCallbacks> global_callbacks_; std::shared_ptr<GlobalCallbacks> global_callbacks_;
std::list<SyncRequest>* sync_methods_; std::list<SyncRequest>* sync_methods_;

@ -46,12 +46,27 @@ extern "C" {
#define GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY \ #define GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY \
"grpc-internal-encoding-request" "grpc-internal-encoding-request"
/** To be used in channel arguments */ /** To be used in channel arguments.
*
* \addtogroup grpc_arg_keys
* \{ */
/** Default compression algorithm for the channel.
* Its value is an int from the \a grpc_compression_algorithm enum. */
#define GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM \ #define GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM \
"grpc.default_compression_algorithm" "grpc.default_compression_algorithm"
/** Default compression level for the channel.
* Its value is an int from the \a grpc_compression_level enum. */
#define GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL "grpc.default_compression_level" #define GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL "grpc.default_compression_level"
/** Compression algorithms supported by the channel.
* Its value is a bitset (an int). Bits correspond to algorithms in \a
* grpc_compression_algorithm. For example, its LSB corresponds to
* GRPC_COMPRESS_NONE, the next bit to GRPC_COMPRESS_DEFLATE, etc.
* Unset bits disable support for the algorithm. By default all algorithms are
* supported. It's not possible to disable GRPC_COMPRESS_NONE (the attempt will
* be ignored). */
#define GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET \ #define GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET \
"grpc.compression_enabled_algorithms_bitset" "grpc.compression_enabled_algorithms_bitset"
/** \} */
/* The various compression algorithms supported by gRPC */ /* The various compression algorithms supported by gRPC */
typedef enum { typedef enum {

@ -106,58 +106,66 @@ typedef struct {
by grpc_arg; keys are strings to allow easy backwards-compatible extension by grpc_arg; keys are strings to allow easy backwards-compatible extension
by arbitrary parties. by arbitrary parties.
All evaluation is performed at channel creation time (i.e. the values in All evaluation is performed at channel creation time (i.e. the values in
this structure need only live through the creation invocation). */ this structure need only live through the creation invocation).
See the description of the \ref grpc_arg_keys "available args" for more
details. */
typedef struct { typedef struct {
size_t num_args; size_t num_args;
grpc_arg *args; grpc_arg *args;
} grpc_channel_args; } grpc_channel_args;
/* Channel argument keys: */ /** \defgroup grpc_arg_keys
/** Enable census for tracing and stats collection */ * Channel argument keys.
* \{
*/
/** If non-zero, enable census for tracing and stats collection. */
#define GRPC_ARG_ENABLE_CENSUS "grpc.census" #define GRPC_ARG_ENABLE_CENSUS "grpc.census"
/** Enable load reporting */ /** If non-zero, enable load reporting. */
#define GRPC_ARG_ENABLE_LOAD_REPORTING "grpc.loadreporting" #define GRPC_ARG_ENABLE_LOAD_REPORTING "grpc.loadreporting"
/** Maximum number of concurrent incoming streams to allow on a http2 /** Maximum number of concurrent incoming streams to allow on a http2
connection */ connection. Int valued. */
#define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams" #define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
/** Maximum message length that the channel can receive */ /** Maximum message length that the channel can receive. Int valued, bytes. */
#define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length" #define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
/** Initial sequence number for http2 transports */ /** Initial sequence number for http2 transports. Int valued. */
#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \ #define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
"grpc.http2.initial_sequence_number" "grpc.http2.initial_sequence_number"
/** Amount to read ahead on individual streams. Defaults to 64kb, larger /** Amount to read ahead on individual streams. Defaults to 64kb, larger
values can help throughput on high-latency connections. values can help throughput on high-latency connections.
NOTE: at some point we'd like to auto-tune this, and this parameter NOTE: at some point we'd like to auto-tune this, and this parameter
will become a no-op. */ will become a no-op. Int valued, bytes. */
#define GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES "grpc.http2.lookahead_bytes" #define GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES "grpc.http2.lookahead_bytes"
/** How much memory to use for hpack decoding */ /** How much memory to use for hpack decoding. Int valued, bytes. */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \ #define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \
"grpc.http2.hpack_table_size.decoder" "grpc.http2.hpack_table_size.decoder"
/** How much memory to use for hpack encoding */ /** How much memory to use for hpack encoding. Int valued, bytes. */
#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \ #define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \
"grpc.http2.hpack_table_size.encoder" "grpc.http2.hpack_table_size.encoder"
/** Default authority to pass if none specified on call construction */ /** Default authority to pass if none specified on call construction. A string.
* */
#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority" #define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
/** Primary user agent: goes at the start of the user-agent metadata /** Primary user agent: goes at the start of the user-agent metadata
sent on each request */ sent on each request. A string. */
#define GRPC_ARG_PRIMARY_USER_AGENT_STRING "grpc.primary_user_agent" #define GRPC_ARG_PRIMARY_USER_AGENT_STRING "grpc.primary_user_agent"
/** Secondary user agent: goes at the end of the user-agent metadata /** Secondary user agent: goes at the end of the user-agent metadata
sent on each request */ sent on each request. A string. */
#define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent" #define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent"
/** The maximum time between subsequent connection attempts, in ms */ /** The maximum time between subsequent connection attempts, in ms */
#define GRPC_ARG_MAX_RECONNECT_BACKOFF_MS "grpc.max_reconnect_backoff_ms" #define GRPC_ARG_MAX_RECONNECT_BACKOFF_MS "grpc.max_reconnect_backoff_ms"
/* The caller of the secure_channel_create functions may override the target /* The caller of the secure_channel_create functions may override the target
name used for SSL host name checking using this channel argument which is of name used for SSL host name checking using this channel argument which is of
type GRPC_ARG_STRING. This *should* be used for testing only. type \a GRPC_ARG_STRING. This *should* be used for testing only.
If this argument is not specified, the name used for SSL host name checking If this argument is not specified, the name used for SSL host name checking
will be the target parameter (assuming that the secure channel is an SSL will be the target parameter (assuming that the secure channel is an SSL
channel). If this parameter is specified and the underlying is not an SSL channel). If this parameter is specified and the underlying is not an SSL
channel, it will just be ignored. */ channel, it will just be ignored. */
#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override" #define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override"
/* Maximum metadata size */ /* Maximum metadata size, in bytes. */
#define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size" #define GRPC_ARG_MAX_METADATA_SIZE "grpc.max_metadata_size"
/** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */ /** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */
#define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport" #define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport"
/** \} */
/** Result of a grpc call. If the caller satisfies the prerequisites of a /** Result of a grpc call. If the caller satisfies the prerequisites of a
particular operation, the grpc_call_error returned will be GRPC_CALL_OK. particular operation, the grpc_call_error returned will be GRPC_CALL_OK.

@ -119,7 +119,7 @@
// libraries; it should be integrated with the `__linux__` definitions below. // libraries; it should be integrated with the `__linux__` definitions below.
#define GPR_PLATFORM_STRING "manylinux" #define GPR_PLATFORM_STRING "manylinux"
#define GPR_POSIX_CRASH_HANDLER 1 #define GPR_POSIX_CRASH_HANDLER 1
#define GPR_CPU_LINUX 1 #define GPR_CPU_POSIX 1
#define GPR_GCC_ATOMIC 1 #define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1 #define GPR_GCC_TLS 1
#define GPR_LINUX 1 #define GPR_LINUX 1

@ -1,5 +1,15 @@
framework module grpc { framework module grpc {
umbrella header "grpc.h" umbrella header "grpc.h"
header "byte_buffer_reader.h"
header "grpc_security.h"
header "grpc_security_constants.h"
header "impl/codegen/alloc.h"
header "impl/codegen/byte_buffer_reader.h"
header "support/alloc.h"
header "support/port_platform.h"
header "support/string_util.h"
export * export *
module * { export * } module * { export * }
} }

@ -1,6 +1,6 @@
{ {
"name": "grpc", "name": "grpc",
"version": "1.0.0-pre1", "version": "1.0.0-pre2",
"author": "Google Inc.", "author": "Google Inc.",
"description": "gRPC Library for Node", "description": "gRPC Library for Node",
"homepage": "http://www.grpc.io/", "homepage": "http://www.grpc.io/",

@ -10,7 +10,7 @@
<email>grpc-packages@google.com</email> <email>grpc-packages@google.com</email>
<active>yes</active> <active>yes</active>
</lead> </lead>
<date>2016-07-13</date> <date>2016-07-28</date>
<time>16:06:07</time> <time>16:06:07</time>
<version> <version>
<release>1.0.0</release> <release>1.0.0</release>
@ -22,8 +22,7 @@
</stability> </stability>
<license>BSD</license> <license>BSD</license>
<notes> <notes>
- GA release - PHP7 Support continued, reduce code duplication #7543
- Fix shutdown hang problem #4017
</notes> </notes>
<contents> <contents>
<dir baseinstalldir="/" name="/"> <dir baseinstalldir="/" name="/">
@ -47,6 +46,7 @@
<file baseinstalldir="/" name="src/php/ext/grpc/channel.h" role="src" /> <file baseinstalldir="/" name="src/php/ext/grpc/channel.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/channel_credentials.h" role="src" /> <file baseinstalldir="/" name="src/php/ext/grpc/channel_credentials.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/completion_queue.h" role="src" /> <file baseinstalldir="/" name="src/php/ext/grpc/completion_queue.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/php7_wrapper.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/php_grpc.h" role="src" /> <file baseinstalldir="/" name="src/php/ext/grpc/php_grpc.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/server.h" role="src" /> <file baseinstalldir="/" name="src/php/ext/grpc/server.h" role="src" />
<file baseinstalldir="/" name="src/php/ext/grpc/server_credentials.h" role="src" /> <file baseinstalldir="/" name="src/php/ext/grpc/server_credentials.h" role="src" />
@ -1087,8 +1087,8 @@ Update to wrap gRPC C Core version 0.10.0
</release> </release>
<release> <release>
<version> <version>
<release>1.0.0</release> <release>1.0.0RC1</release>
<api>1.0.0</api> <api>1.0.0RC1</api>
</version> </version>
<stability> <stability>
<release>stable</release> <release>stable</release>
@ -1101,5 +1101,35 @@ Update to wrap gRPC C Core version 0.10.0
- Fix shutdown hang problem #4017 - Fix shutdown hang problem #4017
</notes> </notes>
</release> </release>
<release>
<version>
<release>1.0.0RC2</release>
<api>1.0.0RC2</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2016-07-21</date>
<license>BSD</license>
<notes>
- PHP7 Support #7464
</notes>
</release>
<release>
<version>
<release>1.0.0RC3</release>
<api>1.0.0RC3</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2016-07-28</date>
<license>BSD</license>
<notes>
- PHP7 Support continued, reduce code duplication #7543
</notes>
</release>
</changelog> </changelog>
</package> </package>

@ -3,6 +3,6 @@ coverage>=4.0
cython>=0.23 cython>=0.23
enum34>=1.0.4 enum34>=1.0.4
futures>=2.2.0 futures>=2.2.0
protobuf>=3.0.0a3 protobuf>=3.0.0
six>=1.10 six>=1.10
wheel>=0.29 wheel>=0.29

@ -9,5 +9,5 @@ build_base=python_build
[build_ext] [build_ext]
inplace=1 inplace=1
[build_proto_modules] [build_package_protos]
exclude=.*protoc_plugin/protoc_plugin_test\.proto$ exclude=.*protoc_plugin/protoc_plugin_test\.proto$

@ -29,17 +29,18 @@
"""A setup module for the GRPC Python package.""" """A setup module for the GRPC Python package."""
from distutils import extension as _extension
from distutils import util
import os import os
import os.path import os.path
import pkg_resources
import platform import platform
import re
import shlex import shlex
import shutil import shutil
import sys import sys
import sysconfig import sysconfig
from distutils import core as _core
from distutils import extension as _extension
import pkg_resources
import setuptools import setuptools
from setuptools.command import egg_info from setuptools.command import egg_info
@ -47,10 +48,10 @@ from setuptools.command import egg_info
egg_info.manifest_maker.template = 'PYTHON-MANIFEST.in' egg_info.manifest_maker.template = 'PYTHON-MANIFEST.in'
PY3 = sys.version_info.major == 3 PY3 = sys.version_info.major == 3
PYTHON_STEM = './src/python/grpcio' PYTHON_STEM = os.path.join('src', 'python', 'grpcio')
CORE_INCLUDE = ('./include', '.',) CORE_INCLUDE = ('include', '.',)
BORINGSSL_INCLUDE = ('./third_party/boringssl/include',) BORINGSSL_INCLUDE = (os.path.join('third_party', 'boringssl', 'include'),)
ZLIB_INCLUDE = ('./third_party/zlib',) ZLIB_INCLUDE = (os.path.join('third_party', 'zlib'),)
# Ensure we're in the proper directory whether or not we're being used by pip. # Ensure we're in the proper directory whether or not we're being used by pip.
os.chdir(os.path.dirname(os.path.abspath(__file__))) os.chdir(os.path.dirname(os.path.abspath(__file__)))
@ -62,8 +63,8 @@ import commands
import grpc_core_dependencies import grpc_core_dependencies
import grpc_version import grpc_version
# TODO(atash) make this conditional on being on a mingw32 build if 'win32' in sys.platform:
_unixccompiler_patch.monkeypatch_unix_compiler() _unixccompiler_patch.monkeypatch_unix_compiler()
LICENSE = '3-clause BSD' LICENSE = '3-clause BSD'
@ -105,7 +106,9 @@ if not "win32" in sys.platform:
if "win32" in sys.platform: if "win32" in sys.platform:
EXTENSION_LIBRARIES += ('ws2_32',) EXTENSION_LIBRARIES += ('ws2_32',)
DEFINE_MACROS = (('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600), ('GPR_BACKWARDS_COMPATIBILITY_MODE', 1),) DEFINE_MACROS = (
('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600),
('GPR_BACKWARDS_COMPATIBILITY_MODE', 1),)
if "win32" in sys.platform: if "win32" in sys.platform:
DEFINE_MACROS += (('OPENSSL_WINDOWS', 1), ('WIN32_LEAN_AND_MEAN', 1),) DEFINE_MACROS += (('OPENSSL_WINDOWS', 1), ('WIN32_LEAN_AND_MEAN', 1),)
if '64bit' in platform.architecture()[0]: if '64bit' in platform.architecture()[0]:
@ -132,6 +135,10 @@ if 'darwin' in sys.platform and PY3:
if mac_target and (pkg_resources.parse_version(mac_target) < if mac_target and (pkg_resources.parse_version(mac_target) <
pkg_resources.parse_version('10.7.0')): pkg_resources.parse_version('10.7.0')):
os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.7' os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.7'
os.environ['_PYTHON_HOST_PLATFORM'] = re.sub(
r'macosx-[0-9]+\.[0-9]+-(.+)',
r'macosx-10.7-\1',
util.get_platform())
def cython_extensions(module_names, extra_sources, include_dirs, def cython_extensions(module_names, extra_sources, include_dirs,
@ -182,7 +189,7 @@ INSTALL_REQUIRES = (
'futures>=2.2.0', 'futures>=2.2.0',
# TODO(atash): eventually split the grpcio package into a metapackage # TODO(atash): eventually split the grpcio package into a metapackage
# depending on protobuf and the runtime component (independent of protobuf) # depending on protobuf and the runtime component (independent of protobuf)
'protobuf>=3.0.0a3', 'protobuf>=3.0.0',
) )
SETUP_REQUIRES = INSTALL_REQUIRES + ( SETUP_REQUIRES = INSTALL_REQUIRES + (
@ -200,12 +207,13 @@ COMMAND_CLASS = {
} }
# Ensure that package data is copied over before any commands have been run: # Ensure that package data is copied over before any commands have been run:
credentials_dir = os.path.join(PYTHON_STEM, 'grpc/_cython/_credentials') credentials_dir = os.path.join(PYTHON_STEM, 'grpc', '_cython', '_credentials')
try: try:
os.mkdir(credentials_dir) os.mkdir(credentials_dir)
except OSError: except OSError:
pass pass
shutil.copyfile('etc/roots.pem', os.path.join(credentials_dir, 'roots.pem')) shutil.copyfile(os.path.join('etc', 'roots.pem'),
os.path.join(credentials_dir, 'roots.pem'))
PACKAGE_DATA = { PACKAGE_DATA = {
# Binaries that may or may not be present in the final installation, but are # Binaries that may or may not be present in the final installation, but are

@ -48,7 +48,7 @@ inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
file->name().find_last_of(".proto") == file->name().size() - 1) { file->name().find_last_of(".proto") == file->name().size() - 1) {
*file_name_or_error = *file_name_or_error =
file->name().substr(0, file->name().size() - proto_suffix_length) + file->name().substr(0, file->name().size() - proto_suffix_length) +
"_services.rb"; "_services_pb.rb";
return true; return true;
} else { } else {
*file_name_or_error = "Invalid proto file name: must end with .proto"; *file_name_or_error = "Invalid proto file name: must end with .proto";
@ -58,7 +58,7 @@ inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
inline grpc::string MessagesRequireName( inline grpc::string MessagesRequireName(
const grpc::protobuf::FileDescriptor *file) { const grpc::protobuf::FileDescriptor *file) {
return Replace(file->name(), ".proto", ""); return Replace(file->name(), ".proto", "_pb");
} }
// Get leading or trailing comments in a string. Comment lines start with "# ". // Get leading or trailing comments in a string. Comment lines start with "# ".

@ -91,11 +91,13 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
connector *c = arg; connector *c = arg;
grpc_closure *notify; grpc_closure *notify;
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
grpc_error *error = GRPC_ERROR_NONE;
if (c->connecting_endpoint == NULL) { if (c->connecting_endpoint == NULL) {
memset(c->result, 0, sizeof(*c->result)); memset(c->result, 0, sizeof(*c->result));
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
} else if (status != GRPC_SECURITY_OK) { } else if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, "Secure handshake failed with error %d.", status); error = grpc_error_set_int(GRPC_ERROR_CREATE("Secure handshake failed"),
GRPC_ERROR_INT_SECURITY_STATUS, status);
memset(c->result, 0, sizeof(*c->result)); memset(c->result, 0, sizeof(*c->result));
c->connecting_endpoint = NULL; c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
@ -113,7 +115,7 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
} }
notify = c->notify; notify = c->notify;
c->notify = NULL; c->notify = NULL;
grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_NONE, NULL); grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
} }
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,

@ -36,11 +36,14 @@
#include "src/core/lib/debug/trace.h" #include "src/core/lib/debug/trace.h"
#include "src/core/lib/transport/metadata.h" #include "src/core/lib/transport/metadata.h"
extern int grpc_http_write_state_trace;
void grpc_chttp2_plugin_init(void) { void grpc_chttp2_plugin_init(void) {
grpc_chttp2_base64_encode_and_huffman_compress = grpc_chttp2_base64_encode_and_huffman_compress =
grpc_chttp2_base64_encode_and_huffman_compress_impl; grpc_chttp2_base64_encode_and_huffman_compress_impl;
grpc_register_tracer("http", &grpc_http_trace); grpc_register_tracer("http", &grpc_http_trace);
grpc_register_tracer("flowctl", &grpc_flowctl_trace); grpc_register_tracer("flowctl", &grpc_flowctl_trace);
grpc_register_tracer("http_write_state", &grpc_http_write_state_trace);
} }
void grpc_chttp2_plugin_shutdown(void) {} void grpc_chttp2_plugin_shutdown(void) {}

@ -48,6 +48,7 @@
#include "src/core/ext/transport/chttp2/transport/status_conversion.h" #include "src/core/ext/transport/chttp2/transport/status_conversion.h"
#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h" #include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
#include "src/core/lib/http/parser.h" #include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/workqueue.h"
#include "src/core/lib/profiling/timers.h" #include "src/core/lib/profiling/timers.h"
#include "src/core/lib/support/string.h" #include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/static_metadata.h"
@ -60,9 +61,9 @@
#define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024) #define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024)
#define MAX_CLIENT_STREAM_ID 0x7fffffffu #define MAX_CLIENT_STREAM_ID 0x7fffffffu
int grpc_http_trace = 0; int grpc_http_trace = 0;
int grpc_flowctl_trace = 0; int grpc_flowctl_trace = 0;
int grpc_http_write_state_trace = 0;
#define TRANSPORT_FROM_WRITING(tw) \ #define TRANSPORT_FROM_WRITING(tw) \
((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \ ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
@ -88,10 +89,16 @@ static const grpc_transport_vtable vtable;
static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error); static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
static void initiate_writing(grpc_exec_ctx *exec_ctx, void *t,
grpc_error *error);
static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_error *error);
/** Set a transport level setting, and push it to our peer */ /** Set a transport level setting, and push it to our peer */
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
uint32_t value); grpc_chttp2_setting_id id, uint32_t value);
/** Start disconnection chain */ /** Start disconnection chain */
static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@ -137,7 +144,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global); grpc_chttp2_transport_global *transport_global);
static void incoming_byte_stream_update_flow_control( static void incoming_byte_stream_update_flow_control(
grpc_chttp2_transport_global *transport_global, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, size_t max_size_hint, grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
size_t have_already); size_t have_already);
static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx, static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
@ -201,6 +208,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
gpr_free(t); gpr_free(t);
} }
/*#define REFCOUNTING_DEBUG 1*/
#ifdef REFCOUNTING_DEBUG #ifdef REFCOUNTING_DEBUG
#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__) #define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__) #define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__)
@ -231,7 +239,7 @@ static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
const grpc_channel_args *channel_args, const grpc_channel_args *channel_args,
grpc_endpoint *ep, uint8_t is_client) { grpc_endpoint *ep, bool is_client) {
size_t i; size_t i;
int j; int j;
@ -273,6 +281,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_closure_init(&t->writing_action, writing_action, t); grpc_closure_init(&t->writing_action, writing_action, t);
grpc_closure_init(&t->reading_action, reading_action, t); grpc_closure_init(&t->reading_action, reading_action, t);
grpc_closure_init(&t->parsing_action, parsing_action, t); grpc_closure_init(&t->parsing_action, parsing_action, t);
grpc_closure_init(&t->initiate_writing, initiate_writing, t);
gpr_slice_buffer_init(&t->parsing.qbuf); gpr_slice_buffer_init(&t->parsing.qbuf);
grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser); grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
@ -286,6 +295,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_slice_buffer_add( gpr_slice_buffer_add(
&t->global.qbuf, &t->global.qbuf,
gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING)); gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "initial_write");
} }
/* 8 is a random stab in the dark as to a good initial size: it's small enough /* 8 is a random stab in the dark as to a good initial size: it's small enough
that it shouldn't waste memory for infrequently used connections, yet that it shouldn't waste memory for infrequently used connections, yet
@ -311,11 +321,12 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
/* configure http2 the way we like it */ /* configure http2 the way we like it */
if (is_client) { if (is_client) {
push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0); push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0); push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
} }
push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW); push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, DEFAULT_WINDOW);
push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
DEFAULT_MAX_HEADER_LIST_SIZE); DEFAULT_MAX_HEADER_LIST_SIZE);
if (channel_args) { if (channel_args) {
@ -329,7 +340,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_log(GPR_ERROR, "%s: must be an integer", gpr_log(GPR_ERROR, "%s: must be an integer",
GRPC_ARG_MAX_CONCURRENT_STREAMS); GRPC_ARG_MAX_CONCURRENT_STREAMS);
} else { } else {
push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
(uint32_t)channel_args->args[i].value.integer); (uint32_t)channel_args->args[i].value.integer);
} }
} else if (0 == strcmp(channel_args->args[i].key, } else if (0 == strcmp(channel_args->args[i].key,
@ -368,7 +379,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_log(GPR_ERROR, "%s: must be non-negative", gpr_log(GPR_ERROR, "%s: must be non-negative",
GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER); GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER);
} else { } else {
push_setting(t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE, push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE,
(uint32_t)channel_args->args[i].value.integer); (uint32_t)channel_args->args[i].value.integer);
} }
} else if (0 == strcmp(channel_args->args[i].key, } else if (0 == strcmp(channel_args->args[i].key,
@ -393,7 +404,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
gpr_log(GPR_ERROR, "%s: must be non-negative", gpr_log(GPR_ERROR, "%s: must be non-negative",
GRPC_ARG_MAX_METADATA_SIZE); GRPC_ARG_MAX_METADATA_SIZE);
} else { } else {
push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, push_setting(exec_ctx, t, GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
(uint32_t)channel_args->args[i].value.integer); (uint32_t)channel_args->args[i].value.integer);
} }
} }
@ -444,6 +455,9 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_error *error) { grpc_error *error) {
if (!t->closed) { if (!t->closed) {
if (grpc_http_write_state_trace) {
gpr_log(GPR_DEBUG, "W:%p close transport", t);
}
t->closed = 1; t->closed = 1;
connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN, connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_REF(error), "close_transport"); GRPC_ERROR_REF(error), "close_transport");
@ -590,7 +604,8 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_metadata_buffer_destroy( grpc_chttp2_incoming_metadata_buffer_destroy(
&s->global.received_trailing_metadata); &s->global.received_trailing_metadata);
gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer); gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer);
GRPC_ERROR_UNREF(s->global.removal_error); GRPC_ERROR_UNREF(s->global.read_closed_error);
GRPC_ERROR_UNREF(s->global.write_closed_error);
UNREF_TRANSPORT(exec_ctx, t, "stream"); UNREF_TRANSPORT(exec_ctx, t, "stream");
@ -634,6 +649,36 @@ grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
* LOCK MANAGEMENT * LOCK MANAGEMENT
*/ */
static const char *write_state_name(grpc_chttp2_write_state state) {
switch (state) {
case GRPC_CHTTP2_WRITING_INACTIVE:
return "INACTIVE";
case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
return "REQUESTED[p=0]";
case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
return "REQUESTED[p=1]";
case GRPC_CHTTP2_WRITE_SCHEDULED:
return "SCHEDULED";
case GRPC_CHTTP2_WRITING:
return "WRITING";
case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
return "WRITING[p=1]";
case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
return "WRITING[p=0]";
}
GPR_UNREACHABLE_CODE(return "UNKNOWN");
}
static void set_write_state(grpc_chttp2_transport *t,
grpc_chttp2_write_state state, const char *reason) {
if (grpc_http_write_state_trace) {
gpr_log(GPR_DEBUG, "W:%p %s -> %s because %s", t,
write_state_name(t->executor.write_state), write_state_name(state),
reason);
}
t->executor.write_state = state;
}
static void finish_global_actions(grpc_exec_ctx *exec_ctx, static void finish_global_actions(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) { grpc_chttp2_transport *t) {
grpc_chttp2_executor_action_header *hdr; grpc_chttp2_executor_action_header *hdr;
@ -642,13 +687,6 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
GPR_TIMER_BEGIN("finish_global_actions", 0); GPR_TIMER_BEGIN("finish_global_actions", 0);
for (;;) { for (;;) {
if (!t->executor.writing_active && !t->closed &&
grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
t->executor.writing_active = 1;
REF_TRANSPORT(t, "writing");
prevent_endpoint_shutdown(t);
grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
}
check_read_ops(exec_ctx, &t->global); check_read_ops(exec_ctx, &t->global);
gpr_mu_lock(&t->executor.mu); gpr_mu_lock(&t->executor.mu);
@ -669,8 +707,28 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
continue; continue;
} else { } else {
t->executor.global_active = false; t->executor.global_active = false;
switch (t->executor.write_state) {
case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "unlocking");
REF_TRANSPORT(t, "initiate_writing");
gpr_mu_unlock(&t->executor.mu);
grpc_exec_ctx_sched(
exec_ctx, &t->initiate_writing, GRPC_ERROR_NONE,
t->ep != NULL ? grpc_endpoint_get_workqueue(t->ep) : NULL);
break;
case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
start_writing(exec_ctx, t);
gpr_mu_unlock(&t->executor.mu);
break;
case GRPC_CHTTP2_WRITING_INACTIVE:
case GRPC_CHTTP2_WRITING:
case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
case GRPC_CHTTP2_WRITE_SCHEDULED:
gpr_mu_unlock(&t->executor.mu);
break;
}
} }
gpr_mu_unlock(&t->executor.mu);
break; break;
} }
@ -741,16 +799,118 @@ void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
* OUTPUT PROCESSING * OUTPUT PROCESSING
*/ */
void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global, void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global) { grpc_chttp2_transport_global *transport_global,
bool covered_by_poller, const char *reason) {
/* Perform state checks, and transition to a scheduled state if appropriate.
Each time we finish the global lock execution, we check if we need to
write. If we do:
- (if there is a poller surrounding the write) schedule
initiate_writing, which locks and calls initiate_writing_locked to...
- call start_writing, which verifies (under the global lock) that there
are things that need to be written by calling
grpc_chttp2_unlocking_check_writes, and if so schedules writing_action
against the current exec_ctx, to be executed OUTSIDE of the global lock
- eventually writing_action results in grpc_chttp2_terminate_writing being
called, which re-takes the global lock, updates state, checks if we need
to do *another* write immediately, and if so loops back to
start_writing.
Current problems:
- too much lock entry/exiting
- the writing thread can become stuck indefinitely (punt through the
workqueue periodically to fix) */
grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global);
switch (t->executor.write_state) {
case GRPC_CHTTP2_WRITING_INACTIVE:
set_write_state(t, covered_by_poller
? GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER
: GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
reason);
break;
case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
/* nothing to do: write already requested */
break;
case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
if (covered_by_poller) {
/* upgrade to note poller is available to cover the write */
set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER, reason);
}
break;
case GRPC_CHTTP2_WRITE_SCHEDULED:
/* nothing to do: write already scheduled */
break;
case GRPC_CHTTP2_WRITING:
set_write_state(t,
covered_by_poller ? GRPC_CHTTP2_WRITING_STALE_WITH_POLLER
: GRPC_CHTTP2_WRITING_STALE_NO_POLLER,
reason);
break;
case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
/* nothing to do: write already requested */
break;
case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
if (covered_by_poller) {
/* upgrade to note poller is available to cover the write */
set_write_state(t, GRPC_CHTTP2_WRITING_STALE_WITH_POLLER, reason);
}
break;
}
}
static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED ||
t->executor.write_state == GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER);
if (!t->closed &&
grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
set_write_state(t, GRPC_CHTTP2_WRITING, "start_writing");
REF_TRANSPORT(t, "writing");
prevent_endpoint_shutdown(t);
grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
} else {
if (t->closed) {
set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE,
"start_writing:transport_closed");
} else {
set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE,
"start_writing:nothing_to_write");
}
end_waiting_for_write(exec_ctx, t, GRPC_ERROR_CREATE("Nothing to write"));
if (t->ep && !t->endpoint_reading) {
destroy_endpoint(exec_ctx, t);
}
}
}
static void initiate_writing_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused,
void *arg_ignored) {
start_writing(exec_ctx, t);
UNREF_TRANSPORT(exec_ctx, t, "initiate_writing");
}
static void initiate_writing(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_chttp2_run_with_global_lock(exec_ctx, arg, NULL, initiate_writing_locked,
NULL, 0);
}
void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
bool covered_by_poller, const char *reason) {
if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed && if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed &&
grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) { grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing"); GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
grpc_chttp2_initiate_write(exec_ctx, transport_global, covered_by_poller,
reason);
} }
} }
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
uint32_t value) { grpc_chttp2_setting_id id, uint32_t value) {
const grpc_chttp2_setting_parameters *sp = const grpc_chttp2_setting_parameters *sp =
&grpc_chttp2_settings_parameters[id]; &grpc_chttp2_settings_parameters[id];
uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value); uint32_t use_value = GPR_CLAMP(value, sp->min_value, sp->max_value);
@ -761,9 +921,22 @@ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) { if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) {
t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value; t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value;
t->global.dirtied_local_settings = 1; t->global.dirtied_local_settings = 1;
grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "push_setting");
} }
} }
static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_error *error) {
grpc_chttp2_stream_global *stream_global;
while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
&stream_global)) {
fail_pending_writes(exec_ctx, &t->global, stream_global,
GRPC_ERROR_REF(error));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
}
GRPC_ERROR_UNREF(error);
}
static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx, static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_chttp2_stream *s_ignored, grpc_chttp2_stream *s_ignored,
@ -778,24 +951,32 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing); grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
grpc_chttp2_stream_global *stream_global; end_waiting_for_write(exec_ctx, t, error);
while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
&stream_global)) { switch (t->executor.write_state) {
fail_pending_writes(exec_ctx, &t->global, stream_global, case GRPC_CHTTP2_WRITING_INACTIVE:
GRPC_ERROR_REF(error)); case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes"); case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
case GRPC_CHTTP2_WRITE_SCHEDULED:
GPR_UNREACHABLE_CODE(break);
case GRPC_CHTTP2_WRITING:
set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "terminate_writing");
break;
case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
"terminate_writing");
break;
case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
"terminate_writing");
break;
} }
/* leave the writing flag up on shutdown to prevent further writes in
unlock()
from starting */
t->executor.writing_active = 0;
if (t->ep && !t->endpoint_reading) { if (t->ep && !t->endpoint_reading) {
destroy_endpoint(exec_ctx, t); destroy_endpoint(exec_ctx, t);
} }
UNREF_TRANSPORT(exec_ctx, t, "writing"); UNREF_TRANSPORT(exec_ctx, t, "writing");
GRPC_ERROR_UNREF(error);
} }
void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
@ -878,7 +1059,8 @@ static void maybe_start_some_streams(
stream_global->id, STREAM_FROM_GLOBAL(stream_global)); stream_global->id, STREAM_FROM_GLOBAL(stream_global));
stream_global->in_stream_map = true; stream_global->in_stream_map = true;
transport_global->concurrent_stream_count++; transport_global->concurrent_stream_count++;
grpc_chttp2_become_writable(transport_global, stream_global); grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, true,
"new_stream");
} }
/* cancel out streams that will never be started */ /* cancel out streams that will never be started */
while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID && while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
@ -1018,9 +1200,11 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
maybe_start_some_streams(exec_ctx, transport_global); maybe_start_some_streams(exec_ctx, transport_global);
} else { } else {
GPR_ASSERT(stream_global->id != 0); GPR_ASSERT(stream_global->id != 0);
grpc_chttp2_become_writable(transport_global, stream_global); grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
true, "op.send_initial_metadata");
} }
} else { } else {
stream_global->send_trailing_metadata = NULL;
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, transport_global, stream_global, exec_ctx, transport_global, stream_global,
&stream_global->send_initial_metadata_finished, &stream_global->send_initial_metadata_finished,
@ -1042,7 +1226,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
} else { } else {
stream_global->send_message = op->send_message; stream_global->send_message = op->send_message;
if (stream_global->id != 0) { if (stream_global->id != 0) {
grpc_chttp2_become_writable(transport_global, stream_global); grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
true, "op.send_message");
} }
} }
} }
@ -1075,6 +1260,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
} }
if (stream_global->write_closed) { if (stream_global->write_closed) {
stream_global->send_trailing_metadata = NULL;
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, transport_global, stream_global, exec_ctx, transport_global, stream_global,
&stream_global->send_trailing_metadata_finished, &stream_global->send_trailing_metadata_finished,
@ -1085,7 +1271,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
} else if (stream_global->id != 0) { } else if (stream_global->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding /* TODO(ctiller): check if there's flow control for any outstanding
bytes before going writable */ bytes before going writable */
grpc_chttp2_become_writable(transport_global, stream_global); grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
true, "op.send_trailing_metadata");
} }
} }
} }
@ -1106,8 +1293,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
(stream_global->incoming_frames.head == NULL || (stream_global->incoming_frames.head == NULL ||
stream_global->incoming_frames.head->is_tail)) { stream_global->incoming_frames.head->is_tail)) {
incoming_byte_stream_update_flow_control( incoming_byte_stream_update_flow_control(
transport_global, stream_global, transport_global->stream_lookahead, exec_ctx, transport_global, stream_global,
0); transport_global->stream_lookahead, 0);
} }
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
} }
@ -1135,7 +1322,8 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
sizeof(*op)); sizeof(*op));
} }
static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) { static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_closure *on_recv) {
grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p)); grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p));
p->next = &t->global.pings; p->next = &t->global.pings;
p->prev = p->next->prev; p->prev = p->next->prev;
@ -1150,6 +1338,7 @@ static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
p->id[7] = (uint8_t)(t->global.ping_counter & 0xff); p->id[7] = (uint8_t)(t->global.ping_counter & 0xff);
p->on_recv = on_recv; p->on_recv = on_recv;
gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id)); gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
grpc_chttp2_initiate_write(exec_ctx, &t->global, true, "send_ping");
} }
static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@ -1209,6 +1398,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
close_transport = grpc_chttp2_has_streams(t) close_transport = grpc_chttp2_has_streams(t)
? GRPC_ERROR_NONE ? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE("GOAWAY sent"); : GRPC_ERROR_CREATE("GOAWAY sent");
grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "goaway_sent");
} }
if (op->set_accept_stream) { if (op->set_accept_stream) {
@ -1226,7 +1416,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
} }
if (op->send_ping) { if (op->send_ping) {
send_ping_locked(t, op->send_ping); send_ping_locked(exec_ctx, t, op->send_ping);
} }
if (close_transport != GRPC_ERROR_NONE) { if (close_transport != GRPC_ERROR_NONE) {
@ -1414,6 +1604,8 @@ static void cancel_from_api(grpc_exec_ctx *exec_ctx,
&transport_global->qbuf, &transport_global->qbuf,
grpc_chttp2_rst_stream_create(stream_global->id, (uint32_t)http_error, grpc_chttp2_rst_stream_create(stream_global->id, (uint32_t)http_error,
&stream_global->stats.outgoing)); &stream_global->stats.outgoing));
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"rst_stream");
} }
const char *msg = const char *msg =
@ -1473,10 +1665,39 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
} }
} }
static void add_error(grpc_error *error, grpc_error **refs, size_t *nrefs) {
if (error == GRPC_ERROR_NONE) return;
for (size_t i = 0; i < *nrefs; i++) {
if (error == refs[i]) {
return;
}
}
refs[*nrefs] = error;
++*nrefs;
}
static grpc_error *removal_error(grpc_error *extra_error,
grpc_chttp2_stream_global *stream_global) {
grpc_error *refs[3];
size_t nrefs = 0;
add_error(stream_global->read_closed_error, refs, &nrefs);
add_error(stream_global->write_closed_error, refs, &nrefs);
add_error(extra_error, refs, &nrefs);
grpc_error *error = GRPC_ERROR_NONE;
if (nrefs > 0) {
error = GRPC_ERROR_CREATE_REFERENCING("Failed due to stream removal", refs,
nrefs);
}
GRPC_ERROR_UNREF(extra_error);
return error;
}
static void fail_pending_writes(grpc_exec_ctx *exec_ctx, static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, grpc_chttp2_stream_global *stream_global,
grpc_error *error) { grpc_error *error) {
error = removal_error(error, stream_global);
stream_global->send_message = NULL;
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, transport_global, stream_global, exec_ctx, transport_global, stream_global,
&stream_global->send_initial_metadata_finished, GRPC_ERROR_REF(error)); &stream_global->send_initial_metadata_finished, GRPC_ERROR_REF(error));
@ -1499,14 +1720,17 @@ void grpc_chttp2_mark_stream_closed(
} }
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
if (close_reads && !stream_global->read_closed) { if (close_reads && !stream_global->read_closed) {
stream_global->read_closed_error = GRPC_ERROR_REF(error);
stream_global->read_closed = true; stream_global->read_closed = true;
stream_global->published_initial_metadata = true; stream_global->published_initial_metadata = true;
stream_global->published_trailing_metadata = true; stream_global->published_trailing_metadata = true;
decrement_active_streams_locked(exec_ctx, transport_global, stream_global); decrement_active_streams_locked(exec_ctx, transport_global, stream_global);
} }
if (close_writes && !stream_global->write_closed) { if (close_writes && !stream_global->write_closed) {
stream_global->write_closed_error = GRPC_ERROR_REF(error);
stream_global->write_closed = true; stream_global->write_closed = true;
if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.writing_active) { if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.write_state !=
GRPC_CHTTP2_WRITING_INACTIVE) {
GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes"); GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
grpc_chttp2_list_add_closed_waiting_for_writing(transport_global, grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
stream_global); stream_global);
@ -1516,7 +1740,6 @@ void grpc_chttp2_mark_stream_closed(
} }
} }
if (stream_global->read_closed && stream_global->write_closed) { if (stream_global->read_closed && stream_global->write_closed) {
stream_global->removal_error = GRPC_ERROR_REF(error);
if (stream_global->id != 0 && if (stream_global->id != 0 &&
TRANSPORT_FROM_GLOBAL(transport_global)->executor.parsing_active) { TRANSPORT_FROM_GLOBAL(transport_global)->executor.parsing_active) {
grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global, grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
@ -1524,7 +1747,8 @@ void grpc_chttp2_mark_stream_closed(
} else { } else {
if (stream_global->id != 0) { if (stream_global->id != 0) {
remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global), remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
stream_global->id, GRPC_ERROR_REF(error)); stream_global->id,
removal_error(GRPC_ERROR_REF(error), stream_global));
} }
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
} }
@ -1649,6 +1873,8 @@ static void close_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
1, error); 1, error);
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"close_from_api");
} }
typedef struct { typedef struct {
@ -1678,8 +1904,14 @@ static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
} }
/** update window from a settings change */ /** update window from a settings change */
typedef struct {
grpc_chttp2_transport *t;
grpc_exec_ctx *exec_ctx;
} update_global_window_args;
static void update_global_window(void *args, uint32_t id, void *stream) { static void update_global_window(void *args, uint32_t id, void *stream) {
grpc_chttp2_transport *t = args; update_global_window_args *a = args;
grpc_chttp2_transport *t = a->t;
grpc_chttp2_stream *s = stream; grpc_chttp2_stream *s = stream;
grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_transport_global *transport_global = &t->global;
grpc_chttp2_stream_global *stream_global = &s->global; grpc_chttp2_stream_global *stream_global = &s->global;
@ -1693,7 +1925,8 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
is_zero = stream_global->outgoing_window <= 0; is_zero = stream_global->outgoing_window <= 0;
if (was_zero && !is_zero) { if (was_zero && !is_zero) {
grpc_chttp2_become_writable(transport_global, stream_global); grpc_chttp2_become_writable(a->exec_ctx, transport_global, stream_global,
true, "update_global_window");
} }
} }
@ -1801,14 +2034,19 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_transport_global *transport_global = &t->global;
grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
/* copy parsing qbuf to global qbuf */ /* copy parsing qbuf to global qbuf */
gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf); if (t->parsing.qbuf.count > 0) {
gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"parsing_qbuf");
}
/* merge stream lists */ /* merge stream lists */
grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map); grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map);
transport_global->concurrent_stream_count = transport_global->concurrent_stream_count =
(uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map); (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
if (transport_parsing->initial_window_update != 0) { if (transport_parsing->initial_window_update != 0) {
update_global_window_args args = {t, exec_ctx};
grpc_chttp2_stream_map_for_each(&t->parsing_stream_map, grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
update_global_window, t); update_global_window, &args);
transport_parsing->initial_window_update = 0; transport_parsing->initial_window_update = 0;
} }
/* handle higher level things */ /* handle higher level things */
@ -1831,7 +2069,7 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GPR_ASSERT(stream_global->write_closed); GPR_ASSERT(stream_global->write_closed);
GPR_ASSERT(stream_global->read_closed); GPR_ASSERT(stream_global->read_closed);
remove_stream(exec_ctx, t, stream_global->id, remove_stream(exec_ctx, t, stream_global->id,
GRPC_ERROR_REF(stream_global->removal_error)); removal_error(GRPC_ERROR_NONE, stream_global));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
} }
@ -1854,11 +2092,12 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
} }
drop_connection(exec_ctx, t, GRPC_ERROR_REF(error)); drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
t->endpoint_reading = 0; t->endpoint_reading = 0;
if (!t->executor.writing_active && t->ep) { if (grpc_http_write_state_trace) {
grpc_endpoint_destroy(exec_ctx, t->ep); gpr_log(GPR_DEBUG, "R:%p -> 0 ws=%s", t,
t->ep = NULL; write_state_name(t->executor.write_state));
/* safe as we still have a ref for read */ }
UNREF_TRANSPORT(exec_ctx, t, "disconnect"); if (t->executor.write_state == GRPC_CHTTP2_WRITING_INACTIVE && t->ep) {
destroy_endpoint(exec_ctx, t);
} }
} else if (!t->closed) { } else if (!t->closed) {
keep_reading = true; keep_reading = true;
@ -1942,7 +2181,7 @@ static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
} }
static void incoming_byte_stream_update_flow_control( static void incoming_byte_stream_update_flow_control(
grpc_chttp2_transport_global *transport_global, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, size_t max_size_hint, grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
size_t have_already) { size_t have_already) {
uint32_t max_recv_bytes; uint32_t max_recv_bytes;
@ -1977,7 +2216,8 @@ static void incoming_byte_stream_update_flow_control(
add_max_recv_bytes); add_max_recv_bytes);
grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global, grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global,
stream_global); stream_global);
grpc_chttp2_become_writable(transport_global, stream_global); grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
false, "read_incoming_stream");
} }
} }
@ -1999,8 +2239,9 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global = &bs->stream->global; grpc_chttp2_stream_global *stream_global = &bs->stream->global;
if (bs->is_tail) { if (bs->is_tail) {
incoming_byte_stream_update_flow_control( incoming_byte_stream_update_flow_control(exec_ctx, transport_global,
transport_global, stream_global, arg->max_size_hint, bs->slices.length); stream_global, arg->max_size_hint,
bs->slices.length);
} }
if (bs->slices.count > 0) { if (bs->slices.count > 0) {
*arg->slice = gpr_slice_buffer_take_first(&bs->slices); *arg->slice = gpr_slice_buffer_take_first(&bs->slices);
@ -2184,7 +2425,7 @@ static char *format_flowctl_context_var(const char *context, const char *var,
if (context == NULL) { if (context == NULL) {
*scope = NULL; *scope = NULL;
gpr_asprintf(&buf, "%s(%" PRId64 ")", var, val); gpr_asprintf(&buf, "%s(%" PRId64 ")", var, val);
result = gpr_leftpad(buf, ' ', 40); result = gpr_leftpad(buf, ' ', 60);
gpr_free(buf); gpr_free(buf);
return result; return result;
} }
@ -2197,7 +2438,7 @@ static char *format_flowctl_context_var(const char *context, const char *var,
gpr_free(tmp); gpr_free(tmp);
} }
gpr_asprintf(&buf, "%s.%s(%" PRId64 ")", underscore_pos + 1, var, val); gpr_asprintf(&buf, "%s.%s(%" PRId64 ")", underscore_pos + 1, var, val);
result = gpr_leftpad(buf, ' ', 40); result = gpr_leftpad(buf, ' ', 60);
gpr_free(buf); gpr_free(buf);
return result; return result;
} }
@ -2230,7 +2471,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
tmp_phase = gpr_leftpad(phase, ' ', 8); tmp_phase = gpr_leftpad(phase, ' ', 8);
tmp_scope1 = gpr_leftpad(scope1, ' ', 11); tmp_scope1 = gpr_leftpad(scope1, ' ', 11);
gpr_asprintf(&prefix, "FLOW %s: %s %s ", phase, clisvr, scope1); gpr_asprintf(&prefix, "FLOW %s: %s %s ", tmp_phase, clisvr, scope1);
gpr_free(tmp_phase); gpr_free(tmp_phase);
gpr_free(tmp_scope1); gpr_free(tmp_scope1);

@ -305,6 +305,22 @@ typedef struct grpc_chttp2_executor_action_header {
void *arg; void *arg;
} grpc_chttp2_executor_action_header; } grpc_chttp2_executor_action_header;
typedef enum {
/** no writing activity */
GRPC_CHTTP2_WRITING_INACTIVE,
/** write has been requested, but not scheduled yet */
GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
/** write has been requested and scheduled against the workqueue */
GRPC_CHTTP2_WRITE_SCHEDULED,
/** write has been initiated after being reaped from the workqueue */
GRPC_CHTTP2_WRITING,
/** write has been initiated, AND another write needs to be started once it's
done */
GRPC_CHTTP2_WRITING_STALE_WITH_POLLER,
GRPC_CHTTP2_WRITING_STALE_NO_POLLER,
} grpc_chttp2_write_state;
struct grpc_chttp2_transport { struct grpc_chttp2_transport {
grpc_transport base; /* must be first */ grpc_transport base; /* must be first */
gpr_refcount refs; gpr_refcount refs;
@ -319,10 +335,10 @@ struct grpc_chttp2_transport {
/** is a thread currently in the global lock */ /** is a thread currently in the global lock */
bool global_active; bool global_active;
/** is a thread currently writing */
bool writing_active;
/** is a thread currently parsing */ /** is a thread currently parsing */
bool parsing_active; bool parsing_active;
/** write execution state of the transport */
grpc_chttp2_write_state write_state;
grpc_chttp2_executor_action_header *pending_actions_head; grpc_chttp2_executor_action_header *pending_actions_head;
grpc_chttp2_executor_action_header *pending_actions_tail; grpc_chttp2_executor_action_header *pending_actions_tail;
@ -342,7 +358,8 @@ struct grpc_chttp2_transport {
/** global state for reading/writing */ /** global state for reading/writing */
grpc_chttp2_transport_global global; grpc_chttp2_transport_global global;
/** state only accessible by the chain of execution that /** state only accessible by the chain of execution that
set writing_active=1 */ set writing_state >= GRPC_WRITING, and only by the writing closure
chain. */
grpc_chttp2_transport_writing writing; grpc_chttp2_transport_writing writing;
/** state only accessible by the chain of execution that /** state only accessible by the chain of execution that
set parsing_active=1 */ set parsing_active=1 */
@ -363,6 +380,8 @@ struct grpc_chttp2_transport {
grpc_closure reading_action; grpc_closure reading_action;
/** closure to actually do parsing */ /** closure to actually do parsing */
grpc_closure parsing_action; grpc_closure parsing_action;
/** closure to initiate writing */
grpc_closure initiate_writing;
/** incoming read bytes */ /** incoming read bytes */
gpr_slice_buffer read_buffer; gpr_slice_buffer read_buffer;
@ -436,8 +455,10 @@ typedef struct {
bool seen_error; bool seen_error;
bool exceeded_metadata_size; bool exceeded_metadata_size;
/** the error that resulted in this stream being removed */ /** the error that resulted in this stream being read-closed */
grpc_error *removal_error; grpc_error *read_closed_error;
/** the error that resulted in this stream being write-closed */
grpc_error *write_closed_error;
bool published_initial_metadata; bool published_initial_metadata;
bool published_trailing_metadata; bool published_trailing_metadata;
@ -514,15 +535,20 @@ struct grpc_chttp2_stream {
}; };
/** Transport writing call flow: /** Transport writing call flow:
chttp2_transport.c calls grpc_chttp2_unlocking_check_writes to see if writes grpc_chttp2_initiate_write() is called anywhere that we know bytes need to
are required; go out on the wire.
if they are, chttp2_transport.c calls grpc_chttp2_perform_writes to do the If no other write has been started, a task is enqueued onto our workqueue.
writes. When that task executes, it obtains the global lock, and gathers the data
Once writes have been completed (meaning another write could potentially be to write.
started), The global lock is dropped and we do the syscall to write.
grpc_chttp2_terminate_writing is called. This will call After writing, a follow-up check is made to see if another round of writing
grpc_chttp2_cleanup_writing, at which should be performed.
point the write phase is complete. */
The actual call chain is documented in the implementation of this function.
*/
void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
bool covered_by_poller, const char *reason);
/** Someone is unlocking the transport mutex: check to see if writes /** Someone is unlocking the transport mutex: check to see if writes
are required, and schedule them if so */ are required, and schedule them if so */
@ -610,9 +636,8 @@ int grpc_chttp2_list_pop_check_read_ops(
void grpc_chttp2_list_add_writing_stalled_by_transport( void grpc_chttp2_list_add_writing_stalled_by_transport(
grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing); grpc_chttp2_stream_writing *stream_writing);
void grpc_chttp2_list_flush_writing_stalled_by_transport( bool grpc_chttp2_list_flush_writing_stalled_by_transport(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing);
bool is_window_available);
void grpc_chttp2_list_add_stalled_by_transport( void grpc_chttp2_list_add_stalled_by_transport(
grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_transport_writing *transport_writing,
@ -822,7 +847,9 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
/** add a ref to the stream and add it to the writable list; /** add a ref to the stream and add it to the writable list;
ref will be dropped in writing.c */ ref will be dropped in writing.c */
void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global, void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global); grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
bool covered_by_poller, const char *reason);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */ #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */

@ -154,10 +154,8 @@ void grpc_chttp2_publish_reads(
transport_parsing, outgoing_window); transport_parsing, outgoing_window);
is_zero = transport_global->outgoing_window <= 0; is_zero = transport_global->outgoing_window <= 0;
if (was_zero && !is_zero) { if (was_zero && !is_zero) {
while (grpc_chttp2_list_pop_stalled_by_transport(transport_global, grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
&stream_global)) { "new_global_flow_control");
grpc_chttp2_become_writable(transport_global, stream_global);
}
} }
if (transport_parsing->incoming_window < if (transport_parsing->incoming_window <
@ -168,6 +166,8 @@ void grpc_chttp2_publish_reads(
announce_incoming_window, announce_bytes); announce_incoming_window, announce_bytes);
GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing, GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing,
incoming_window, announce_bytes); incoming_window, announce_bytes);
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"global incoming window");
} }
/* for each stream that saw an update, fixup global state */ /* for each stream that saw an update, fixup global state */
@ -190,7 +190,8 @@ void grpc_chttp2_publish_reads(
outgoing_window); outgoing_window);
is_zero = stream_global->outgoing_window <= 0; is_zero = stream_global->outgoing_window <= 0;
if (was_zero && !is_zero) { if (was_zero && !is_zero) {
grpc_chttp2_become_writable(transport_global, stream_global); grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
false, "stream.read_flow_control");
} }
stream_global->max_recv_bytes -= (uint32_t)GPR_MIN( stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(

@ -329,6 +329,7 @@ void grpc_chttp2_list_add_writing_stalled_by_transport(
grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing) { grpc_chttp2_stream_writing *stream_writing) {
grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing); grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing);
gpr_log(GPR_DEBUG, "writing stalled %d", stream->global.id);
if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) { if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) {
GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled"); GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled");
} }
@ -336,27 +337,28 @@ void grpc_chttp2_list_add_writing_stalled_by_transport(
GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT); GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT);
} }
void grpc_chttp2_list_flush_writing_stalled_by_transport( bool grpc_chttp2_list_flush_writing_stalled_by_transport(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing) {
bool is_window_available) {
grpc_chttp2_stream *stream; grpc_chttp2_stream *stream;
bool out = false;
grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing); grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing);
while (stream_list_pop(transport, &stream, while (stream_list_pop(transport, &stream,
GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) { GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) {
if (is_window_available) { gpr_log(GPR_DEBUG, "move %d from writing stalled to just stalled",
grpc_chttp2_become_writable(&transport->global, &stream->global); stream->global.id);
} else { grpc_chttp2_list_add_stalled_by_transport(transport_writing,
grpc_chttp2_list_add_stalled_by_transport(transport_writing, &stream->writing);
&stream->writing);
}
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global, GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global,
"chttp2_writing_stalled"); "chttp2_writing_stalled");
out = true;
} }
return out;
} }
void grpc_chttp2_list_add_stalled_by_transport( void grpc_chttp2_list_add_stalled_by_transport(
grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing) { grpc_chttp2_stream_writing *stream_writing) {
gpr_log(GPR_DEBUG, "stalled %d", stream_writing->id);
stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
STREAM_FROM_WRITING(stream_writing), STREAM_FROM_WRITING(stream_writing),
GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT); GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);

@ -75,9 +75,13 @@ int grpc_chttp2_unlocking_check_writes(
GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window, GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
transport_global, outgoing_window); transport_global, outgoing_window);
bool is_window_available = transport_writing->outgoing_window > 0; if (transport_writing->outgoing_window > 0) {
grpc_chttp2_list_flush_writing_stalled_by_transport( while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
exec_ctx, transport_writing, is_window_available); &stream_global)) {
grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
false, "transport.read_flow_control");
}
}
/* for each grpc_chttp2_stream that's become writable, frame it's data /* for each grpc_chttp2_stream that's become writable, frame it's data
(according to available window sizes) and add to the output buffer */ (according to available window sizes) and add to the output buffer */
@ -331,6 +335,12 @@ void grpc_chttp2_cleanup_writing(
grpc_chttp2_stream_writing *stream_writing; grpc_chttp2_stream_writing *stream_writing;
grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_global *stream_global;
if (grpc_chttp2_list_flush_writing_stalled_by_transport(exec_ctx,
transport_writing)) {
grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
"resume_stalled_stream");
}
while (grpc_chttp2_list_pop_written_stream( while (grpc_chttp2_list_pop_written_stream(
transport_global, transport_writing, &stream_global, &stream_writing)) { transport_global, transport_writing, &stream_global, &stream_writing)) {
if (stream_writing->sent_initial_metadata) { if (stream_writing->sent_initial_metadata) {

@ -65,3 +65,7 @@ void grpc_endpoint_destroy(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) {
char* grpc_endpoint_get_peer(grpc_endpoint* ep) { char* grpc_endpoint_get_peer(grpc_endpoint* ep) {
return ep->vtable->get_peer(ep); return ep->vtable->get_peer(ep);
} }
grpc_workqueue* grpc_endpoint_get_workqueue(grpc_endpoint* ep) {
return ep->vtable->get_workqueue(ep);
}

@ -51,6 +51,7 @@ struct grpc_endpoint_vtable {
gpr_slice_buffer *slices, grpc_closure *cb); gpr_slice_buffer *slices, grpc_closure *cb);
void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
gpr_slice_buffer *slices, grpc_closure *cb); gpr_slice_buffer *slices, grpc_closure *cb);
grpc_workqueue *(*get_workqueue)(grpc_endpoint *ep);
void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
grpc_pollset *pollset); grpc_pollset *pollset);
void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@ -69,6 +70,9 @@ void grpc_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
char *grpc_endpoint_get_peer(grpc_endpoint *ep); char *grpc_endpoint_get_peer(grpc_endpoint *ep);
/* Retrieve a reference to the workqueue associated with this endpoint */
grpc_workqueue *grpc_endpoint_get_workqueue(grpc_endpoint *ep);
/* Write slices out to the socket. /* Write slices out to the socket.
If the connection is ready for more data after the end of the call, it If the connection is ready for more data after the end of the call, it

@ -57,6 +57,7 @@
#include "src/core/lib/iomgr/ev_posix.h" #include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/wakeup_fd_posix.h" #include "src/core/lib/iomgr/wakeup_fd_posix.h"
#include "src/core/lib/iomgr/workqueue.h"
#include "src/core/lib/profiling/timers.h" #include "src/core/lib/profiling/timers.h"
#include "src/core/lib/support/block_annotate.h" #include "src/core/lib/support/block_annotate.h"
@ -113,9 +114,7 @@ struct grpc_fd {
grpc_closure *read_closure; grpc_closure *read_closure;
grpc_closure *write_closure; grpc_closure *write_closure;
/* The polling island to which this fd belongs to and the mutex protecting the /* The polling island to which this fd belongs to (protected by mu) */
the field */
gpr_mu pi_mu;
struct polling_island *polling_island; struct polling_island *polling_island;
struct grpc_fd *freelist_next; struct grpc_fd *freelist_next;
@ -152,16 +151,17 @@ static void fd_global_shutdown(void);
* Polling island Declarations * Polling island Declarations
*/ */
// #define GRPC_PI_REF_COUNT_DEBUG //#define GRPC_PI_REF_COUNT_DEBUG
#ifdef GRPC_PI_REF_COUNT_DEBUG #ifdef GRPC_PI_REF_COUNT_DEBUG
#define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__) #define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__)
#define PI_UNREF(p, r) pi_unref_dbg((p), (r), __FILE__, __LINE__) #define PI_UNREF(exec_ctx, p, r) \
pi_unref_dbg((exec_ctx), (p), (r), __FILE__, __LINE__)
#else /* defined(GRPC_PI_REF_COUNT_DEBUG) */ #else /* defined(GRPC_PI_REF_COUNT_DEBUG) */
#define PI_ADD_REF(p, r) pi_add_ref((p)) #define PI_ADD_REF(p, r) pi_add_ref((p))
#define PI_UNREF(p, r) pi_unref((p)) #define PI_UNREF(exec_ctx, p, r) pi_unref((exec_ctx), (p))
#endif /* !defined(GPRC_PI_REF_COUNT_DEBUG) */ #endif /* !defined(GPRC_PI_REF_COUNT_DEBUG) */
@ -172,7 +172,7 @@ typedef struct polling_island {
Once the ref count becomes zero, this structure is destroyed which means Once the ref count becomes zero, this structure is destroyed which means
we should ensure that there is never a scenario where a PI_ADD_REF() is we should ensure that there is never a scenario where a PI_ADD_REF() is
racing with a PI_UNREF() that just made the ref_count zero. */ racing with a PI_UNREF() that just made the ref_count zero. */
gpr_refcount ref_count; gpr_atm ref_count;
/* Pointer to the polling_island this merged into. /* Pointer to the polling_island this merged into.
* merged_to value is only set once in polling_island's lifetime (and that too * merged_to value is only set once in polling_island's lifetime (and that too
@ -184,6 +184,9 @@ typedef struct polling_island {
* (except mu and ref_count) are invalid and must be ignored. */ * (except mu and ref_count) are invalid and must be ignored. */
gpr_atm merged_to; gpr_atm merged_to;
/* The workqueue associated with this polling island */
grpc_workqueue *workqueue;
/* The fd of the underlying epoll set */ /* The fd of the underlying epoll set */
int epoll_fd; int epoll_fd;
@ -191,11 +194,6 @@ typedef struct polling_island {
size_t fd_cnt; size_t fd_cnt;
size_t fd_capacity; size_t fd_capacity;
grpc_fd **fds; grpc_fd **fds;
/* Polling islands that are no longer needed are kept in a freelist so that
they can be reused. This field points to the next polling island in the
free list */
struct polling_island *next_free;
} polling_island; } polling_island;
/******************************************************************************* /*******************************************************************************
@ -253,13 +251,14 @@ struct grpc_pollset_set {
* Common helpers * Common helpers
*/ */
static void append_error(grpc_error **composite, grpc_error *error, static bool append_error(grpc_error **composite, grpc_error *error,
const char *desc) { const char *desc) {
if (error == GRPC_ERROR_NONE) return; if (error == GRPC_ERROR_NONE) return true;
if (*composite == GRPC_ERROR_NONE) { if (*composite == GRPC_ERROR_NONE) {
*composite = GRPC_ERROR_CREATE(desc); *composite = GRPC_ERROR_CREATE(desc);
} }
*composite = grpc_error_add_child(*composite, error); *composite = grpc_error_add_child(*composite, error);
return false;
} }
/******************************************************************************* /*******************************************************************************
@ -275,11 +274,8 @@ static void append_error(grpc_error **composite, grpc_error *error,
threads that woke up MUST NOT call grpc_wakeup_fd_consume_wakeup() */ threads that woke up MUST NOT call grpc_wakeup_fd_consume_wakeup() */
static grpc_wakeup_fd polling_island_wakeup_fd; static grpc_wakeup_fd polling_island_wakeup_fd;
/* Polling island freelist */ /* Forward declaration */
static gpr_mu g_pi_freelist_mu; static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi);
static polling_island *g_pi_freelist = NULL;
static void polling_island_delete(); /* Forward declaration */
#ifdef GRPC_TSAN #ifdef GRPC_TSAN
/* Currently TSAN may incorrectly flag data races between epoll_ctl and /* Currently TSAN may incorrectly flag data races between epoll_ctl and
@ -293,28 +289,35 @@ gpr_atm g_epoll_sync;
#endif /* defined(GRPC_TSAN) */ #endif /* defined(GRPC_TSAN) */
#ifdef GRPC_PI_REF_COUNT_DEBUG #ifdef GRPC_PI_REF_COUNT_DEBUG
void pi_add_ref(polling_island *pi); static void pi_add_ref(polling_island *pi);
void pi_unref(polling_island *pi); static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi);
void pi_add_ref_dbg(polling_island *pi, char *reason, char *file, int line) { static void pi_add_ref_dbg(polling_island *pi, char *reason, char *file,
long old_cnt = gpr_atm_acq_load(&(pi->ref_count.count)); int line) {
long old_cnt = gpr_atm_acq_load(&pi->ref_count);
pi_add_ref(pi); pi_add_ref(pi);
gpr_log(GPR_DEBUG, "Add ref pi: %p, old: %ld -> new:%ld (%s) - (%s, %d)", gpr_log(GPR_DEBUG, "Add ref pi: %p, old: %ld -> new:%ld (%s) - (%s, %d)",
(void *)pi, old_cnt, old_cnt + 1, reason, file, line); (void *)pi, old_cnt, old_cnt + 1, reason, file, line);
} }
void pi_unref_dbg(polling_island *pi, char *reason, char *file, int line) { static void pi_unref_dbg(grpc_exec_ctx *exec_ctx, polling_island *pi,
long old_cnt = gpr_atm_acq_load(&(pi->ref_count.count)); char *reason, char *file, int line) {
pi_unref(pi); long old_cnt = gpr_atm_acq_load(&pi->ref_count);
pi_unref(exec_ctx, pi);
gpr_log(GPR_DEBUG, "Unref pi: %p, old:%ld -> new:%ld (%s) - (%s, %d)", gpr_log(GPR_DEBUG, "Unref pi: %p, old:%ld -> new:%ld (%s) - (%s, %d)",
(void *)pi, old_cnt, (old_cnt - 1), reason, file, line); (void *)pi, old_cnt, (old_cnt - 1), reason, file, line);
} }
#endif #endif
void pi_add_ref(polling_island *pi) { gpr_ref(&pi->ref_count); } static void pi_add_ref(polling_island *pi) {
gpr_atm_no_barrier_fetch_add(&pi->ref_count, 1);
}
void pi_unref(polling_island *pi) { static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi) {
/* If ref count went to zero, delete the polling island. /* If ref count went to one, we're back to just the workqueue owning a ref.
Unref the workqueue to break the loop.
If ref count went to zero, delete the polling island.
Note that this deletion not be done under a lock. Once the ref count goes Note that this deletion not be done under a lock. Once the ref count goes
to zero, we are guaranteed that no one else holds a reference to the to zero, we are guaranteed that no one else holds a reference to the
polling island (and that there is no racing pi_add_ref() call either). polling island (and that there is no racing pi_add_ref() call either).
@ -322,12 +325,20 @@ void pi_unref(polling_island *pi) {
Also, if we are deleting the polling island and the merged_to field is Also, if we are deleting the polling island and the merged_to field is
non-empty, we should remove a ref to the merged_to polling island non-empty, we should remove a ref to the merged_to polling island
*/ */
if (gpr_unref(&pi->ref_count)) { switch (gpr_atm_full_fetch_add(&pi->ref_count, -1)) {
polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to); case 2: /* last external ref: the only one now owned is by the workqueue */
polling_island_delete(pi); GRPC_WORKQUEUE_UNREF(exec_ctx, pi->workqueue, "polling_island");
if (next != NULL) { break;
PI_UNREF(next, "pi_delete"); /* Recursive call */ case 1: {
polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to);
polling_island_delete(exec_ctx, pi);
if (next != NULL) {
PI_UNREF(exec_ctx, next, "pi_delete"); /* Recursive call */
}
break;
} }
case 0:
GPR_UNREACHABLE_CODE(return );
} }
} }
@ -462,69 +473,68 @@ static void polling_island_remove_fd_locked(polling_island *pi, grpc_fd *fd,
} }
/* Might return NULL in case of an error */ /* Might return NULL in case of an error */
static polling_island *polling_island_create(grpc_fd *initial_fd, static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx,
grpc_fd *initial_fd,
grpc_error **error) { grpc_error **error) {
polling_island *pi = NULL; polling_island *pi = NULL;
char *err_msg;
const char *err_desc = "polling_island_create"; const char *err_desc = "polling_island_create";
/* Try to get one from the polling island freelist */ *error = GRPC_ERROR_NONE;
gpr_mu_lock(&g_pi_freelist_mu);
if (g_pi_freelist != NULL) {
pi = g_pi_freelist;
g_pi_freelist = g_pi_freelist->next_free;
pi->next_free = NULL;
}
gpr_mu_unlock(&g_pi_freelist_mu);
/* Create new polling island if we could not get one from the free list */ pi = gpr_malloc(sizeof(*pi));
if (pi == NULL) { gpr_mu_init(&pi->mu);
pi = gpr_malloc(sizeof(*pi)); pi->fd_cnt = 0;
gpr_mu_init(&pi->mu); pi->fd_capacity = 0;
pi->fd_cnt = 0; pi->fds = NULL;
pi->fd_capacity = 0; pi->epoll_fd = -1;
pi->fds = NULL; pi->workqueue = NULL;
}
gpr_ref_init(&pi->ref_count, 0); gpr_atm_rel_store(&pi->ref_count, 0);
gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL); gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL);
pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC); pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (pi->epoll_fd < 0) { if (pi->epoll_fd < 0) {
gpr_asprintf(&err_msg, "epoll_create1 failed with error %d (%s)", errno, append_error(error, GRPC_OS_ERROR(errno, "epoll_create1"), err_desc);
strerror(errno)); goto done;
append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc); }
gpr_free(err_msg);
} else {
polling_island_add_wakeup_fd_locked(pi, &grpc_global_wakeup_fd, error);
pi->next_free = NULL;
if (initial_fd != NULL) { polling_island_add_wakeup_fd_locked(pi, &grpc_global_wakeup_fd, error);
/* Lock the polling island here just in case we got this structure from
the freelist and the polling island lock was not released yet (by the if (initial_fd != NULL) {
code that adds the polling island to the freelist) */ polling_island_add_fds_locked(pi, &initial_fd, 1, true, error);
gpr_mu_lock(&pi->mu); }
polling_island_add_fds_locked(pi, &initial_fd, 1, true, error);
gpr_mu_unlock(&pi->mu); if (append_error(error, grpc_workqueue_create(exec_ctx, &pi->workqueue),
} err_desc) &&
*error == GRPC_ERROR_NONE) {
polling_island_add_fds_locked(pi, &pi->workqueue->wakeup_read_fd, 1, true,
error);
GPR_ASSERT(pi->workqueue->wakeup_read_fd->polling_island == NULL);
pi->workqueue->wakeup_read_fd->polling_island = pi;
PI_ADD_REF(pi, "fd");
} }
done:
if (*error != GRPC_ERROR_NONE) {
if (pi->workqueue != NULL) {
GRPC_WORKQUEUE_UNREF(exec_ctx, pi->workqueue, "polling_island");
}
polling_island_delete(exec_ctx, pi);
pi = NULL;
}
return pi; return pi;
} }
static void polling_island_delete(polling_island *pi) { static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi) {
GPR_ASSERT(pi->fd_cnt == 0); GPR_ASSERT(pi->fd_cnt == 0);
gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL); if (pi->epoll_fd >= 0) {
close(pi->epoll_fd);
close(pi->epoll_fd); }
pi->epoll_fd = -1; gpr_mu_destroy(&pi->mu);
gpr_free(pi->fds);
gpr_mu_lock(&g_pi_freelist_mu); gpr_free(pi);
pi->next_free = g_pi_freelist;
g_pi_freelist = pi;
gpr_mu_unlock(&g_pi_freelist_mu);
} }
/* Attempts to gets the last polling island in the linked list (liked by the /* Attempts to gets the last polling island in the linked list (liked by the
@ -704,9 +714,6 @@ static polling_island *polling_island_merge(polling_island *p,
static grpc_error *polling_island_global_init() { static grpc_error *polling_island_global_init() {
grpc_error *error = GRPC_ERROR_NONE; grpc_error *error = GRPC_ERROR_NONE;
gpr_mu_init(&g_pi_freelist_mu);
g_pi_freelist = NULL;
error = grpc_wakeup_fd_init(&polling_island_wakeup_fd); error = grpc_wakeup_fd_init(&polling_island_wakeup_fd);
if (error == GRPC_ERROR_NONE) { if (error == GRPC_ERROR_NONE) {
error = grpc_wakeup_fd_wakeup(&polling_island_wakeup_fd); error = grpc_wakeup_fd_wakeup(&polling_island_wakeup_fd);
@ -716,18 +723,6 @@ static grpc_error *polling_island_global_init() {
} }
static void polling_island_global_shutdown() { static void polling_island_global_shutdown() {
polling_island *next;
gpr_mu_lock(&g_pi_freelist_mu);
gpr_mu_unlock(&g_pi_freelist_mu);
while (g_pi_freelist != NULL) {
next = g_pi_freelist->next_free;
gpr_mu_destroy(&g_pi_freelist->mu);
gpr_free(g_pi_freelist->fds);
gpr_free(g_pi_freelist);
g_pi_freelist = next;
}
gpr_mu_destroy(&g_pi_freelist_mu);
grpc_wakeup_fd_destroy(&polling_island_wakeup_fd); grpc_wakeup_fd_destroy(&polling_island_wakeup_fd);
} }
@ -845,7 +840,6 @@ static grpc_fd *fd_create(int fd, const char *name) {
if (new_fd == NULL) { if (new_fd == NULL) {
new_fd = gpr_malloc(sizeof(grpc_fd)); new_fd = gpr_malloc(sizeof(grpc_fd));
gpr_mu_init(&new_fd->mu); gpr_mu_init(&new_fd->mu);
gpr_mu_init(&new_fd->pi_mu);
} }
/* Note: It is not really needed to get the new_fd->mu lock here. If this is a /* Note: It is not really needed to get the new_fd->mu lock here. If this is a
@ -896,6 +890,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
const char *reason) { const char *reason) {
bool is_fd_closed = false; bool is_fd_closed = false;
grpc_error *error = GRPC_ERROR_NONE; grpc_error *error = GRPC_ERROR_NONE;
polling_island *unref_pi = NULL;
gpr_mu_lock(&fd->mu); gpr_mu_lock(&fd->mu);
fd->on_done_closure = on_done; fd->on_done_closure = on_done;
@ -923,21 +918,26 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
- Unlock the latest polling island - Unlock the latest polling island
- Set fd->polling_island to NULL (but remove the ref on the polling island - Set fd->polling_island to NULL (but remove the ref on the polling island
before doing this.) */ before doing this.) */
gpr_mu_lock(&fd->pi_mu);
if (fd->polling_island != NULL) { if (fd->polling_island != NULL) {
polling_island *pi_latest = polling_island_lock(fd->polling_island); polling_island *pi_latest = polling_island_lock(fd->polling_island);
polling_island_remove_fd_locked(pi_latest, fd, is_fd_closed, &error); polling_island_remove_fd_locked(pi_latest, fd, is_fd_closed, &error);
gpr_mu_unlock(&pi_latest->mu); gpr_mu_unlock(&pi_latest->mu);
PI_UNREF(fd->polling_island, "fd_orphan"); unref_pi = fd->polling_island;
fd->polling_island = NULL; fd->polling_island = NULL;
} }
gpr_mu_unlock(&fd->pi_mu);
grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, error, NULL); grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, error, NULL);
gpr_mu_unlock(&fd->mu); gpr_mu_unlock(&fd->mu);
UNREF_BY(fd, 2, reason); /* Drop the reference */ UNREF_BY(fd, 2, reason); /* Drop the reference */
if (unref_pi != NULL) {
/* Unref stale polling island here, outside the fd lock above.
The polling island owns a workqueue which owns an fd, and unreffing
inside the lock can cause an eventual lock loop that makes TSAN very
unhappy. */
PI_UNREF(exec_ctx, unref_pi, "fd_orphan");
}
GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error)); GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error));
} }
@ -1037,6 +1037,17 @@ static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
gpr_mu_unlock(&fd->mu); gpr_mu_unlock(&fd->mu);
} }
static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) {
gpr_mu_lock(&fd->mu);
grpc_workqueue *workqueue = NULL;
if (fd->polling_island != NULL) {
workqueue =
GRPC_WORKQUEUE_REF(fd->polling_island->workqueue, "get_workqueue");
}
gpr_mu_unlock(&fd->mu);
return workqueue;
}
/******************************************************************************* /*******************************************************************************
* Pollset Definitions * Pollset Definitions
*/ */
@ -1227,9 +1238,10 @@ static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
gpr_mu_unlock(&fd->mu); gpr_mu_unlock(&fd->mu);
} }
static void pollset_release_polling_island(grpc_pollset *ps, char *reason) { static void pollset_release_polling_island(grpc_exec_ctx *exec_ctx,
grpc_pollset *ps, char *reason) {
if (ps->polling_island != NULL) { if (ps->polling_island != NULL) {
PI_UNREF(ps->polling_island, reason); PI_UNREF(exec_ctx, ps->polling_island, reason);
} }
ps->polling_island = NULL; ps->polling_island = NULL;
} }
@ -1242,7 +1254,7 @@ static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx,
pollset->finish_shutdown_called = true; pollset->finish_shutdown_called = true;
/* Release the ref and set pollset->polling_island to NULL */ /* Release the ref and set pollset->polling_island to NULL */
pollset_release_polling_island(pollset, "ps_shutdown"); pollset_release_polling_island(exec_ctx, pollset, "ps_shutdown");
grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL); grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
} }
@ -1281,7 +1293,7 @@ static void pollset_reset(grpc_pollset *pollset) {
pollset->finish_shutdown_called = false; pollset->finish_shutdown_called = false;
pollset->kicked_without_pollers = false; pollset->kicked_without_pollers = false;
pollset->shutdown_done = NULL; pollset->shutdown_done = NULL;
pollset_release_polling_island(pollset, "ps_reset"); GPR_ASSERT(pollset->polling_island == NULL);
} }
#define GRPC_EPOLL_MAX_EVENTS 1000 #define GRPC_EPOLL_MAX_EVENTS 1000
@ -1309,7 +1321,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
this function (i.e pollset_work_and_unlock()) is called */ this function (i.e pollset_work_and_unlock()) is called */
if (pollset->polling_island == NULL) { if (pollset->polling_island == NULL) {
pollset->polling_island = polling_island_create(NULL, error); pollset->polling_island = polling_island_create(exec_ctx, NULL, error);
if (pollset->polling_island == NULL) { if (pollset->polling_island == NULL) {
GPR_TIMER_END("pollset_work_and_unlock", 0); GPR_TIMER_END("pollset_work_and_unlock", 0);
return; /* Fatal error. We cannot continue */ return; /* Fatal error. We cannot continue */
@ -1329,7 +1341,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
/* Always do PI_ADD_REF before PI_UNREF because PI_UNREF may cause the /* Always do PI_ADD_REF before PI_UNREF because PI_UNREF may cause the
polling island to be deleted */ polling island to be deleted */
PI_ADD_REF(pi, "ps"); PI_ADD_REF(pi, "ps");
PI_UNREF(pollset->polling_island, "ps"); PI_UNREF(exec_ctx, pollset->polling_island, "ps");
pollset->polling_island = pi; pollset->polling_island = pi;
} }
@ -1400,7 +1412,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
that we got before releasing the polling island lock). This is because that we got before releasing the polling island lock). This is because
pollset->polling_island pointer might get udpated in other parts of the pollset->polling_island pointer might get udpated in other parts of the
code when there is an island merge while we are doing epoll_wait() above */ code when there is an island merge while we are doing epoll_wait() above */
PI_UNREF(pi, "ps_work"); PI_UNREF(exec_ctx, pi, "ps_work");
GPR_TIMER_END("pollset_work_and_unlock", 0); GPR_TIMER_END("pollset_work_and_unlock", 0);
} }
@ -1517,10 +1529,11 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_error *error = GRPC_ERROR_NONE; grpc_error *error = GRPC_ERROR_NONE;
gpr_mu_lock(&pollset->mu); gpr_mu_lock(&pollset->mu);
gpr_mu_lock(&fd->pi_mu); gpr_mu_lock(&fd->mu);
polling_island *pi_new = NULL; polling_island *pi_new = NULL;
retry:
/* 1) If fd->polling_island and pollset->polling_island are both non-NULL and /* 1) If fd->polling_island and pollset->polling_island are both non-NULL and
* equal, do nothing. * equal, do nothing.
* 2) If fd->polling_island and pollset->polling_island are both NULL, create * 2) If fd->polling_island and pollset->polling_island are both NULL, create
@ -1535,15 +1548,44 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
* polling_island fields in both fd and pollset to point to the merged * polling_island fields in both fd and pollset to point to the merged
* polling island. * polling island.
*/ */
if (fd->orphaned) {
gpr_mu_unlock(&fd->mu);
gpr_mu_unlock(&pollset->mu);
/* early out */
return;
}
if (fd->polling_island == pollset->polling_island) { if (fd->polling_island == pollset->polling_island) {
pi_new = fd->polling_island; pi_new = fd->polling_island;
if (pi_new == NULL) { if (pi_new == NULL) {
pi_new = polling_island_create(fd, &error); /* Unlock before creating a new polling island: the polling island will
create a workqueue which creates a file descriptor, and holding an fd
GRPC_POLLING_TRACE( lock here can eventually cause a loop to appear to TSAN (making it
"pollset_add_fd: Created new polling island. pi_new: %p (fd: %d, " unhappy). We don't think it's a real loop (there's an epoch point where
"pollset: %p)", that loop possibility disappears), but the advantages of keeping TSAN
(void *)pi_new, fd->fd, (void *)pollset); happy outweigh any performance advantage we might have by keeping the
lock held. */
gpr_mu_unlock(&fd->mu);
pi_new = polling_island_create(exec_ctx, fd, &error);
gpr_mu_lock(&fd->mu);
/* Need to reverify any assumptions made between the initial lock and
getting to this branch: if they've changed, we need to throw away our
work and figure things out again. */
if (fd->polling_island != NULL) {
GRPC_POLLING_TRACE(
"pollset_add_fd: Raced creating new polling island. pi_new: %p "
"(fd: %d, pollset: %p)",
(void *)pi_new, fd->fd, (void *)pollset);
PI_ADD_REF(pi_new, "dance_of_destruction");
PI_UNREF(exec_ctx, pi_new, "dance_of_destruction");
goto retry;
} else {
GRPC_POLLING_TRACE(
"pollset_add_fd: Created new polling island. pi_new: %p (fd: %d, "
"pollset: %p)",
(void *)pi_new, fd->fd, (void *)pollset);
}
} }
} else if (fd->polling_island == NULL) { } else if (fd->polling_island == NULL) {
pi_new = polling_island_lock(pollset->polling_island); pi_new = polling_island_lock(pollset->polling_island);
@ -1579,7 +1621,7 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
if (fd->polling_island != pi_new) { if (fd->polling_island != pi_new) {
PI_ADD_REF(pi_new, "fd"); PI_ADD_REF(pi_new, "fd");
if (fd->polling_island != NULL) { if (fd->polling_island != NULL) {
PI_UNREF(fd->polling_island, "fd"); PI_UNREF(exec_ctx, fd->polling_island, "fd");
} }
fd->polling_island = pi_new; fd->polling_island = pi_new;
} }
@ -1587,13 +1629,15 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
if (pollset->polling_island != pi_new) { if (pollset->polling_island != pi_new) {
PI_ADD_REF(pi_new, "ps"); PI_ADD_REF(pi_new, "ps");
if (pollset->polling_island != NULL) { if (pollset->polling_island != NULL) {
PI_UNREF(pollset->polling_island, "ps"); PI_UNREF(exec_ctx, pollset->polling_island, "ps");
} }
pollset->polling_island = pi_new; pollset->polling_island = pi_new;
} }
gpr_mu_unlock(&fd->pi_mu); gpr_mu_unlock(&fd->mu);
gpr_mu_unlock(&pollset->mu); gpr_mu_unlock(&pollset->mu);
GRPC_LOG_IF_ERROR("pollset_add_fd", error);
} }
/******************************************************************************* /*******************************************************************************
@ -1744,9 +1788,9 @@ static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
void *grpc_fd_get_polling_island(grpc_fd *fd) { void *grpc_fd_get_polling_island(grpc_fd *fd) {
polling_island *pi; polling_island *pi;
gpr_mu_lock(&fd->pi_mu); gpr_mu_lock(&fd->mu);
pi = fd->polling_island; pi = fd->polling_island;
gpr_mu_unlock(&fd->pi_mu); gpr_mu_unlock(&fd->mu);
return pi; return pi;
} }
@ -1794,6 +1838,7 @@ static const grpc_event_engine_vtable vtable = {
.fd_notify_on_read = fd_notify_on_read, .fd_notify_on_read = fd_notify_on_read,
.fd_notify_on_write = fd_notify_on_write, .fd_notify_on_write = fd_notify_on_write,
.fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
.fd_get_workqueue = fd_get_workqueue,
.pollset_init = pollset_init, .pollset_init = pollset_init,
.pollset_shutdown = pollset_shutdown, .pollset_shutdown = pollset_shutdown,

@ -725,6 +725,8 @@ static void fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
GRPC_FD_UNREF(fd, "poll"); GRPC_FD_UNREF(fd, "poll");
} }
static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { return NULL; }
/******************************************************************************* /*******************************************************************************
* pollset_posix.c * pollset_posix.c
*/ */
@ -2006,6 +2008,7 @@ static const grpc_event_engine_vtable vtable = {
.fd_notify_on_read = fd_notify_on_read, .fd_notify_on_read = fd_notify_on_read,
.fd_notify_on_write = fd_notify_on_write, .fd_notify_on_write = fd_notify_on_write,
.fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
.fd_get_workqueue = fd_get_workqueue,
.pollset_init = pollset_init, .pollset_init = pollset_init,
.pollset_shutdown = pollset_shutdown, .pollset_shutdown = pollset_shutdown,

@ -617,6 +617,8 @@ static void fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
GRPC_FD_UNREF(fd, "poll"); GRPC_FD_UNREF(fd, "poll");
} }
static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { return NULL; }
/******************************************************************************* /*******************************************************************************
* pollset_posix.c * pollset_posix.c
*/ */
@ -1234,6 +1236,7 @@ static const grpc_event_engine_vtable vtable = {
.fd_notify_on_read = fd_notify_on_read, .fd_notify_on_read = fd_notify_on_read,
.fd_notify_on_write = fd_notify_on_write, .fd_notify_on_write = fd_notify_on_write,
.fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
.fd_get_workqueue = fd_get_workqueue,
.pollset_init = pollset_init, .pollset_init = pollset_init,
.pollset_shutdown = pollset_shutdown, .pollset_shutdown = pollset_shutdown,

@ -148,6 +148,10 @@ grpc_fd *grpc_fd_create(int fd, const char *name) {
return g_event_engine->fd_create(fd, name); return g_event_engine->fd_create(fd, name);
} }
grpc_workqueue *grpc_fd_get_workqueue(grpc_fd *fd) {
return g_event_engine->fd_get_workqueue(fd);
}
int grpc_fd_wrapped_fd(grpc_fd *fd) { int grpc_fd_wrapped_fd(grpc_fd *fd) {
return g_event_engine->fd_wrapped_fd(fd); return g_event_engine->fd_wrapped_fd(fd);
} }

@ -56,6 +56,7 @@ typedef struct grpc_event_engine_vtable {
void (*fd_notify_on_write)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, void (*fd_notify_on_write)(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure); grpc_closure *closure);
bool (*fd_is_shutdown)(grpc_fd *fd); bool (*fd_is_shutdown)(grpc_fd *fd);
grpc_workqueue *(*fd_get_workqueue)(grpc_fd *fd);
grpc_pollset *(*fd_get_read_notifier_pollset)(grpc_exec_ctx *exec_ctx, grpc_pollset *(*fd_get_read_notifier_pollset)(grpc_exec_ctx *exec_ctx,
grpc_fd *fd); grpc_fd *fd);
@ -107,6 +108,9 @@ const char *grpc_get_poll_strategy_name();
This takes ownership of closing fd. */ This takes ownership of closing fd. */
grpc_fd *grpc_fd_create(int fd, const char *name); grpc_fd *grpc_fd_create(int fd, const char *name);
/* Get a workqueue that's associated with this fd */
grpc_workqueue *grpc_fd_get_workqueue(grpc_fd *fd);
/* Return the wrapped fd, or -1 if it has been released or closed. */ /* Return the wrapped fd, or -1 if it has been released or closed. */
int grpc_fd_wrapped_fd(grpc_fd *fd); int grpc_fd_wrapped_fd(grpc_fd *fd);

@ -37,6 +37,7 @@
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include <grpc/support/thd.h> #include <grpc/support/thd.h>
#include "src/core/lib/iomgr/workqueue.h"
#include "src/core/lib/profiling/timers.h" #include "src/core/lib/profiling/timers.h"
bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx *exec_ctx) { bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx *exec_ctx) {
@ -85,14 +86,17 @@ void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {
void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure, void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
grpc_error *error, grpc_error *error,
grpc_workqueue *offload_target_or_null) { grpc_workqueue *offload_target_or_null) {
GPR_ASSERT(offload_target_or_null == NULL); if (offload_target_or_null == NULL) {
grpc_closure_list_append(&exec_ctx->closure_list, closure, error); grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
} else {
grpc_workqueue_enqueue(exec_ctx, offload_target_or_null, closure, error);
GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched");
}
} }
void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
grpc_closure_list *list, grpc_closure_list *list,
grpc_workqueue *offload_target_or_null) { grpc_workqueue *offload_target_or_null) {
GPR_ASSERT(offload_target_or_null == NULL);
grpc_closure_list_move(list, &exec_ctx->closure_list); grpc_closure_list_move(list, &exec_ctx->closure_list);
} }

@ -93,7 +93,11 @@ bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx);
/** Finish any pending work for a grpc_exec_ctx. Must be called before /** Finish any pending work for a grpc_exec_ctx. Must be called before
* the instance is destroyed, or work may be lost. */ * the instance is destroyed, or work may be lost. */
void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx); void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx);
/** Add a closure to be executed at the next flush/finish point */ /** Add a closure to be executed in the future.
If \a offload_target_or_null is NULL, the closure will be executed at the
next exec_ctx.{finish,flush} point.
If \a offload_target_or_null is non-NULL, the closure will be scheduled
against the workqueue, and a reference to the workqueue will be consumed. */
void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure, void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
grpc_error *error, grpc_error *error,
grpc_workqueue *offload_target_or_null); grpc_workqueue *offload_target_or_null);

@ -45,6 +45,7 @@
#include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/network_status_tracker.h"
#include "src/core/lib/iomgr/timer.h" #include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/support/env.h" #include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h" #include "src/core/lib/support/string.h"
@ -62,6 +63,7 @@ void grpc_iomgr_init(void) {
grpc_timer_list_init(gpr_now(GPR_CLOCK_MONOTONIC)); grpc_timer_list_init(gpr_now(GPR_CLOCK_MONOTONIC));
g_root_object.next = g_root_object.prev = &g_root_object; g_root_object.next = g_root_object.prev = &g_root_object;
g_root_object.name = "root"; g_root_object.name = "root";
grpc_network_status_init();
grpc_iomgr_platform_init(); grpc_iomgr_platform_init();
} }
@ -140,6 +142,7 @@ void grpc_iomgr_shutdown(void) {
grpc_iomgr_platform_shutdown(); grpc_iomgr_platform_shutdown();
grpc_exec_ctx_global_shutdown(); grpc_exec_ctx_global_shutdown();
grpc_network_status_shutdown();
gpr_mu_destroy(&g_mu); gpr_mu_destroy(&g_mu);
gpr_cv_destroy(&g_rcv); gpr_cv_destroy(&g_rcv);
} }

@ -42,10 +42,16 @@ typedef struct endpoint_ll_node {
static endpoint_ll_node *head = NULL; static endpoint_ll_node *head = NULL;
static gpr_mu g_endpoint_mutex; static gpr_mu g_endpoint_mutex;
static bool g_init_done = false;
void grpc_initialize_network_status_monitor() { void grpc_network_status_shutdown(void) {
g_init_done = true; if (head != NULL) {
gpr_log(GPR_ERROR,
"Memory leaked as all network endpoints were not shut down");
}
gpr_mu_destroy(&g_endpoint_mutex);
}
void grpc_network_status_init(void) {
gpr_mu_init(&g_endpoint_mutex); gpr_mu_init(&g_endpoint_mutex);
// TODO(makarandd): Install callback with OS to monitor network status. // TODO(makarandd): Install callback with OS to monitor network status.
} }
@ -60,9 +66,6 @@ void grpc_destroy_network_status_monitor() {
} }
void grpc_network_status_register_endpoint(grpc_endpoint *ep) { void grpc_network_status_register_endpoint(grpc_endpoint *ep) {
if (!g_init_done) {
grpc_initialize_network_status_monitor();
}
gpr_mu_lock(&g_endpoint_mutex); gpr_mu_lock(&g_endpoint_mutex);
if (head == NULL) { if (head == NULL) {
head = (endpoint_ll_node *)gpr_malloc(sizeof(endpoint_ll_node)); head = (endpoint_ll_node *)gpr_malloc(sizeof(endpoint_ll_node));

@ -35,7 +35,11 @@
#define GRPC_CORE_LIB_IOMGR_NETWORK_STATUS_TRACKER_H #define GRPC_CORE_LIB_IOMGR_NETWORK_STATUS_TRACKER_H
#include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/endpoint.h"
void grpc_network_status_init(void);
void grpc_network_status_shutdown(void);
void grpc_network_status_register_endpoint(grpc_endpoint *ep); void grpc_network_status_register_endpoint(grpc_endpoint *ep);
void grpc_network_status_unregister_endpoint(grpc_endpoint *ep); void grpc_network_status_unregister_endpoint(grpc_endpoint *ep);
void grpc_network_status_shutdown_all_endpoints(); void grpc_network_status_shutdown_all_endpoints();
#endif /* GRPC_CORE_LIB_IOMGR_NETWORK_STATUS_TRACKER_H */ #endif /* GRPC_CORE_LIB_IOMGR_NETWORK_STATUS_TRACKER_H */

@ -284,7 +284,7 @@ static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
} }
/* returns true if done, false if pending; if returning true, *error is set */ /* returns true if done, false if pending; if returning true, *error is set */
#define MAX_WRITE_IOVEC 16 #define MAX_WRITE_IOVEC 1024
static bool tcp_flush(grpc_tcp *tcp, grpc_error **error) { static bool tcp_flush(grpc_tcp *tcp, grpc_error **error) {
struct msghdr msg; struct msghdr msg;
struct iovec iov[MAX_WRITE_IOVEC]; struct iovec iov[MAX_WRITE_IOVEC];
@ -450,9 +450,19 @@ static char *tcp_get_peer(grpc_endpoint *ep) {
return gpr_strdup(tcp->peer_string); return gpr_strdup(tcp->peer_string);
} }
static const grpc_endpoint_vtable vtable = { static grpc_workqueue *tcp_get_workqueue(grpc_endpoint *ep) {
tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set, grpc_tcp *tcp = (grpc_tcp *)ep;
tcp_shutdown, tcp_destroy, tcp_get_peer}; return grpc_fd_get_workqueue(tcp->em_fd);
}
static const grpc_endpoint_vtable vtable = {tcp_read,
tcp_write,
tcp_get_workqueue,
tcp_add_to_pollset,
tcp_add_to_pollset_set,
tcp_shutdown,
tcp_destroy,
tcp_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size, grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
const char *peer_string) { const char *peer_string) {

@ -491,7 +491,8 @@ static grpc_error *clone_port(grpc_tcp_listener *listener, unsigned count) {
} }
for (unsigned i = 0; i < count; i++) { for (unsigned i = 0; i < count; i++) {
int fd, port; int fd = -1;
int port = -1;
grpc_dualstack_mode dsmode; grpc_dualstack_mode dsmode;
err = grpc_create_dualstack_socket(&listener->addr.sockaddr, SOCK_STREAM, 0, err = grpc_create_dualstack_socket(&listener->addr.sockaddr, SOCK_STREAM, 0,
&dsmode, &fd); &dsmode, &fd);

@ -389,9 +389,16 @@ static char *win_get_peer(grpc_endpoint *ep) {
return gpr_strdup(tcp->peer_string); return gpr_strdup(tcp->peer_string);
} }
static grpc_endpoint_vtable vtable = { static grpc_workqueue *win_get_workqueue(grpc_endpoint *ep) { return NULL; }
win_read, win_write, win_add_to_pollset, win_add_to_pollset_set,
win_shutdown, win_destroy, win_get_peer}; static grpc_endpoint_vtable vtable = {win_read,
win_write,
win_get_workqueue,
win_add_to_pollset,
win_add_to_pollset_set,
win_shutdown,
win_destroy,
win_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) { grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp)); grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));

@ -60,6 +60,7 @@
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/ev_posix.h" #include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/sockaddr_utils.h"
@ -128,7 +129,7 @@ grpc_udp_server *grpc_udp_server_create(void) {
} }
static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1, NULL); grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
gpr_mu_destroy(&s->mu); gpr_mu_destroy(&s->mu);
gpr_cv_destroy(&s->cv); gpr_cv_destroy(&s->cv);
@ -138,7 +139,7 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
} }
static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
bool success) { grpc_error *error) {
grpc_udp_server *s = server; grpc_udp_server *s = server;
gpr_mu_lock(&s->mu); gpr_mu_lock(&s->mu);
s->destroyed_ports++; s->destroyed_ports++;
@ -217,14 +218,23 @@ static int prepare_socket(int fd, const struct sockaddr *addr,
goto error; goto error;
} }
if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1)) { if (grpc_set_socket_nonblocking(fd, 1) != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, gpr_log(GPR_ERROR, "Unable to set nonblocking %d: %s", fd, strerror(errno));
strerror(errno)); goto error;
}
if (grpc_set_socket_cloexec(fd, 1) != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Unable to set cloexec %d: %s", fd, strerror(errno));
goto error;
} }
if (grpc_set_socket_ip_pktinfo_if_possible(fd) && if (grpc_set_socket_ip_pktinfo_if_possible(fd) != GRPC_ERROR_NONE) {
addr->sa_family == AF_INET6) { gpr_log(GPR_ERROR, "Unable to set ip_pktinfo.");
grpc_set_socket_ipv6_recvpktinfo_if_possible(fd); goto error;
} else if (addr->sa_family == AF_INET6) {
if (grpc_set_socket_ipv6_recvpktinfo_if_possible(fd) != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Unable to set ipv6_recvpktinfo.");
goto error;
}
} }
GPR_ASSERT(addr_len < ~(socklen_t)0); GPR_ASSERT(addr_len < ~(socklen_t)0);
@ -241,13 +251,13 @@ static int prepare_socket(int fd, const struct sockaddr *addr,
goto error; goto error;
} }
if (!grpc_set_socket_sndbuf(fd, buffer_size_bytes)) { if (grpc_set_socket_sndbuf(fd, buffer_size_bytes) != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Failed to set send buffer size to %d bytes", gpr_log(GPR_ERROR, "Failed to set send buffer size to %d bytes",
buffer_size_bytes); buffer_size_bytes);
goto error; goto error;
} }
if (!grpc_set_socket_rcvbuf(fd, buffer_size_bytes)) { if (grpc_set_socket_rcvbuf(fd, buffer_size_bytes) != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Failed to set receive buffer size to %d bytes", gpr_log(GPR_ERROR, "Failed to set receive buffer size to %d bytes",
buffer_size_bytes); buffer_size_bytes);
goto error; goto error;
@ -263,10 +273,10 @@ error:
} }
/* event manager callback when reads are ready */ /* event manager callback when reads are ready */
static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
server_port *sp = arg; server_port *sp = arg;
if (!success) { if (error != GRPC_ERROR_NONE) {
gpr_mu_lock(&sp->server->mu); gpr_mu_lock(&sp->server->mu);
if (0 == --sp->server->active_ports) { if (0 == --sp->server->active_ports) {
gpr_mu_unlock(&sp->server->mu); gpr_mu_unlock(&sp->server->mu);
@ -369,7 +379,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr,
/* Try listening on IPv6 first. */ /* Try listening on IPv6 first. */
addr = (struct sockaddr *)&wild6; addr = (struct sockaddr *)&wild6;
addr_len = sizeof(wild6); addr_len = sizeof(wild6);
fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); // TODO(rjshade): Test and propagate the returned grpc_error*:
grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd);
allocated_port1 = allocated_port1 =
add_socket_to_server(s, fd, addr, addr_len, read_cb, orphan_cb); add_socket_to_server(s, fd, addr, addr_len, read_cb, orphan_cb);
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
@ -384,7 +395,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr,
addr_len = sizeof(wild4); addr_len = sizeof(wild4);
} }
fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); // TODO(rjshade): Test and propagate the returned grpc_error*:
grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd);
if (fd < 0) { if (fd < 0) {
gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
} }

@ -38,6 +38,7 @@
#include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
#ifdef GPR_POSIX_SOCKET #ifdef GPR_POSIX_SOCKET
#include "src/core/lib/iomgr/workqueue_posix.h" #include "src/core/lib/iomgr/workqueue_posix.h"
@ -49,35 +50,45 @@
/* grpc_workqueue is forward declared in exec_ctx.h */ /* grpc_workqueue is forward declared in exec_ctx.h */
/** Create a work queue */ /* Deprecated: do not use.
grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx, This has *already* been removed in a future commit. */
grpc_workqueue **workqueue);
void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
#define GRPC_WORKQUEUE_REFCOUNT_DEBUG /* Reference counting functions. Use the macro's always
(GRPC_WORKQUEUE_{REF,UNREF}).
Pass in a descriptive reason string for reffing/unreffing as the last
argument to each macro. When GRPC_WORKQUEUE_REFCOUNT_DEBUG is defined, that
string will be printed alongside the refcount. When it is not defined, the
string will be discarded at compilation time. */
//#define GRPC_WORKQUEUE_REFCOUNT_DEBUG
#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
#define GRPC_WORKQUEUE_REF(p, r) \ #define GRPC_WORKQUEUE_REF(p, r) \
grpc_workqueue_ref((p), __FILE__, __LINE__, (r)) (grpc_workqueue_ref((p), __FILE__, __LINE__, (r)), (p))
#define GRPC_WORKQUEUE_UNREF(cl, p, r) \ #define GRPC_WORKQUEUE_UNREF(exec_ctx, p, r) \
grpc_workqueue_unref((cl), (p), __FILE__, __LINE__, (r)) grpc_workqueue_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line, void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
const char *reason); const char *reason);
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
const char *file, int line, const char *reason); const char *file, int line, const char *reason);
#else #else
#define GRPC_WORKQUEUE_REF(p, r) grpc_workqueue_ref((p)) #define GRPC_WORKQUEUE_REF(p, r) (grpc_workqueue_ref((p)), (p))
#define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p)) #define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p))
void grpc_workqueue_ref(grpc_workqueue *workqueue); void grpc_workqueue_ref(grpc_workqueue *workqueue);
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue); void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
#endif #endif
/** Bind this workqueue to a pollset */ /** Add a work item to a workqueue. Items added to a work queue will be started
void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx, in approximately the order they were enqueued, on some thread that may or
grpc_workqueue *workqueue, may not be the current thread. Successive closures enqueued onto a workqueue
grpc_pollset *pollset); MAY be executed concurrently.
It is generally more expensive to add a closure to a workqueue than to the
execution context, both in terms of CPU work and in execution latency.
/** Add a work item to a workqueue */ Use work queues when it's important that other threads be given a chance to
tackle some workload. */
void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue, void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
grpc_closure *closure, grpc_error *error); grpc_closure *closure, grpc_error *error);

@ -70,7 +70,7 @@ grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx,
static void workqueue_destroy(grpc_exec_ctx *exec_ctx, static void workqueue_destroy(grpc_exec_ctx *exec_ctx,
grpc_workqueue *workqueue) { grpc_workqueue *workqueue) {
GPR_ASSERT(grpc_closure_list_empty(workqueue->closure_list)); grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd); grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd);
} }
@ -100,12 +100,6 @@ void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
} }
} }
void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx,
grpc_workqueue *workqueue,
grpc_pollset *pollset) {
grpc_pollset_add_fd(exec_ctx, pollset, workqueue->wakeup_read_fd);
}
void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) { void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
gpr_mu_lock(&workqueue->mu); gpr_mu_lock(&workqueue->mu);
grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL); grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);

@ -50,4 +50,9 @@ struct grpc_workqueue {
grpc_closure read_closure; grpc_closure read_closure;
}; };
/** Create a work queue. Returns an error if creation fails. If creation
succeeds, sets *workqueue to point to it. */
grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx,
grpc_workqueue **workqueue);
#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H */ #endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H */

@ -37,4 +37,26 @@
#include "src/core/lib/iomgr/workqueue.h" #include "src/core/lib/iomgr/workqueue.h"
// Minimal implementation of grpc_workqueue for Windows
// Works by directly enqueuing workqueue items onto the current execution
// context, which is at least correct, if not performant or in the spirit of
// workqueues.
void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
const char *reason) {}
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
const char *file, int line, const char *reason) {}
#else
void grpc_workqueue_ref(grpc_workqueue *workqueue) {}
void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
#endif
void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
grpc_closure *closure, grpc_error *error) {
grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
}
#endif /* GPR_WINDOWS */ #endif /* GPR_WINDOWS */

@ -360,11 +360,19 @@ static char *endpoint_get_peer(grpc_endpoint *secure_ep) {
return grpc_endpoint_get_peer(ep->wrapped_ep); return grpc_endpoint_get_peer(ep->wrapped_ep);
} }
static const grpc_endpoint_vtable vtable = { static grpc_workqueue *endpoint_get_workqueue(grpc_endpoint *secure_ep) {
endpoint_read, endpoint_write, secure_endpoint *ep = (secure_endpoint *)secure_ep;
endpoint_add_to_pollset, endpoint_add_to_pollset_set, return grpc_endpoint_get_workqueue(ep->wrapped_ep);
endpoint_shutdown, endpoint_destroy, }
endpoint_get_peer};
static const grpc_endpoint_vtable vtable = {endpoint_read,
endpoint_write,
endpoint_get_workqueue,
endpoint_add_to_pollset,
endpoint_add_to_pollset_set,
endpoint_shutdown,
endpoint_destroy,
endpoint_get_peer};
grpc_endpoint *grpc_secure_endpoint_create( grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *transport, struct tsi_frame_protector *protector, grpc_endpoint *transport,

@ -79,17 +79,18 @@ void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print) {
void gpr_log_verbosity_init() { void gpr_log_verbosity_init() {
char *verbosity = gpr_getenv("GRPC_VERBOSITY"); char *verbosity = gpr_getenv("GRPC_VERBOSITY");
if (verbosity == NULL) return;
gpr_atm min_severity_to_print = GPR_LOG_VERBOSITY_UNSET; gpr_atm min_severity_to_print = GPR_LOG_SEVERITY_ERROR;
if (strcmp(verbosity, "DEBUG") == 0) { if (verbosity != NULL) {
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_DEBUG; if (strcmp(verbosity, "DEBUG") == 0) {
} else if (strcmp(verbosity, "INFO") == 0) { min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_DEBUG;
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_INFO; } else if (strcmp(verbosity, "INFO") == 0) {
} else if (strcmp(verbosity, "ERROR") == 0) { min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_INFO;
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_ERROR; } else if (strcmp(verbosity, "ERROR") == 0) {
min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_ERROR;
}
gpr_free(verbosity);
} }
gpr_free(verbosity);
if ((gpr_atm_no_barrier_load(&g_min_severity_to_print)) == if ((gpr_atm_no_barrier_load(&g_min_severity_to_print)) ==
GPR_LOG_VERBOSITY_UNSET) { GPR_LOG_VERBOSITY_UNSET) {
gpr_atm_no_barrier_store(&g_min_severity_to_print, min_severity_to_print); gpr_atm_no_barrier_store(&g_min_severity_to_print, min_severity_to_print);

@ -73,6 +73,7 @@ typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type;
typedef struct requested_call { typedef struct requested_call {
requested_call_type type; requested_call_type type;
size_t cq_idx;
void *tag; void *tag;
grpc_server *server; grpc_server *server;
grpc_completion_queue *cq_bound_to_call; grpc_completion_queue *cq_bound_to_call;
@ -206,11 +207,11 @@ struct grpc_server {
registered_method *registered_methods; registered_method *registered_methods;
/** one request matcher for unregistered methods */ /** one request matcher for unregistered methods */
request_matcher unregistered_request_matcher; request_matcher unregistered_request_matcher;
/** free list of available requested_calls indices */ /** free list of available requested_calls_per_cq indices */
gpr_stack_lockfree *request_freelist; gpr_stack_lockfree **request_freelist_per_cq;
/** requested call backing data */ /** requested call backing data */
requested_call *requested_calls; requested_call **requested_calls_per_cq;
size_t max_requested_calls; int max_requested_calls_per_cq;
gpr_atm shutdown_flag; gpr_atm shutdown_flag;
uint8_t shutdown_published; uint8_t shutdown_published;
@ -357,7 +358,8 @@ static void request_matcher_kill_requests(grpc_exec_ctx *exec_ctx,
for (size_t i = 0; i < server->cq_count; i++) { for (size_t i = 0; i < server->cq_count; i++) {
while ((request_id = gpr_stack_lockfree_pop(rm->requests_per_cq[i])) != while ((request_id = gpr_stack_lockfree_pop(rm->requests_per_cq[i])) !=
-1) { -1) {
fail_call(exec_ctx, server, i, &server->requested_calls[request_id], fail_call(exec_ctx, server, i,
&server->requested_calls_per_cq[i][request_id],
GRPC_ERROR_REF(error)); GRPC_ERROR_REF(error));
} }
} }
@ -392,12 +394,16 @@ static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) {
} }
for (i = 0; i < server->cq_count; i++) { for (i = 0; i < server->cq_count; i++) {
GRPC_CQ_INTERNAL_UNREF(server->cqs[i], "server"); GRPC_CQ_INTERNAL_UNREF(server->cqs[i], "server");
if (server->started) {
gpr_stack_lockfree_destroy(server->request_freelist_per_cq[i]);
gpr_free(server->requested_calls_per_cq[i]);
}
} }
gpr_stack_lockfree_destroy(server->request_freelist); gpr_free(server->request_freelist_per_cq);
gpr_free(server->requested_calls_per_cq);
gpr_free(server->cqs); gpr_free(server->cqs);
gpr_free(server->pollsets); gpr_free(server->pollsets);
gpr_free(server->shutdown_tags); gpr_free(server->shutdown_tags);
gpr_free(server->requested_calls);
gpr_free(server); gpr_free(server);
} }
@ -460,11 +466,13 @@ static void done_request_event(grpc_exec_ctx *exec_ctx, void *req,
requested_call *rc = req; requested_call *rc = req;
grpc_server *server = rc->server; grpc_server *server = rc->server;
if (rc >= server->requested_calls && if (rc >= server->requested_calls_per_cq[rc->cq_idx] &&
rc < server->requested_calls + server->max_requested_calls) { rc < server->requested_calls_per_cq[rc->cq_idx] +
GPR_ASSERT(rc - server->requested_calls <= INT_MAX); server->max_requested_calls_per_cq) {
gpr_stack_lockfree_push(server->request_freelist, GPR_ASSERT(rc - server->requested_calls_per_cq[rc->cq_idx] <= INT_MAX);
(int)(rc - server->requested_calls)); gpr_stack_lockfree_push(
server->request_freelist_per_cq[rc->cq_idx],
(int)(rc - server->requested_calls_per_cq[rc->cq_idx]));
} else { } else {
gpr_free(req); gpr_free(req);
} }
@ -540,7 +548,7 @@ static void publish_new_rpc(grpc_exec_ctx *exec_ctx, void *arg,
calld->state = ACTIVATED; calld->state = ACTIVATED;
gpr_mu_unlock(&calld->mu_state); gpr_mu_unlock(&calld->mu_state);
publish_call(exec_ctx, server, calld, cq_idx, publish_call(exec_ctx, server, calld, cq_idx,
&server->requested_calls[request_id]); &server->requested_calls_per_cq[cq_idx][request_id]);
return; /* early out */ return; /* early out */
} }
} }
@ -979,8 +987,6 @@ void grpc_server_register_non_listening_completion_queue(
} }
grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) { grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
size_t i;
GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved)); GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved));
grpc_server *server = gpr_malloc(sizeof(grpc_server)); grpc_server *server = gpr_malloc(sizeof(grpc_server));
@ -998,15 +1004,7 @@ grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
&server->root_channel_data; &server->root_channel_data;
/* TODO(ctiller): expose a channel_arg for this */ /* TODO(ctiller): expose a channel_arg for this */
server->max_requested_calls = 32768; server->max_requested_calls_per_cq = 32768;
server->request_freelist =
gpr_stack_lockfree_create(server->max_requested_calls);
for (i = 0; i < (size_t)server->max_requested_calls; i++) {
gpr_stack_lockfree_push(server->request_freelist, (int)i);
}
server->requested_calls = gpr_malloc(server->max_requested_calls *
sizeof(*server->requested_calls));
server->channel_args = grpc_channel_args_copy(args); server->channel_args = grpc_channel_args_copy(args);
return server; return server;
@ -1066,16 +1064,28 @@ void grpc_server_start(grpc_server *server) {
server->started = true; server->started = true;
size_t pollset_count = 0; size_t pollset_count = 0;
server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count); server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count);
server->request_freelist_per_cq =
gpr_malloc(sizeof(*server->request_freelist_per_cq) * server->cq_count);
server->requested_calls_per_cq =
gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count);
for (i = 0; i < server->cq_count; i++) { for (i = 0; i < server->cq_count; i++) {
if (!grpc_cq_is_non_listening_server_cq(server->cqs[i])) { if (!grpc_cq_is_non_listening_server_cq(server->cqs[i])) {
server->pollsets[pollset_count++] = grpc_cq_pollset(server->cqs[i]); server->pollsets[pollset_count++] = grpc_cq_pollset(server->cqs[i]);
} }
server->request_freelist_per_cq[i] =
gpr_stack_lockfree_create((size_t)server->max_requested_calls_per_cq);
for (int j = 0; j < server->max_requested_calls_per_cq; j++) {
gpr_stack_lockfree_push(server->request_freelist_per_cq[i], j);
}
server->requested_calls_per_cq[i] =
gpr_malloc((size_t)server->max_requested_calls_per_cq *
sizeof(*server->requested_calls_per_cq[i]));
} }
request_matcher_init(&server->unregistered_request_matcher, request_matcher_init(&server->unregistered_request_matcher,
server->max_requested_calls, server); (size_t)server->max_requested_calls_per_cq, server);
for (registered_method *rm = server->registered_methods; rm; rm = rm->next) { for (registered_method *rm = server->registered_methods; rm; rm = rm->next) {
request_matcher_init(&rm->request_matcher, server->max_requested_calls, request_matcher_init(&rm->request_matcher,
server); (size_t)server->max_requested_calls_per_cq, server);
} }
for (l = server->listeners; l; l = l->next) { for (l = server->listeners; l; l = l->next) {
@ -1307,11 +1317,13 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_CREATE("Server Shutdown")); GRPC_ERROR_CREATE("Server Shutdown"));
return GRPC_CALL_OK; return GRPC_CALL_OK;
} }
request_id = gpr_stack_lockfree_pop(server->request_freelist); request_id = gpr_stack_lockfree_pop(server->request_freelist_per_cq[cq_idx]);
if (request_id == -1) { if (request_id == -1) {
/* out of request ids: just fail this one */ /* out of request ids: just fail this one */
fail_call(exec_ctx, server, cq_idx, rc, fail_call(exec_ctx, server, cq_idx, rc,
GRPC_ERROR_CREATE("Server Shutdown")); grpc_error_set_int(GRPC_ERROR_CREATE("Out of request ids"),
GRPC_ERROR_INT_LIMIT,
server->max_requested_calls_per_cq));
return GRPC_CALL_OK; return GRPC_CALL_OK;
} }
switch (rc->type) { switch (rc->type) {
@ -1322,7 +1334,7 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
rm = &rc->data.registered.registered_method->request_matcher; rm = &rc->data.registered.registered_method->request_matcher;
break; break;
} }
server->requested_calls[request_id] = *rc; server->requested_calls_per_cq[cq_idx][request_id] = *rc;
gpr_free(rc); gpr_free(rc);
if (gpr_stack_lockfree_push(rm->requests_per_cq[cq_idx], request_id)) { if (gpr_stack_lockfree_push(rm->requests_per_cq[cq_idx], request_id)) {
/* this was the first queued request: we need to lock and start /* this was the first queued request: we need to lock and start
@ -1346,7 +1358,7 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
calld->state = ACTIVATED; calld->state = ACTIVATED;
gpr_mu_unlock(&calld->mu_state); gpr_mu_unlock(&calld->mu_state);
publish_call(exec_ctx, server, calld, cq_idx, publish_call(exec_ctx, server, calld, cq_idx,
&server->requested_calls[request_id]); &server->requested_calls_per_cq[cq_idx][request_id]);
} }
gpr_mu_lock(&server->mu_call); gpr_mu_lock(&server->mu_call);
} }
@ -1382,6 +1394,7 @@ grpc_call_error grpc_server_request_call(
} }
grpc_cq_begin_op(cq_for_notification, tag); grpc_cq_begin_op(cq_for_notification, tag);
details->reserved = NULL; details->reserved = NULL;
rc->cq_idx = cq_idx;
rc->type = BATCH_CALL; rc->type = BATCH_CALL;
rc->server = server; rc->server = server;
rc->tag = tag; rc->tag = tag;
@ -1430,6 +1443,7 @@ grpc_call_error grpc_server_request_registered_call(
goto done; goto done;
} }
grpc_cq_begin_op(cq_for_notification, tag); grpc_cq_begin_op(cq_for_notification, tag);
rc->cq_idx = cq_idx;
rc->type = REGISTERED_CALL; rc->type = REGISTERED_CALL;
rc->server = server; rc->server = server;
rc->tag = tag; rc->tag = tag;

@ -36,4 +36,4 @@
#include <grpc/grpc.h> #include <grpc/grpc.h>
const char *grpc_version_string(void) { return "1.0.0-pre1"; } const char *grpc_version_string(void) { return "1.0.0-pre2"; }

@ -179,6 +179,9 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
while ((w = tracker->watchers) != NULL) { while ((w = tracker->watchers) != NULL) {
*w->current = tracker->current_state; *w->current = tracker->current_state;
tracker->watchers = w->next; tracker->watchers = w->next;
if (grpc_connectivity_state_trace) {
gpr_log(GPR_DEBUG, "NOTIFY: %p", w->notify);
}
grpc_exec_ctx_sched(exec_ctx, w->notify, grpc_exec_ctx_sched(exec_ctx, w->notify,
GRPC_ERROR_REF(tracker->current_error), NULL); GRPC_ERROR_REF(tracker->current_error), NULL);
gpr_free(w); gpr_free(w);

@ -281,6 +281,7 @@ Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned,
: max_message_size_(max_message_size), : max_message_size_(max_message_size),
started_(false), started_(false),
shutdown_(false), shutdown_(false),
shutdown_notified_(false),
num_running_cb_(0), num_running_cb_(0),
sync_methods_(new std::list<SyncRequest>), sync_methods_(new std::list<SyncRequest>),
has_generic_service_(false), has_generic_service_(false),
@ -462,13 +463,16 @@ void Server::ShutdownInternal(gpr_timespec deadline) {
while (num_running_cb_ != 0) { while (num_running_cb_ != 0) {
callback_cv_.wait(lock); callback_cv_.wait(lock);
} }
shutdown_notified_ = true;
shutdown_cv_.notify_all();
} }
} }
void Server::Wait() { void Server::Wait() {
grpc::unique_lock<grpc::mutex> lock(mu_); grpc::unique_lock<grpc::mutex> lock(mu_);
while (num_running_cb_ != 0) { while (started_ && !shutdown_notified_) {
callback_cv_.wait(lock); shutdown_cv_.wait(lock);
} }
} }

@ -129,7 +129,8 @@ ServerContext::ServerContext()
deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)), deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
call_(nullptr), call_(nullptr),
cq_(nullptr), cq_(nullptr),
sent_initial_metadata_(false) {} sent_initial_metadata_(false),
compression_level_set_(false) {}
ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata, ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
size_t metadata_count) size_t metadata_count)
@ -139,7 +140,8 @@ ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
deadline_(deadline), deadline_(deadline),
call_(nullptr), call_(nullptr),
cq_(nullptr), cq_(nullptr),
sent_initial_metadata_(false) { sent_initial_metadata_(false),
compression_level_set_(false) {
for (size_t i = 0; i < metadata_count; i++) { for (size_t i = 0; i < metadata_count; i++) {
client_metadata_.insert(std::pair<grpc::string_ref, grpc::string_ref>( client_metadata_.insert(std::pair<grpc::string_ref, grpc::string_ref>(
metadata[i].key, metadata[i].key,
@ -194,15 +196,6 @@ bool ServerContext::IsCancelled() const {
} }
} }
void ServerContext::set_compression_level(grpc_compression_level level) {
// TODO(dgq): get rid of grpc_call_compression_for_level and propagate the
// compression level by adding a new argument to
// CallOpSendInitialMetadata::SendInitialMetadata.
const grpc_compression_algorithm algorithm_for_level =
grpc_call_compression_for_level(call_, level);
set_compression_algorithm(algorithm_for_level);
}
void ServerContext::set_compression_algorithm( void ServerContext::set_compression_algorithm(
grpc_compression_algorithm algorithm) { grpc_compression_algorithm algorithm) {
char* algorithm_name = NULL; char* algorithm_name = NULL;

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit.ConsoleRunner" version="3.2.0" />
<package id="OpenCover" version="4.6.519" />
<package id="ReportGenerator" version="2.4.4.0" />
</packages>

@ -1,5 +1,5 @@
{ {
"version": "1.0.0-pre1", "version": "1.0.0-pre2",
"title": "gRPC C# Auth", "title": "gRPC C# Auth",
"authors": [ "Google Inc." ], "authors": [ "Google Inc." ],
"copyright": "Copyright 2015, Google Inc.", "copyright": "Copyright 2015, Google Inc.",
@ -22,7 +22,7 @@
} }
}, },
"dependencies": { "dependencies": {
"Grpc.Core": "1.0.0-pre1", "Grpc.Core": "1.0.0-pre2",
"Google.Apis.Auth": "1.11.1" "Google.Apis.Auth": "1.11.1"
}, },
"frameworks": { "frameworks": {
@ -32,9 +32,9 @@
"net45" "net45"
], ],
"dependencies": { "dependencies": {
"Microsoft.NETCore.Portable.Compatibility": "1.0.1-rc2-24027", "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
"NETStandard.Library": "1.5.0-rc2-24027", "NETStandard.Library": "1.6.0",
"System.Threading.Tasks": "4.0.11-rc2-24027" "System.Threading.Tasks": "4.0.11"
} }
} }
} }

@ -40,7 +40,7 @@ namespace Grpc.Core.Tests
{ {
public class AppDomainUnloadTest public class AppDomainUnloadTest
{ {
#if NETSTANDARD1_5 #if NETCOREAPP1_0
[Test] [Test]
[Ignore("Not supported for CoreCLR")] [Ignore("Not supported for CoreCLR")]
public void AppDomainUnloadHookCanCleanupAbandonedCall() public void AppDomainUnloadHookCanCleanupAbandonedCall()

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

Loading…
Cancel
Save