Merge branch 'master' of github.com:grpc/grpc into tv/watchOS

pull/19703/head^2
Tony Lu 6 years ago
commit 8e99f682e8
  1. 2
      BUILD
  2. 3
      BUILD.gn
  3. 41
      CMakeLists.txt
  4. 42
      Makefile
  5. 12
      build.yaml
  6. 1
      config.m4
  7. 1
      config.w32
  8. 41
      doc/versioning.md
  9. 2
      gRPC-C++.podspec
  10. 3
      gRPC-Core.podspec
  11. 2
      grpc.gemspec
  12. 4
      grpc.gyp
  13. 2
      package.xml
  14. 2
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  15. 2
      src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
  16. 5
      src/core/ext/filters/client_channel/subchannel.cc
  17. 2
      src/core/lib/iomgr/cfstream_handle.cc
  18. 13
      src/core/lib/iomgr/executor/mpmcqueue.cc
  19. 7
      src/core/lib/iomgr/executor/mpmcqueue.h
  20. 138
      src/core/lib/iomgr/executor/threadpool.cc
  21. 153
      src/core/lib/iomgr/executor/threadpool.h
  22. 6
      src/core/lib/iomgr/lockfree_event.cc
  23. 29
      src/objective-c/GRPCClient/GRPCCall.m
  24. 12
      src/objective-c/GRPCClient/private/GRPCChannelPool.m
  25. 47
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
  26. 90
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
  27. 1
      src/objective-c/GRPCClient/private/GRPCHost.m
  28. 1
      src/python/grpcio/grpc_core_dependencies.py
  29. 5
      src/python/grpcio_tests/tests/bazel_namespace_package_hack.py
  30. 2
      src/ruby/lib/grpc/grpc.rb
  31. 14
      test/core/end2end/goaway_server_test.cc
  32. 11
      test/core/iomgr/BUILD
  33. 192
      test/core/iomgr/threadpool_test.cc
  34. 28
      test/core/util/port_server_client.cc
  35. 4
      tools/bazel.rc
  36. 1
      tools/doxygen/Doxyfile.c++
  37. 2
      tools/doxygen/Doxyfile.c++.internal
  38. 1
      tools/doxygen/Doxyfile.core
  39. 3
      tools/doxygen/Doxyfile.core.internal
  40. 23
      tools/internal_ci/macos/grpc_cfstream_asan.cfg
  41. 23
      tools/internal_ci/macos/grpc_cfstream_tsan.cfg
  42. 2
      tools/internal_ci/macos/grpc_run_bazel_tests.sh
  43. 19
      tools/run_tests/generated/sources_and_headers.json
  44. 24
      tools/run_tests/generated/tests.json

@ -704,6 +704,7 @@ grpc_cc_library(
"src/core/lib/iomgr/exec_ctx.cc",
"src/core/lib/iomgr/executor.cc",
"src/core/lib/iomgr/executor/mpmcqueue.cc",
"src/core/lib/iomgr/executor/threadpool.cc",
"src/core/lib/iomgr/fork_posix.cc",
"src/core/lib/iomgr/fork_windows.cc",
"src/core/lib/iomgr/gethostname_fallback.cc",
@ -862,6 +863,7 @@ grpc_cc_library(
"src/core/lib/iomgr/exec_ctx.h",
"src/core/lib/iomgr/executor.h",
"src/core/lib/iomgr/executor/mpmcqueue.h",
"src/core/lib/iomgr/executor/threadpool.h",
"src/core/lib/iomgr/gethostname.h",
"src/core/lib/iomgr/gevent_util.h",
"src/core/lib/iomgr/grpc_if_nametoindex.h",

@ -527,6 +527,8 @@ config("grpc_config") {
"src/core/lib/iomgr/executor.h",
"src/core/lib/iomgr/executor/mpmcqueue.cc",
"src/core/lib/iomgr/executor/mpmcqueue.h",
"src/core/lib/iomgr/executor/threadpool.cc",
"src/core/lib/iomgr/executor/threadpool.h",
"src/core/lib/iomgr/fork_posix.cc",
"src/core/lib/iomgr/fork_windows.cc",
"src/core/lib/iomgr/gethostname.h",
@ -1242,6 +1244,7 @@ config("grpc_config") {
"src/core/lib/iomgr/exec_ctx.h",
"src/core/lib/iomgr/executor.h",
"src/core/lib/iomgr/executor/mpmcqueue.h",
"src/core/lib/iomgr/executor/threadpool.h",
"src/core/lib/iomgr/gethostname.h",
"src/core/lib/iomgr/grpc_if_nametoindex.h",
"src/core/lib/iomgr/internal_errqueue.h",

@ -427,6 +427,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c tcp_server_posix_test)
endif()
add_dependencies(buildtests_c tcp_server_uv_test)
add_dependencies(buildtests_c threadpool_test)
add_dependencies(buildtests_c time_averaged_stats_test)
add_dependencies(buildtests_c timeout_encoding_test)
add_dependencies(buildtests_c timer_heap_test)
@ -1035,6 +1036,7 @@ add_library(grpc
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/executor/mpmcqueue.cc
src/core/lib/iomgr/executor/threadpool.cc
src/core/lib/iomgr/fork_posix.cc
src/core/lib/iomgr/fork_windows.cc
src/core/lib/iomgr/gethostname_fallback.cc
@ -1474,6 +1476,7 @@ add_library(grpc_cronet
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/executor/mpmcqueue.cc
src/core/lib/iomgr/executor/threadpool.cc
src/core/lib/iomgr/fork_posix.cc
src/core/lib/iomgr/fork_windows.cc
src/core/lib/iomgr/gethostname_fallback.cc
@ -1895,6 +1898,7 @@ add_library(grpc_test_util
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/executor/mpmcqueue.cc
src/core/lib/iomgr/executor/threadpool.cc
src/core/lib/iomgr/fork_posix.cc
src/core/lib/iomgr/fork_windows.cc
src/core/lib/iomgr/gethostname_fallback.cc
@ -2229,6 +2233,7 @@ add_library(grpc_test_util_unsecure
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/executor/mpmcqueue.cc
src/core/lib/iomgr/executor/threadpool.cc
src/core/lib/iomgr/fork_posix.cc
src/core/lib/iomgr/fork_windows.cc
src/core/lib/iomgr/gethostname_fallback.cc
@ -2539,6 +2544,7 @@ add_library(grpc_unsecure
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/executor/mpmcqueue.cc
src/core/lib/iomgr/executor/threadpool.cc
src/core/lib/iomgr/fork_posix.cc
src/core/lib/iomgr/fork_windows.cc
src/core/lib/iomgr/gethostname_fallback.cc
@ -3580,6 +3586,7 @@ add_library(grpc++_cronet
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/executor/mpmcqueue.cc
src/core/lib/iomgr/executor/threadpool.cc
src/core/lib/iomgr/fork_posix.cc
src/core/lib/iomgr/fork_windows.cc
src/core/lib/iomgr/gethostname_fallback.cc
@ -10517,6 +10524,40 @@ target_link_libraries(tcp_server_uv_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(threadpool_test
test/core/iomgr/threadpool_test.cc
)
target_include_directories(threadpool_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
target_link_libraries(threadpool_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
)
# avoid dependency on libstdc++
if (_gRPC_CORE_NOSTDCXX_FLAGS)
set_target_properties(threadpool_test PROPERTIES LINKER_LANGUAGE C)
target_compile_options(threadpool_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(time_averaged_stats_test
test/core/iomgr/time_averaged_stats_test.cc
)

@ -1132,6 +1132,7 @@ tcp_client_uv_test: $(BINDIR)/$(CONFIG)/tcp_client_uv_test
tcp_posix_test: $(BINDIR)/$(CONFIG)/tcp_posix_test
tcp_server_posix_test: $(BINDIR)/$(CONFIG)/tcp_server_posix_test
tcp_server_uv_test: $(BINDIR)/$(CONFIG)/tcp_server_uv_test
threadpool_test: $(BINDIR)/$(CONFIG)/threadpool_test
time_averaged_stats_test: $(BINDIR)/$(CONFIG)/time_averaged_stats_test
timeout_encoding_test: $(BINDIR)/$(CONFIG)/timeout_encoding_test
timer_heap_test: $(BINDIR)/$(CONFIG)/timer_heap_test
@ -1553,6 +1554,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/tcp_posix_test \
$(BINDIR)/$(CONFIG)/tcp_server_posix_test \
$(BINDIR)/$(CONFIG)/tcp_server_uv_test \
$(BINDIR)/$(CONFIG)/threadpool_test \
$(BINDIR)/$(CONFIG)/time_averaged_stats_test \
$(BINDIR)/$(CONFIG)/timeout_encoding_test \
$(BINDIR)/$(CONFIG)/timer_heap_test \
@ -2189,6 +2191,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/tcp_server_posix_test || ( echo test tcp_server_posix_test failed ; exit 1 )
$(E) "[RUN] Testing tcp_server_uv_test"
$(Q) $(BINDIR)/$(CONFIG)/tcp_server_uv_test || ( echo test tcp_server_uv_test failed ; exit 1 )
$(E) "[RUN] Testing threadpool_test"
$(Q) $(BINDIR)/$(CONFIG)/threadpool_test || ( echo test threadpool_test failed ; exit 1 )
$(E) "[RUN] Testing time_averaged_stats_test"
$(Q) $(BINDIR)/$(CONFIG)/time_averaged_stats_test || ( echo test time_averaged_stats_test failed ; exit 1 )
$(E) "[RUN] Testing timeout_encoding_test"
@ -3546,6 +3550,7 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/exec_ctx.cc \
src/core/lib/iomgr/executor.cc \
src/core/lib/iomgr/executor/mpmcqueue.cc \
src/core/lib/iomgr/executor/threadpool.cc \
src/core/lib/iomgr/fork_posix.cc \
src/core/lib/iomgr/fork_windows.cc \
src/core/lib/iomgr/gethostname_fallback.cc \
@ -3976,6 +3981,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/iomgr/exec_ctx.cc \
src/core/lib/iomgr/executor.cc \
src/core/lib/iomgr/executor/mpmcqueue.cc \
src/core/lib/iomgr/executor/threadpool.cc \
src/core/lib/iomgr/fork_posix.cc \
src/core/lib/iomgr/fork_windows.cc \
src/core/lib/iomgr/gethostname_fallback.cc \
@ -4387,6 +4393,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/iomgr/exec_ctx.cc \
src/core/lib/iomgr/executor.cc \
src/core/lib/iomgr/executor/mpmcqueue.cc \
src/core/lib/iomgr/executor/threadpool.cc \
src/core/lib/iomgr/fork_posix.cc \
src/core/lib/iomgr/fork_windows.cc \
src/core/lib/iomgr/gethostname_fallback.cc \
@ -4705,6 +4712,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/iomgr/exec_ctx.cc \
src/core/lib/iomgr/executor.cc \
src/core/lib/iomgr/executor/mpmcqueue.cc \
src/core/lib/iomgr/executor/threadpool.cc \
src/core/lib/iomgr/fork_posix.cc \
src/core/lib/iomgr/fork_windows.cc \
src/core/lib/iomgr/gethostname_fallback.cc \
@ -4986,6 +4994,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/exec_ctx.cc \
src/core/lib/iomgr/executor.cc \
src/core/lib/iomgr/executor/mpmcqueue.cc \
src/core/lib/iomgr/executor/threadpool.cc \
src/core/lib/iomgr/fork_posix.cc \
src/core/lib/iomgr/fork_windows.cc \
src/core/lib/iomgr/gethostname_fallback.cc \
@ -5997,6 +6006,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/iomgr/exec_ctx.cc \
src/core/lib/iomgr/executor.cc \
src/core/lib/iomgr/executor/mpmcqueue.cc \
src/core/lib/iomgr/executor/threadpool.cc \
src/core/lib/iomgr/fork_posix.cc \
src/core/lib/iomgr/fork_windows.cc \
src/core/lib/iomgr/gethostname_fallback.cc \
@ -13440,6 +13450,38 @@ endif
endif
THREADPOOL_TEST_SRC = \
test/core/iomgr/threadpool_test.cc \
THREADPOOL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(THREADPOOL_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/threadpool_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/threadpool_test: $(THREADPOOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(THREADPOOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/threadpool_test
endif
$(OBJDIR)/$(CONFIG)/test/core/iomgr/threadpool_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_threadpool_test: $(THREADPOOL_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(THREADPOOL_TEST_OBJS:.o=.dep)
endif
endif
TIME_AVERAGED_STATS_TEST_SRC = \
test/core/iomgr/time_averaged_stats_test.cc \

@ -281,6 +281,7 @@ filegroups:
- src/core/lib/iomgr/exec_ctx.cc
- src/core/lib/iomgr/executor.cc
- src/core/lib/iomgr/executor/mpmcqueue.cc
- src/core/lib/iomgr/executor/threadpool.cc
- src/core/lib/iomgr/fork_posix.cc
- src/core/lib/iomgr/fork_windows.cc
- src/core/lib/iomgr/gethostname_fallback.cc
@ -469,6 +470,7 @@ filegroups:
- src/core/lib/iomgr/exec_ctx.h
- src/core/lib/iomgr/executor.h
- src/core/lib/iomgr/executor/mpmcqueue.h
- src/core/lib/iomgr/executor/threadpool.h
- src/core/lib/iomgr/gethostname.h
- src/core/lib/iomgr/grpc_if_nametoindex.h
- src/core/lib/iomgr/internal_errqueue.h
@ -3734,6 +3736,16 @@ targets:
- gpr
exclude_iomgrs:
- native
- name: threadpool_test
build: test
language: c
src:
- test/core/iomgr/threadpool_test.cc
deps:
- grpc_test_util
- grpc
- gpr
uses_polling: false
- name: time_averaged_stats_test
build: test
language: c

@ -128,6 +128,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/exec_ctx.cc \
src/core/lib/iomgr/executor.cc \
src/core/lib/iomgr/executor/mpmcqueue.cc \
src/core/lib/iomgr/executor/threadpool.cc \
src/core/lib/iomgr/fork_posix.cc \
src/core/lib/iomgr/fork_windows.cc \
src/core/lib/iomgr/gethostname_fallback.cc \

@ -103,6 +103,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\iomgr\\exec_ctx.cc " +
"src\\core\\lib\\iomgr\\executor.cc " +
"src\\core\\lib\\iomgr\\executor\\mpmcqueue.cc " +
"src\\core\\lib\\iomgr\\executor\\threadpool.cc " +
"src\\core\\lib\\iomgr\\fork_posix.cc " +
"src\\core\\lib\\iomgr\\fork_windows.cc " +
"src\\core\\lib\\iomgr\\gethostname_fallback.cc " +

@ -0,0 +1,41 @@
# gRPC Versioning Guide
## Versioning Overview
All gRPC implementations use a three-part version number (`vX.Y.Z`) and strictly follow [semantic versioning](https://semver.org/), which defines the semantics of major, minor and patch components of the version number. In addition to that, gRPC versions evolve according to these rules:
- **Major version bumps** only happen on rare occasions. In order to qualify for a major version bump, certain criteria described later in this document need to be met. Most importantly, a major version increase must not break wire compatibility with other gRPC implementations so that existing gRPC libraries remain fully interoperable.
- **Minor version bumps** happen approx. every 6 weeks as part of the normal release cycle as defined by the gRPC release process. A new release branch named vMAJOR.MINOR.PATCH) is cut every 6 weeks based on the [release schedule](https://github.com/grpc/grpc/blob/master/doc/grpc_release_schedule.md).
- **Patch version bump** corresponds to bugfixes done on release branch.
There are also a few extra rules regarding adding new gRPC implementations (e.g. adding support for a new language)
- New implementations start at v0.x.y version and until they reach 1.0, they are considered not ready for production workloads. Breaking API changes are allowed in the 0.x releases as the library is not considered stable yet.
- The "1.0" release has semantics of GA (generally available) and being production ready. Requirements to reach this milestone are at least these
- basic RPC features are feature complete and tested
- implementation is tested for interoperability with other languages
- Public API is declared stable
- Once a gRPC library reaches 1.0 (or higher version), the normal rules for versioning apply.
## Policy for updating the major version number
To avoid user confusion and simplify reasoning, the gRPC releases in different languages try to stay synchronized in terms of major and minor version (all languages follow the same release schedule). Nevertheless, because we also strictly follow semantic versioning, there are circumstances in which a gRPC implementation needs to break the version synchronicity and do a major version bump independently of other languages.
### Situations when it's ok to do a major version bump
- **change forced by the language ecosystem:** when the language itself or its standard libraries that we depend on make a breaking change (something which is out of our control), reacting with updating gRPC APIs may be the only adequate response.
- **voluntary change:** Even in non-forced situations, there might be circumstances in which a breaking API change makes sense and represents a net win, but as a rule of thumb breaking changes are very disruptive for users, cause user fragmentation and incur high maintenance costs. Therefore, breaking API changes should be very rare events that need to be considered with extreme care and the bar for accepting such changes is intentionally set very high.
Example scenarios where a breaking API change might be adequate:
- fixing a security problem which requires changes to API (need to consider the non-breaking alternatives first)
- the change leads to very significant gains to security, usability or development velocity. These gains need to be clearly documented and claims need to be supported by evidence (ideally by numbers). Costs to the ecosystem (impact on users, dev team etc.) need to be taken into account and the change still needs to be a net positive after subtracting the costs.
All proposals to make a breaking change need to be documented as a gRFC document (in the grpc/proposal repository) that covers at least these areas:
- Description of the proposal including an explanation why the proposed change is one of the very rare events where a breaking change is introduced.
- Migration costs (= what does it mean for the users to migrate to the new API, what are the costs and risks associated with it)
- Pros of the change (what is gained and how)
- Cons of the change (e.g. user confusion, lost users and user trust, work needed, added maintenance costs)
- Plan for supporting users still using the old major version (in case migration to the new major version is not trivial or not everyone can migrate easily)
Note that while major version bump allows changing APIs used by the users, it must not impact the interoperability of the implementation with other gRPC implementations and the previous major version released. That means that **no backward incompatible protocol changes are allowed**: old clients must continue interoperating correctly with new servers and new servers with old clients.
### Situations that DON'T warrant a major version bump
- Because other languages do so. This is not a good enough reason because
doing a major version bump has high potential for disturbing and confusing the users of that language and fragmenting the user base and that is a bigger threat than having language implementations at different major version (provided the state is well documented). Having some languages at different major version seems to be unavoidable anyway (due to forced version bumps), unless we bump some languages artificially.
- "I don't like this API": In retrospect, some API decisions made in the past necessarily turn out more lucky than others, but without strong reasons that would be in favor of changing the API and without enough supporting evidence (see previous section), other strategy than making a breaking API change needs to be used. Possible options: Expand the API to make it useful again; mark API as deprecated while keeping its functionality and providing a new better API.

@ -479,6 +479,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/exec_ctx.h',
'src/core/lib/iomgr/executor.h',
'src/core/lib/iomgr/executor/mpmcqueue.h',
'src/core/lib/iomgr/executor/threadpool.h',
'src/core/lib/iomgr/gethostname.h',
'src/core/lib/iomgr/grpc_if_nametoindex.h',
'src/core/lib/iomgr/internal_errqueue.h',
@ -685,6 +686,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/exec_ctx.h',
'src/core/lib/iomgr/executor.h',
'src/core/lib/iomgr/executor/mpmcqueue.h',
'src/core/lib/iomgr/executor/threadpool.h',
'src/core/lib/iomgr/gethostname.h',
'src/core/lib/iomgr/grpc_if_nametoindex.h',
'src/core/lib/iomgr/internal_errqueue.h',

@ -439,6 +439,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/exec_ctx.h',
'src/core/lib/iomgr/executor.h',
'src/core/lib/iomgr/executor/mpmcqueue.h',
'src/core/lib/iomgr/executor/threadpool.h',
'src/core/lib/iomgr/gethostname.h',
'src/core/lib/iomgr/grpc_if_nametoindex.h',
'src/core/lib/iomgr/internal_errqueue.h',
@ -593,6 +594,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/exec_ctx.cc',
'src/core/lib/iomgr/executor.cc',
'src/core/lib/iomgr/executor/mpmcqueue.cc',
'src/core/lib/iomgr/executor/threadpool.cc',
'src/core/lib/iomgr/fork_posix.cc',
'src/core/lib/iomgr/fork_windows.cc',
'src/core/lib/iomgr/gethostname_fallback.cc',
@ -1095,6 +1097,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/exec_ctx.h',
'src/core/lib/iomgr/executor.h',
'src/core/lib/iomgr/executor/mpmcqueue.h',
'src/core/lib/iomgr/executor/threadpool.h',
'src/core/lib/iomgr/gethostname.h',
'src/core/lib/iomgr/grpc_if_nametoindex.h',
'src/core/lib/iomgr/internal_errqueue.h',

@ -372,6 +372,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/exec_ctx.h )
s.files += %w( src/core/lib/iomgr/executor.h )
s.files += %w( src/core/lib/iomgr/executor/mpmcqueue.h )
s.files += %w( src/core/lib/iomgr/executor/threadpool.h )
s.files += %w( src/core/lib/iomgr/gethostname.h )
s.files += %w( src/core/lib/iomgr/grpc_if_nametoindex.h )
s.files += %w( src/core/lib/iomgr/internal_errqueue.h )
@ -526,6 +527,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/exec_ctx.cc )
s.files += %w( src/core/lib/iomgr/executor.cc )
s.files += %w( src/core/lib/iomgr/executor/mpmcqueue.cc )
s.files += %w( src/core/lib/iomgr/executor/threadpool.cc )
s.files += %w( src/core/lib/iomgr/fork_posix.cc )
s.files += %w( src/core/lib/iomgr/fork_windows.cc )
s.files += %w( src/core/lib/iomgr/gethostname_fallback.cc )

@ -310,6 +310,7 @@
'src/core/lib/iomgr/exec_ctx.cc',
'src/core/lib/iomgr/executor.cc',
'src/core/lib/iomgr/executor/mpmcqueue.cc',
'src/core/lib/iomgr/executor/threadpool.cc',
'src/core/lib/iomgr/fork_posix.cc',
'src/core/lib/iomgr/fork_windows.cc',
'src/core/lib/iomgr/gethostname_fallback.cc',
@ -687,6 +688,7 @@
'src/core/lib/iomgr/exec_ctx.cc',
'src/core/lib/iomgr/executor.cc',
'src/core/lib/iomgr/executor/mpmcqueue.cc',
'src/core/lib/iomgr/executor/threadpool.cc',
'src/core/lib/iomgr/fork_posix.cc',
'src/core/lib/iomgr/fork_windows.cc',
'src/core/lib/iomgr/gethostname_fallback.cc',
@ -938,6 +940,7 @@
'src/core/lib/iomgr/exec_ctx.cc',
'src/core/lib/iomgr/executor.cc',
'src/core/lib/iomgr/executor/mpmcqueue.cc',
'src/core/lib/iomgr/executor/threadpool.cc',
'src/core/lib/iomgr/fork_posix.cc',
'src/core/lib/iomgr/fork_windows.cc',
'src/core/lib/iomgr/gethostname_fallback.cc',
@ -1165,6 +1168,7 @@
'src/core/lib/iomgr/exec_ctx.cc',
'src/core/lib/iomgr/executor.cc',
'src/core/lib/iomgr/executor/mpmcqueue.cc',
'src/core/lib/iomgr/executor/threadpool.cc',
'src/core/lib/iomgr/fork_posix.cc',
'src/core/lib/iomgr/fork_windows.cc',
'src/core/lib/iomgr/gethostname_fallback.cc',

@ -377,6 +377,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/exec_ctx.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/executor.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/executor/mpmcqueue.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/executor/threadpool.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/gethostname.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/grpc_if_nametoindex.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/internal_errqueue.h" role="src" />
@ -531,6 +532,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/exec_ctx.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/executor.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/executor/mpmcqueue.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/executor/threadpool.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/fork_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/fork_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/gethostname_fallback.cc" role="src" />

@ -144,7 +144,7 @@ AresDnsResolver::AresDnsResolver(ResolverArgs args)
arg = grpc_channel_args_find(channel_args_,
GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
min_time_between_resolutions_ =
grpc_channel_arg_get_integer(arg, {1000, 0, INT_MAX});
grpc_channel_arg_get_integer(arg, {1000 * 30, 0, INT_MAX});
// Enable SRV queries option
arg = grpc_channel_args_find(channel_args_, GRPC_ARG_DNS_ENABLE_SRV_QUERIES);
enable_srv_queries_ = grpc_channel_arg_get_bool(arg, false);

@ -110,7 +110,7 @@ NativeDnsResolver::NativeDnsResolver(ResolverArgs args)
const grpc_arg* arg = grpc_channel_args_find(
args.args, GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
min_time_between_resolutions_ =
grpc_channel_arg_get_integer(arg, {1000, 0, INT_MAX});
grpc_channel_arg_get_integer(arg, {1000 * 30, 0, INT_MAX});
interested_parties_ = grpc_pollset_set_create();
if (args.pollset_set != nullptr) {
grpc_pollset_set_add_pollset_set(interested_parties_, args.pollset_set);

@ -140,8 +140,9 @@ RefCountedPtr<SubchannelCall> SubchannelCall::Create(Args args,
const size_t allocation_size =
args.connected_subchannel->GetInitialCallSizeEstimate(
args.parent_data_size);
return RefCountedPtr<SubchannelCall>(new (args.arena->Alloc(
allocation_size)) SubchannelCall(std::move(args), error));
Arena* arena = args.arena;
return RefCountedPtr<SubchannelCall>(new (
arena->Alloc(allocation_size)) SubchannelCall(std::move(args), error));
}
SubchannelCall::SubchannelCall(Args args, grpc_error** error)

@ -184,7 +184,7 @@ void CFStreamHandle::Ref(const char* file, int line, const char* reason) {
void CFStreamHandle::Unref(const char* file, int line, const char* reason) {
if (grpc_tcp_trace.enabled()) {
gpr_atm val = gpr_atm_no_barrier_load(&refcount_.count);
gpr_log(GPR_ERROR,
gpr_log(GPR_DEBUG,
"CFStream Handle unref %p : %s %" PRIdPTR " -> %" PRIdPTR, this,
reason, val, val - 1);
}

@ -98,14 +98,25 @@ void InfLenFIFOQueue::Put(void* elem) {
}
}
void* InfLenFIFOQueue::Get() {
void* InfLenFIFOQueue::Get(gpr_timespec* wait_time) {
MutexLock l(&mu_);
if (count_.Load(MemoryOrder::RELAXED) == 0) {
gpr_timespec start_time;
if (GRPC_TRACE_FLAG_ENABLED(grpc_thread_pool_trace) &&
wait_time != nullptr) {
start_time = gpr_now(GPR_CLOCK_MONOTONIC);
}
num_waiters_++;
do {
wait_nonempty_.Wait(&mu_);
} while (count_.Load(MemoryOrder::RELAXED) == 0);
num_waiters_--;
if (GRPC_TRACE_FLAG_ENABLED(grpc_thread_pool_trace) &&
wait_time != nullptr) {
*wait_time = gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), start_time);
}
}
GPR_DEBUG_ASSERT(count_.Load(MemoryOrder::RELAXED) > 0);
return PopFront();

@ -42,7 +42,8 @@ class MPMCQueueInterface {
// Removes the oldest element from the queue and return it.
// This might cause to block on empty queue depending on implementation.
virtual void* Get() GRPC_ABSTRACT;
// Optional argument for collecting stats purpose.
virtual void* Get(gpr_timespec* wait_time = nullptr) GRPC_ABSTRACT;
// Returns number of elements in the queue currently
virtual int count() const GRPC_ABSTRACT;
@ -65,7 +66,9 @@ class InfLenFIFOQueue : public MPMCQueueInterface {
// Removes the oldest element from the queue and returns it.
// This routine will cause the thread to block if queue is currently empty.
void* Get();
// Argument wait_time should be passed in when turning on the trace flag
// grpc_thread_pool_trace (for collecting stats info purpose.)
void* Get(gpr_timespec* wait_time = nullptr);
// Returns number of elements in queue currently.
// There might be concurrently add/remove on queue, so count might change

@ -0,0 +1,138 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/executor/threadpool.h"
namespace grpc_core {
void ThreadPoolWorker::Run() {
while (true) {
void* elem;
if (GRPC_TRACE_FLAG_ENABLED(grpc_thread_pool_trace)) {
// Updates stats and print
gpr_timespec wait_time = gpr_time_0(GPR_TIMESPAN);
elem = queue_->Get(&wait_time);
stats_.sleep_time = gpr_time_add(stats_.sleep_time, wait_time);
gpr_log(GPR_INFO,
"ThreadPool Worker [%s %d] Stats: sleep_time %f",
thd_name_, index_, gpr_timespec_to_micros(stats_.sleep_time));
} else {
elem = queue_->Get(nullptr);
}
if (elem == nullptr) {
break;
}
// Runs closure
auto* closure =
static_cast<grpc_experimental_completion_queue_functor*>(elem);
closure->functor_run(closure, closure->internal_success);
}
}
void ThreadPool::SharedThreadPoolConstructor() {
// All worker threads in thread pool must be joinable.
thread_options_.set_joinable(true);
// Create at least 1 worker thread.
if (num_threads_ <= 0) num_threads_ = 1;
queue_ = New<InfLenFIFOQueue>();
threads_ = static_cast<ThreadPoolWorker**>(
gpr_zalloc(num_threads_ * sizeof(ThreadPoolWorker*)));
for (int i = 0; i < num_threads_; ++i) {
threads_[i] =
New<ThreadPoolWorker>(thd_name_, this, queue_, thread_options_, i);
threads_[i]->Start();
}
}
size_t ThreadPool::DefaultStackSize() {
#if defined(__ANDROID__) || defined(__APPLE__)
return 1952 * 1024;
#else
return 64 * 1024;
#endif
}
void ThreadPool::AssertHasNotBeenShutDown() {
// For debug checking purpose, using RELAXED order is sufficient.
GPR_DEBUG_ASSERT(!shut_down_.Load(MemoryOrder::RELAXED));
}
ThreadPool::ThreadPool(int num_threads) : num_threads_(num_threads) {
thd_name_ = "ThreadPoolWorker";
thread_options_ = Thread::Options();
thread_options_.set_stack_size(DefaultStackSize());
SharedThreadPoolConstructor();
}
ThreadPool::ThreadPool(int num_threads, const char* thd_name)
: num_threads_(num_threads), thd_name_(thd_name) {
thread_options_ = Thread::Options();
thread_options_.set_stack_size(DefaultStackSize());
SharedThreadPoolConstructor();
}
ThreadPool::ThreadPool(int num_threads, const char* thd_name,
const Thread::Options& thread_options)
: num_threads_(num_threads),
thd_name_(thd_name),
thread_options_(thread_options) {
if (thread_options_.stack_size() == 0) {
thread_options_.set_stack_size(DefaultStackSize());
}
SharedThreadPoolConstructor();
}
ThreadPool::~ThreadPool() {
// For debug checking purpose, using RELAXED order is sufficient.
shut_down_.Store(true, MemoryOrder::RELAXED);
for (int i = 0; i < num_threads_; ++i) {
queue_->Put(nullptr);
}
for (int i = 0; i < num_threads_; ++i) {
threads_[i]->Join();
}
for (int i = 0; i < num_threads_; ++i) {
Delete(threads_[i]);
}
gpr_free(threads_);
Delete(queue_);
}
void ThreadPool::Add(grpc_experimental_completion_queue_functor* closure) {
AssertHasNotBeenShutDown();
queue_->Put(static_cast<void*>(closure));
}
int ThreadPool::num_pending_closures() const { return queue_->count(); }
int ThreadPool::pool_capacity() const { return num_threads_; }
const Thread::Options& ThreadPool::thread_options() const {
return thread_options_;
}
const char* ThreadPool::thread_name() const { return thd_name_; }
} // namespace grpc_core

@ -0,0 +1,153 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_IOMGR_EXECUTOR_THREADPOOL_H
#define GRPC_CORE_LIB_IOMGR_EXECUTOR_THREADPOOL_H
#include <grpc/support/port_platform.h>
#include <grpc/grpc.h>
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/executor/mpmcqueue.h"
namespace grpc_core {
// A base abstract base class for threadpool.
// Threadpool is an executor that maintains a pool of threads sitting around
// and waiting for closures. A threadpool also maintains a queue of pending
// closures, when closures appearing in the queue, the threads in pool will
// pull them out and execute them.
class ThreadPoolInterface {
public:
// Waits for all pending closures to complete, then shuts down thread pool.
virtual ~ThreadPoolInterface() {}
// Schedules a given closure for execution later.
// Depending on specific subclass implementation, this routine might cause
// current thread to be blocked (in case of unable to schedule).
// Closure should contain a function pointer and arguments it will take, more
// details for closure struct at /grpc/include/grpc/impl/codegen/grpc_types.h
virtual void Add(grpc_experimental_completion_queue_functor* closure)
GRPC_ABSTRACT;
// Returns the current number of pending closures
virtual int num_pending_closures() const GRPC_ABSTRACT;
// Returns the capacity of pool (number of worker threads in pool)
virtual int pool_capacity() const GRPC_ABSTRACT;
// Thread option accessor
virtual const Thread::Options& thread_options() const GRPC_ABSTRACT;
// Returns the thread name for threads in this ThreadPool.
virtual const char* thread_name() const GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS
};
// Worker thread for threadpool. Executes closures in the queue, until getting a
// NULL closure.
class ThreadPoolWorker {
public:
ThreadPoolWorker(const char* thd_name, ThreadPoolInterface* pool,
MPMCQueueInterface* queue, Thread::Options& options,
int index)
: queue_(queue), thd_name_(thd_name), index_(index) {
thd_ = Thread(thd_name,
[](void* th) { static_cast<ThreadPoolWorker*>(th)->Run(); },
this, nullptr, options);
}
~ThreadPoolWorker() {}
void Start() { thd_.Start(); }
void Join() { thd_.Join(); }
private:
// struct for tracking stats of thread
struct Stats {
gpr_timespec sleep_time;
Stats() { sleep_time = gpr_time_0(GPR_TIMESPAN); }
};
void Run(); // Pulls closures from queue and executes them
MPMCQueueInterface* queue_; // Queue in thread pool to pull closures from
Thread thd_; // Thread wrapped in
Stats stats_; // Stats to be collected in run time
const char* thd_name_; // Name of thread
int index_; // Index in thread pool
};
// A fixed size thread pool implementation of abstract thread pool interface.
// In this implementation, the number of threads in pool is fixed, but the
// capacity of closure queue is unlimited.
class ThreadPool : public ThreadPoolInterface {
public:
// Creates a thread pool with size of "num_threads", with default thread name
// "ThreadPoolWorker" and all thread options set to default. If the given size
// is 0 or less, there will be 1 worker thread created inside pool.
ThreadPool(int num_threads);
// Same as ThreadPool(int num_threads) constructor, except
// that it also sets "thd_name" as the name of all threads in the thread pool.
ThreadPool(int num_threads, const char* thd_name);
// Same as ThreadPool(const char *thd_name, int num_threads) constructor,
// except that is also set thread_options for threads.
// Notes for stack size:
// If the stack size field of the passed in Thread::Options is set to default
// value 0, default ThreadPool stack size will be used. The current default
// stack size of this implementation is 1952K for mobile platform and 64K for
// all others.
ThreadPool(int num_threads, const char* thd_name,
const Thread::Options& thread_options);
// Waits for all pending closures to complete, then shuts down thread pool.
~ThreadPool() override;
// Adds given closure into pending queue immediately. Since closure queue has
// infinite length, this routine will not block.
void Add(grpc_experimental_completion_queue_functor* closure) override;
int num_pending_closures() const override;
int pool_capacity() const override;
const Thread::Options& thread_options() const override;
const char* thread_name() const override;
private:
int num_threads_ = 0;
const char* thd_name_ = nullptr;
Thread::Options thread_options_;
ThreadPoolWorker** threads_ = nullptr; // Array of worker threads
MPMCQueueInterface* queue_ = nullptr; // Closure queue
Atomic<bool> shut_down_{false}; // Destructor has been called if set to true
void SharedThreadPoolConstructor();
// For ThreadPool, default stack size for mobile platform is 1952K. for other
// platforms is 64K.
size_t DefaultStackSize();
// Internal Use Only for debug checking.
void AssertHasNotBeenShutDown();
};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_IOMGR_EXECUTOR_THREADPOOL_H */

@ -95,7 +95,7 @@ void LockfreeEvent::NotifyOn(grpc_closure* closure) {
* referencing it. */
gpr_atm curr = gpr_atm_acq_load(&state_);
if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
gpr_log(GPR_ERROR, "LockfreeEvent::NotifyOn: %p curr=%p closure=%p", this,
gpr_log(GPR_DEBUG, "LockfreeEvent::NotifyOn: %p curr=%p closure=%p", this,
(void*)curr, closure);
}
switch (curr) {
@ -161,7 +161,7 @@ bool LockfreeEvent::SetShutdown(grpc_error* shutdown_err) {
while (true) {
gpr_atm curr = gpr_atm_no_barrier_load(&state_);
if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
gpr_log(GPR_ERROR, "LockfreeEvent::SetShutdown: %p curr=%p err=%s",
gpr_log(GPR_DEBUG, "LockfreeEvent::SetShutdown: %p curr=%p err=%s",
&state_, (void*)curr, grpc_error_string(shutdown_err));
}
switch (curr) {
@ -210,7 +210,7 @@ void LockfreeEvent::SetReady() {
gpr_atm curr = gpr_atm_no_barrier_load(&state_);
if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
gpr_log(GPR_ERROR, "LockfreeEvent::SetReady: %p curr=%p", &state_,
gpr_log(GPR_DEBUG, "LockfreeEvent::SetReady: %p curr=%p", &state_,
(void*)curr);
}

@ -33,7 +33,6 @@
#import "private/GRPCCallInternal.h"
#import "private/GRPCChannelPool.h"
#import "private/GRPCCompletionQueue.h"
#import "private/GRPCConnectivityMonitor.h"
#import "private/GRPCHost.h"
#import "private/GRPCRequestHeaders.h"
#import "private/GRPCWrappedCall.h"
@ -288,7 +287,6 @@ const char *kCFStreamVarName = "grpc_cfstream";
GRPCCallSafety _callSafety;
GRPCCallOptions *_callOptions;
GRPCWrappedCall *_wrappedCall;
GRPCConnectivityMonitor *_connectivityMonitor;
// The C gRPC library has less guarantees on the ordering of events than we
// do. Particularly, in the face of errors, there's no ordering guarantee at
@ -494,8 +492,6 @@ const char *kCFStreamVarName = "grpc_cfstream";
}
- (void)dealloc {
[GRPCConnectivityMonitor unregisterObserver:self];
__block GRPCWrappedCall *wrappedCall = _wrappedCall;
dispatch_async(_callQueue, ^{
wrappedCall = nil;
@ -794,12 +790,6 @@ const char *kCFStreamVarName = "grpc_cfstream";
[self sendHeaders];
[self invokeCall];
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream != nil && enableCFStream[0] != '1') {
[GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChanged:)];
}
}
// Now that the RPC has been initiated, request writes can start.
@ -902,23 +892,4 @@ const char *kCFStreamVarName = "grpc_cfstream";
}
}
- (void)connectivityChanged:(NSNotification *)note {
// Cancel underlying call upon this notification.
// Retain because connectivity manager only keeps weak reference to GRPCCall.
__strong GRPCCall *strongSelf = self;
if (strongSelf) {
@synchronized(strongSelf) {
[_wrappedCall cancel];
[strongSelf
finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable
userInfo:@{
NSLocalizedDescriptionKey : @"Connectivity lost."
}]];
}
strongSelf->_requestWriter.state = GRXWriterStateFinished;
}
}
@end

@ -24,7 +24,6 @@
#import "GRPCChannelPool+Test.h"
#import "GRPCChannelPool.h"
#import "GRPCCompletionQueue.h"
#import "GRPCConnectivityMonitor.h"
#import "GRPCCronetChannelFactory.h"
#import "GRPCInsecureChannelFactory.h"
#import "GRPCSecureChannelFactory.h"
@ -215,18 +214,11 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30;
- (instancetype)initPrivate {
if ((self = [super init])) {
_channelPool = [NSMutableDictionary dictionary];
// Connectivity monitor is not required for CFStream
char *enableCFStream = getenv(kCFStreamVarName);
if (enableCFStream == nil || enableCFStream[0] != '1') {
[GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)];
}
}
return self;
}
- (void)dealloc {
[GRPCConnectivityMonitor unregisterObserver:self];
}
- (GRPCPooledChannel *)channelWithHost:(NSString *)host callOptions:(GRPCCallOptions *)callOptions {
@ -267,10 +259,6 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30;
}
}
- (void)connectivityChange:(NSNotification *)note {
[self disconnectAllChannels];
}
@end
@implementation GRPCChannelPool (Test)

@ -1,47 +0,0 @@
/*
*
* Copyright 2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
typedef NS_ENUM(NSInteger, GRPCConnectivityStatus) {
GRPCConnectivityUnknown = 0,
GRPCConnectivityNoNetwork = 1,
GRPCConnectivityCellular = 2,
GRPCConnectivityWiFi = 3,
};
extern NSString* _Nonnull kGRPCConnectivityNotification;
// This interface monitors OS reachability interface for any network status
// change. Parties interested in these events should register themselves as
// observer.
@interface GRPCConnectivityMonitor : NSObject
- (nonnull instancetype)init NS_UNAVAILABLE;
// Register an object as observer of network status change. \a observer
// must have a notification method with one parameter of type
// (NSNotification *) and should pass it to parameter \a selector. The
// parameter of this notification method is not used for now.
+ (void)registerObserver:(_Nonnull id)observer selector:(_Nonnull SEL)selector;
// Ungegister an object from observers of network status change.
+ (void)unregisterObserver:(_Nonnull id)observer;
@end

@ -1,90 +0,0 @@
/*
*
* Copyright 2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#import "GRPCConnectivityMonitor.h"
#include <netinet/in.h>
NSString *kGRPCConnectivityNotification = @"kGRPCConnectivityNotification";
static SCNetworkReachabilityRef reachability;
static GRPCConnectivityStatus currentStatus;
// Aggregate information in flags into network status.
GRPCConnectivityStatus CalculateConnectivityStatus(SCNetworkReachabilityFlags flags) {
GRPCConnectivityStatus result = GRPCConnectivityUnknown;
if (((flags & kSCNetworkReachabilityFlagsReachable) == 0) ||
((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0)) {
return GRPCConnectivityNoNetwork;
}
result = GRPCConnectivityWiFi;
#if TARGET_OS_IPHONE
if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
return result = GRPCConnectivityCellular;
}
#endif
return result;
}
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags,
void *info) {
GRPCConnectivityStatus newStatus = CalculateConnectivityStatus(flags);
if (newStatus != currentStatus) {
[[NSNotificationCenter defaultCenter] postNotificationName:kGRPCConnectivityNotification
object:nil];
currentStatus = newStatus;
}
}
@implementation GRPCConnectivityMonitor
+ (void)initialize {
if (self == [GRPCConnectivityMonitor self]) {
struct sockaddr_in addr = {0};
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
reachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&addr);
currentStatus = GRPCConnectivityUnknown;
SCNetworkConnectionFlags flags;
if (SCNetworkReachabilityGetFlags(reachability, &flags)) {
currentStatus = CalculateConnectivityStatus(flags);
}
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
if (!SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context) ||
!SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(),
kCFRunLoopCommonModes)) {
NSLog(@"gRPC connectivity monitor fail to set");
}
}
}
+ (void)registerObserver:(id)observer selector:(SEL)selector {
[[NSNotificationCenter defaultCenter] addObserver:observer
selector:selector
name:kGRPCConnectivityNotification
object:nil];
}
+ (void)unregisterObserver:(id)observer {
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}
@end

@ -28,7 +28,6 @@
#import "../internal/GRPCCallOptions+Internal.h"
#import "GRPCChannelFactory.h"
#import "GRPCCompletionQueue.h"
#import "GRPCConnectivityMonitor.h"
#import "GRPCCronetChannelFactory.h"
#import "GRPCSecureChannelFactory.h"
#import "NSDictionary+GRPC.h"

@ -102,6 +102,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/exec_ctx.cc',
'src/core/lib/iomgr/executor.cc',
'src/core/lib/iomgr/executor/mpmcqueue.cc',
'src/core/lib/iomgr/executor/threadpool.cc',
'src/core/lib/iomgr/fork_posix.cc',
'src/core/lib/iomgr/fork_windows.cc',
'src/core/lib/iomgr/gethostname_fallback.cc',

@ -16,6 +16,8 @@ import os
import site
import sys
_GRPC_BAZEL_RUNTIME_ENV = "GRPC_BAZEL_RUNTIME"
# TODO(https://github.com/bazelbuild/bazel/issues/6844) Bazel failed to
# interpret namespace packages correctly. This monkey patch will force the
@ -24,6 +26,9 @@ import sys
# Analysis in depth: https://github.com/bazelbuild/rules_python/issues/55
def sys_path_to_site_dir_hack():
"""Add valid sys.path item to site directory to parse the .pth files."""
# Only run within our Bazel environment
if not os.environ.get(_GRPC_BAZEL_RUNTIME_ENV):
return
items = []
for item in sys.path:
if os.path.exists(item):

@ -17,7 +17,7 @@ begin
distrib_lib_dir = File.expand_path(ruby_version_dirname,
File.dirname(__FILE__))
if File.directory?(distrib_lib_dir)
require_relative "#{distrib_lib_dir}/grpc_c"
require "#{distrib_lib_dir}/grpc_c"
else
require 'grpc/grpc_c'
end

@ -185,13 +185,23 @@ int main(int argc, char** argv) {
char* addr;
grpc_channel_args client_args;
grpc_arg arg_array[1];
grpc_arg arg_array[2];
arg_array[0].type = GRPC_ARG_INTEGER;
arg_array[0].key =
const_cast<char*>("grpc.testing.fixed_reconnect_backoff_ms");
arg_array[0].value.integer = 1000;
/* When this test brings down server1 and then brings up server2,
* the targetted server port number changes, and the client channel
* needs to re-resolve to pick this up. This test requires that
* happen within 10 seconds, but gRPC's DNS resolvers rate limit
* resolution attempts to at most once every 30 seconds by default.
* So we tweak it for this test. */
arg_array[1].type = GRPC_ARG_INTEGER;
arg_array[1].key =
const_cast<char*>(GRPC_ARG_DNS_MIN_TIME_BETWEEN_RESOLUTIONS_MS);
arg_array[1].value.integer = 1000;
client_args.args = arg_array;
client_args.num_args = 1;
client_args.num_args = 2;
/* create a channel that picks first amongst the servers */
grpc_channel* chan =

@ -281,6 +281,17 @@ grpc_cc_test(
tags = ["no_windows"],
)
grpc_cc_test(
name = "threadpool_test",
srcs = ["threadpool_test.cc"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "time_averaged_stats_test",
srcs = ["time_averaged_stats_test.cc"],

@ -0,0 +1,192 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "src/core/lib/iomgr/executor/threadpool.h"
#include "test/core/util/test_config.h"
static const int kSmallThreadPoolSize = 20;
static const int kLargeThreadPoolSize = 100;
static const int kThreadSmallIter = 100;
static const int kThreadLargeIter = 10000;
static void test_size_zero(void) {
gpr_log(GPR_INFO, "test_size_zero");
grpc_core::ThreadPool* pool_size_zero =
grpc_core::New<grpc_core::ThreadPool>(0);
GPR_ASSERT(pool_size_zero->pool_capacity() == 1);
Delete(pool_size_zero);
}
static void test_constructor_option(void) {
gpr_log(GPR_INFO, "test_constructor_option");
// Tests options
grpc_core::Thread::Options options;
options.set_stack_size(192 * 1024); // Random non-default value
grpc_core::ThreadPool* pool = grpc_core::New<grpc_core::ThreadPool>(
0, "test_constructor_option", options);
GPR_ASSERT(pool->thread_options().stack_size() == options.stack_size());
Delete(pool);
}
// Simple functor for testing. It will count how many times being called.
class SimpleFunctorForAdd : public grpc_experimental_completion_queue_functor {
public:
friend class SimpleFunctorCheckForAdd;
SimpleFunctorForAdd() {
functor_run = &SimpleFunctorForAdd::Run;
internal_next = this;
internal_success = 0;
}
~SimpleFunctorForAdd() {}
static void Run(struct grpc_experimental_completion_queue_functor* cb,
int ok) {
auto* callback = static_cast<SimpleFunctorForAdd*>(cb);
callback->count_.FetchAdd(1, grpc_core::MemoryOrder::RELAXED);
}
int count() { return count_.Load(grpc_core::MemoryOrder::RELAXED); }
private:
grpc_core::Atomic<int> count_{0};
};
static void test_add(void) {
gpr_log(GPR_INFO, "test_add");
grpc_core::ThreadPool* pool =
grpc_core::New<grpc_core::ThreadPool>(kSmallThreadPoolSize, "test_add");
SimpleFunctorForAdd* functor = grpc_core::New<SimpleFunctorForAdd>();
for (int i = 0; i < kThreadSmallIter; ++i) {
pool->Add(functor);
}
grpc_core::Delete(pool);
GPR_ASSERT(functor->count() == kThreadSmallIter);
grpc_core::Delete(functor);
gpr_log(GPR_DEBUG, "Done.");
}
// Thread that adds closures to pool
class WorkThread {
public:
WorkThread(grpc_core::ThreadPool* pool, SimpleFunctorForAdd* cb, int num_add)
: num_add_(num_add), cb_(cb), pool_(pool) {
thd_ = grpc_core::Thread(
"thread_pool_test_add_thd",
[](void* th) { static_cast<WorkThread*>(th)->Run(); }, this);
}
~WorkThread() {}
void Start() { thd_.Start(); }
void Join() { thd_.Join(); }
private:
void Run() {
for (int i = 0; i < num_add_; ++i) {
pool_->Add(cb_);
}
}
int num_add_;
SimpleFunctorForAdd* cb_;
grpc_core::ThreadPool* pool_;
grpc_core::Thread thd_;
};
static void test_multi_add(void) {
gpr_log(GPR_INFO, "test_multi_add");
const int num_work_thds = 10;
grpc_core::ThreadPool* pool = grpc_core::New<grpc_core::ThreadPool>(
kLargeThreadPoolSize, "test_multi_add");
SimpleFunctorForAdd* functor = grpc_core::New<SimpleFunctorForAdd>();
WorkThread** work_thds = static_cast<WorkThread**>(
gpr_zalloc(sizeof(WorkThread*) * num_work_thds));
gpr_log(GPR_DEBUG, "Fork threads for adding...");
for (int i = 0; i < num_work_thds; ++i) {
work_thds[i] = grpc_core::New<WorkThread>(pool, functor, kThreadLargeIter);
work_thds[i]->Start();
}
// Wait for all threads finish
gpr_log(GPR_DEBUG, "Waiting for all work threads finish...");
for (int i = 0; i < num_work_thds; ++i) {
work_thds[i]->Join();
grpc_core::Delete(work_thds[i]);
}
gpr_free(work_thds);
gpr_log(GPR_DEBUG, "Done.");
gpr_log(GPR_DEBUG, "Waiting for all closures finish...");
// Destructor of thread pool will wait for all closures to finish
grpc_core::Delete(pool);
GPR_ASSERT(functor->count() == kThreadLargeIter * num_work_thds);
grpc_core::Delete(functor);
gpr_log(GPR_DEBUG, "Done.");
}
// Checks the current count with a given number.
class SimpleFunctorCheckForAdd
: public grpc_experimental_completion_queue_functor {
public:
SimpleFunctorCheckForAdd(int ok, int* count) : count_(count) {
functor_run = &SimpleFunctorCheckForAdd::Run;
internal_success = ok;
}
~SimpleFunctorCheckForAdd() {}
static void Run(struct grpc_experimental_completion_queue_functor* cb,
int ok) {
auto* callback = static_cast<SimpleFunctorCheckForAdd*>(cb);
(*callback->count_)++;
GPR_ASSERT(*callback->count_ == callback->internal_success);
}
private:
int* count_;
};
static void test_one_thread_FIFO(void) {
gpr_log(GPR_INFO, "test_one_thread_FIFO");
int counter = 0;
grpc_core::ThreadPool* pool =
grpc_core::New<grpc_core::ThreadPool>(1, "test_one_thread_FIFO");
SimpleFunctorCheckForAdd** check_functors =
static_cast<SimpleFunctorCheckForAdd**>(
gpr_zalloc(sizeof(SimpleFunctorCheckForAdd*) * kThreadSmallIter));
for (int i = 0; i < kThreadSmallIter; ++i) {
check_functors[i] =
grpc_core::New<SimpleFunctorCheckForAdd>(i + 1, &counter);
pool->Add(check_functors[i]);
}
// Destructor of pool will wait until all closures finished.
grpc_core::Delete(pool);
for (int i = 0; i < kThreadSmallIter; ++i) {
grpc_core::Delete(check_functors[i]);
}
gpr_free(check_functors);
gpr_log(GPR_DEBUG, "Done.");
}
int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
test_size_zero();
test_constructor_option();
test_add();
test_multi_add();
test_one_thread_FIFO();
grpc_shutdown();
return 0;
}

@ -35,9 +35,9 @@
#include "src/core/lib/http/httpcli.h"
typedef struct freereq {
gpr_mu* mu;
grpc_polling_entity pops;
int done;
gpr_mu* mu = nullptr;
grpc_polling_entity pops = {};
int done = 0;
} freereq;
static void destroy_pops_and_shutdown(void* p, grpc_error* error) {
@ -68,9 +68,9 @@ void grpc_free_port_using_server(int port) {
grpc_init();
memset(&pr, 0, sizeof(pr));
pr = {};
memset(&req, 0, sizeof(req));
memset(&rsp, 0, sizeof(rsp));
rsp = {};
grpc_pollset* pollset =
static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
@ -117,13 +117,13 @@ void grpc_free_port_using_server(int port) {
}
typedef struct portreq {
gpr_mu* mu;
grpc_polling_entity pops;
int port;
int retries;
char* server;
grpc_httpcli_context* ctx;
grpc_httpcli_response response;
gpr_mu* mu = nullptr;
grpc_polling_entity pops = {};
int port = 0;
int retries = 0;
char* server = nullptr;
grpc_httpcli_context* ctx = nullptr;
grpc_httpcli_response response = {};
} portreq;
static void got_port_from_server(void* arg, grpc_error* error) {
@ -167,7 +167,7 @@ static void got_port_from_server(void* arg, grpc_error* error) {
req.host = pr->server;
req.http.path = const_cast<char*>("/get");
grpc_http_response_destroy(&pr->response);
memset(&pr->response, 0, sizeof(pr->response));
pr->response = {};
grpc_resource_quota* resource_quota =
grpc_resource_quota_create("port_server_client/pick_retry");
grpc_httpcli_get(pr->ctx, &pr->pops, resource_quota, &req,
@ -202,7 +202,7 @@ int grpc_pick_port_using_server(void) {
grpc_init();
{
grpc_core::ExecCtx exec_ctx;
memset(&pr, 0, sizeof(pr));
pr = {};
memset(&req, 0, sizeof(req));
grpc_pollset* pollset =
static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));

@ -5,6 +5,7 @@
build --client_env=CC=clang
build --copt=-DGRPC_BAZEL_BUILD
build --action_env=GRPC_BAZEL_RUNTIME=1
build:opt --compilation_mode=opt
build:opt --copt=-Wframe-larger-than=16384
@ -12,6 +13,9 @@ build:opt --copt=-Wframe-larger-than=16384
build:dbg --compilation_mode=dbg
build:asan --strip=never
# Workaround for https://github.com/bazelbuild/bazel/issues/6932
build:asan --copt -Wno-macro-redefined
build:asan --copt -D_FORTIFY_SOURCE=0
build:asan --copt=-fsanitize=address
build:asan --copt=-O0
build:asan --copt=-fno-omit-frame-pointer

@ -794,6 +794,7 @@ doc/ssl-performance.md \
doc/status_ordering.md \
doc/statuscodes.md \
doc/unit_testing.md \
doc/versioning.md \
doc/wait-for-ready.md \
doc/workarounds.md \
include/grpc++/alarm.h \

@ -794,6 +794,7 @@ doc/ssl-performance.md \
doc/status_ordering.md \
doc/statuscodes.md \
doc/unit_testing.md \
doc/versioning.md \
doc/wait-for-ready.md \
doc/workarounds.md \
include/grpc++/alarm.h \
@ -1144,6 +1145,7 @@ src/core/lib/iomgr/ev_posix.h \
src/core/lib/iomgr/exec_ctx.h \
src/core/lib/iomgr/executor.h \
src/core/lib/iomgr/executor/mpmcqueue.h \
src/core/lib/iomgr/executor/threadpool.h \
src/core/lib/iomgr/gethostname.h \
src/core/lib/iomgr/grpc_if_nametoindex.h \
src/core/lib/iomgr/internal_errqueue.h \

@ -801,6 +801,7 @@ doc/ssl-performance.md \
doc/status_ordering.md \
doc/statuscodes.md \
doc/unit_testing.md \
doc/versioning.md \
doc/wait-for-ready.md \
doc/workarounds.md \
include/grpc/byte_buffer.h \

@ -801,6 +801,7 @@ doc/ssl-performance.md \
doc/status_ordering.md \
doc/statuscodes.md \
doc/unit_testing.md \
doc/versioning.md \
doc/wait-for-ready.md \
doc/workarounds.md \
include/grpc/byte_buffer.h \
@ -1236,6 +1237,8 @@ src/core/lib/iomgr/executor.cc \
src/core/lib/iomgr/executor.h \
src/core/lib/iomgr/executor/mpmcqueue.cc \
src/core/lib/iomgr/executor/mpmcqueue.h \
src/core/lib/iomgr/executor/threadpool.cc \
src/core/lib/iomgr/executor/threadpool.h \
src/core/lib/iomgr/fork_posix.cc \
src/core/lib/iomgr/fork_windows.cc \
src/core/lib/iomgr/gethostname.h \

@ -0,0 +1,23 @@
# Copyright 2019 The gRPC Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Config file for the internal CI (in protobuf text format)
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/macos/grpc_run_bazel_tests.sh"
env_vars {
key: "RUN_TESTS_FLAGS"
value: "--config=asan"
}

@ -0,0 +1,23 @@
# Copyright 2019 The gRPC Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Config file for the internal CI (in protobuf text format)
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/macos/grpc_run_bazel_tests.sh"
env_vars {
key: "RUN_TESTS_FLAGS"
value: "--config=tsan"
}

@ -29,7 +29,7 @@ which bazel
./tools/run_tests/start_port_server.py
# run cfstream_test separately because it messes with the network
bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=all //test/cpp/end2end:cfstream_test
bazel test $RUN_TESTS_FLAGS --spawn_strategy=standalone --genrule_strategy=standalone --test_output=all //test/cpp/end2end:cfstream_test
# kill port_server.py to prevent the build from hanging
ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9

@ -2251,6 +2251,22 @@
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
"grpc",
"grpc_test_util"
],
"headers": [],
"is_filegroup": false,
"language": "c",
"name": "threadpool_test",
"src": [
"test/core/iomgr/threadpool_test.cc"
],
"third_party": false,
"type": "target"
},
{
"deps": [
"gpr",
@ -8541,6 +8557,7 @@
"src/core/lib/iomgr/exec_ctx.cc",
"src/core/lib/iomgr/executor.cc",
"src/core/lib/iomgr/executor/mpmcqueue.cc",
"src/core/lib/iomgr/executor/threadpool.cc",
"src/core/lib/iomgr/fork_posix.cc",
"src/core/lib/iomgr/fork_windows.cc",
"src/core/lib/iomgr/gethostname_fallback.cc",
@ -8730,6 +8747,7 @@
"src/core/lib/iomgr/exec_ctx.h",
"src/core/lib/iomgr/executor.h",
"src/core/lib/iomgr/executor/mpmcqueue.h",
"src/core/lib/iomgr/executor/threadpool.h",
"src/core/lib/iomgr/gethostname.h",
"src/core/lib/iomgr/grpc_if_nametoindex.h",
"src/core/lib/iomgr/internal_errqueue.h",
@ -8889,6 +8907,7 @@
"src/core/lib/iomgr/exec_ctx.h",
"src/core/lib/iomgr/executor.h",
"src/core/lib/iomgr/executor/mpmcqueue.h",
"src/core/lib/iomgr/executor/threadpool.h",
"src/core/lib/iomgr/gethostname.h",
"src/core/lib/iomgr/grpc_if_nametoindex.h",
"src/core/lib/iomgr/internal_errqueue.h",

@ -2793,6 +2793,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": false,
"language": "c",
"name": "threadpool_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save