Merge pull request #11154 from kpayson64/hack_for_disconnects
Reconnect disconnected channels automatically
diff --git a/BUILD b/BUILD
index 4087216..166e6ba 100644
--- a/BUILD
+++ b/BUILD
@@ -40,9 +40,9 @@
# This should be updated along with build.yaml
g_stands_for = "gentle"
-core_version = "3.0.0-pre1"
+core_version = "3.0.0"
-version = "1.3.0-pre1"
+version = "1.3.5"
grpc_cc_library(
name = "gpr",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 81dba56..cff8f85 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -39,7 +39,7 @@
cmake_minimum_required(VERSION 2.8)
set(PACKAGE_NAME "grpc")
-set(PACKAGE_VERSION "1.3.0-pre1")
+set(PACKAGE_VERSION "1.3.5")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
@@ -475,6 +475,7 @@
add_dependencies(buildtests_c multiple_server_queues_test)
add_dependencies(buildtests_c murmur_hash_test)
add_dependencies(buildtests_c no_server_test)
+add_dependencies(buildtests_c num_external_connectivity_watchers_test)
add_dependencies(buildtests_c parse_address_test)
add_dependencies(buildtests_c percent_encoding_test)
if(_gRPC_PLATFORM_LINUX)
@@ -7580,6 +7581,37 @@
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
+add_executable(num_external_connectivity_watchers_test
+ test/core/surface/num_external_connectivity_watchers_test.c
+)
+
+
+target_include_directories(num_external_connectivity_watchers_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${BORINGSSL_ROOT_DIR}/include
+ PRIVATE ${PROTOBUF_ROOT_DIR}/src
+ PRIVATE ${BENCHMARK_ROOT_DIR}/include
+ PRIVATE ${ZLIB_ROOT_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+ PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+ PRIVATE ${CARES_INCLUDE_DIR}
+ PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(num_external_connectivity_watchers_test
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc_test_util
+ grpc
+ gpr_test_util
+ gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
add_executable(parse_address_test
test/core/client_channel/parse_address_test.c
)
diff --git a/Makefile b/Makefile
index 01e06f1..77206ba 100644
--- a/Makefile
+++ b/Makefile
@@ -419,9 +419,9 @@
Q = @
endif
-CORE_VERSION = 3.0.0-pre1
-CPP_VERSION = 1.3.0-pre1
-CSHARP_VERSION = 1.3.0-pre1
+CORE_VERSION = 3.0.0
+CPP_VERSION = 1.3.5
+CSHARP_VERSION = 1.3.5
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -1056,6 +1056,7 @@
nanopb_fuzzer_response_test: $(BINDIR)/$(CONFIG)/nanopb_fuzzer_response_test
nanopb_fuzzer_serverlist_test: $(BINDIR)/$(CONFIG)/nanopb_fuzzer_serverlist_test
no_server_test: $(BINDIR)/$(CONFIG)/no_server_test
+num_external_connectivity_watchers_test: $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test
parse_address_test: $(BINDIR)/$(CONFIG)/parse_address_test
percent_decode_fuzzer: $(BINDIR)/$(CONFIG)/percent_decode_fuzzer
percent_encode_fuzzer: $(BINDIR)/$(CONFIG)/percent_encode_fuzzer
@@ -1427,6 +1428,7 @@
$(BINDIR)/$(CONFIG)/multiple_server_queues_test \
$(BINDIR)/$(CONFIG)/murmur_hash_test \
$(BINDIR)/$(CONFIG)/no_server_test \
+ $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test \
$(BINDIR)/$(CONFIG)/parse_address_test \
$(BINDIR)/$(CONFIG)/percent_encoding_test \
$(BINDIR)/$(CONFIG)/pollset_set_test \
@@ -1883,6 +1885,8 @@
$(Q) $(BINDIR)/$(CONFIG)/murmur_hash_test || ( echo test murmur_hash_test failed ; exit 1 )
$(E) "[RUN] Testing no_server_test"
$(Q) $(BINDIR)/$(CONFIG)/no_server_test || ( echo test no_server_test failed ; exit 1 )
+ $(E) "[RUN] Testing num_external_connectivity_watchers_test"
+ $(Q) $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test || ( echo test num_external_connectivity_watchers_test failed ; exit 1 )
$(E) "[RUN] Testing parse_address_test"
$(Q) $(BINDIR)/$(CONFIG)/parse_address_test || ( echo test parse_address_test failed ; exit 1 )
$(E) "[RUN] Testing percent_encoding_test"
@@ -8241,8 +8245,8 @@
LIBARES_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBARES_SRC))))
-$(LIBARES_OBJS): CPPFLAGS += -Ithird_party/cares -Ithird_party/cares/cares $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux) $(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) -fvisibility=hidden -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DHAVE_CONFIG_H
-$(LIBARES_OBJS): CFLAGS += -Wno-sign-conversion -Wno-invalid-source-encoding
+$(LIBARES_OBJS): CPPFLAGS += -Ithird_party/cares -Ithird_party/cares/cares $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux) $(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) -fvisibility=hidden -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
+$(LIBARES_OBJS): CFLAGS += -Wno-sign-conversion $(if $(subst MINGW32,,$(SYSTEM)),-Wno-invalid-source-encoding,)
$(LIBDIR)/$(CONFIG)/libares.a: $(ZLIB_DEP) $(LIBARES_OBJS)
$(E) "[AR] Creating $@"
@@ -11810,6 +11814,38 @@
endif
+NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_SRC = \
+ test/core/surface/num_external_connectivity_watchers_test.c \
+
+NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test: $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_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) $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_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)/num_external_connectivity_watchers_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/surface/num_external_connectivity_watchers_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_num_external_connectivity_watchers_test: $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
PARSE_ADDRESS_TEST_SRC = \
test/core/client_channel/parse_address_test.c \
diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
index 8465305..bb76b38 100644
--- a/PYTHON-MANIFEST.in
+++ b/PYTHON-MANIFEST.in
@@ -7,7 +7,7 @@
graft third_party/boringssl
graft third_party/nanopb
graft third_party/zlib
-graft third_party/c-ares
+graft third_party/cares
include src/python/grpcio/_spawn_patch.py
include src/python/grpcio/commands.py
include src/python/grpcio/grpc_version.py
diff --git a/Rakefile b/Rakefile
index cc02aa1..7f8d3a2 100755
--- a/Rakefile
+++ b/Rakefile
@@ -80,7 +80,7 @@
grpc_config = ENV['GRPC_CONFIG'] || 'opt'
verbose = ENV['V'] || '0'
- env = 'CPPFLAGS="-D_WIN32_WINNT=0x600 -DUNICODE -D_UNICODE -Wno-unused-variable -Wno-unused-result" '
+ env = 'CPPFLAGS="-D_WIN32_WINNT=0x600 -DUNICODE -D_UNICODE -Wno-unused-variable -Wno-unused-result -DCARES_STATICLIB" '
env += 'LDFLAGS=-static '
env += 'SYSTEM=MINGW32 '
env += 'EMBED_ZLIB=true '
diff --git a/WORKSPACE b/WORKSPACE
index 5a3c4de..5ba82f3 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -77,12 +77,6 @@
path = "third_party/gflags",
)
-git_repository(
- name = "mongoose_repo",
- commit = "4120a97945b41195a6223a600dae8e3b19bed19e",
- remote = "https://github.com/makdharma/mongoose.git"
-)
-
new_local_repository(
name = "submodule_benchmark",
path = "third_party/benchmark",
diff --git a/binding.gyp b/binding.gyp
index 16334a2..a449730 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -39,15 +39,16 @@
{
'variables': {
'runtime%': 'node',
- # UV integration in C core is enabled by default. It can be disabled
- # by setting this argument to anything else.
- 'grpc_uv%': 'true',
# Some Node installations use the system installation of OpenSSL, and on
# some systems, the system OpenSSL still does not have ALPN support. This
# will let users recompile gRPC to work without ALPN.
'grpc_alpn%': 'true',
# Indicates that the library should be built with gcov.
- 'grpc_gcov%': 'false'
+ 'grpc_gcov%': 'false',
+ # Indicates that the library should be built with compatibility for musl
+ # libc, so that it can run on Alpine Linux. This is only necessary if not
+ # building on Alpine Linux
+ 'grpc_alpine%': 'false'
},
'target_defaults': {
'configurations': {
@@ -86,17 +87,11 @@
'include'
],
'defines': [
- 'GPR_BACKWARDS_COMPATIBILITY_MODE'
+ 'GPR_BACKWARDS_COMPATIBILITY_MODE',
+ 'GRPC_ARES=0',
+ 'GRPC_UV'
],
'conditions': [
- ['grpc_uv=="true"', {
- 'defines': [
- 'GRPC_ARES=0',
- # Disabling this while bugs are ironed out. Uncomment this to
- # re-enable libuv integration in C core.
- 'GRPC_UV'
- ]
- }],
['grpc_gcov=="true"', {
'cflags': [
'-O0',
@@ -115,6 +110,11 @@
'-rdynamic',
],
}],
+ ['grpc_alpine=="true"', {
+ 'defines': [
+ 'GPR_MUSL_LIBC_COMPAT'
+ ]
+ }],
['OS!="win" and runtime=="electron"', {
"defines": [
'OPENSSL_NO_THREADS'
@@ -535,6 +535,10 @@
}
]
},
+ ]
+ }],
+ ['OS == "win"', {
+ 'targets': [
# Only want to compile zlib under Windows
{
'cflags': [
@@ -569,7 +573,6 @@
}]
],
'targets': [
-
{
'cflags': [
'-std=c99',
@@ -648,7 +651,6 @@
'type': 'static_library',
'dependencies': [
'gpr',
- 'node_modules/cares/deps/cares/cares.gyp:cares',
],
'sources': [
'src/core/lib/surface/init.c',
@@ -938,20 +940,16 @@
"src/node/ext/call_credentials.cc",
"src/node/ext/channel.cc",
"src/node/ext/channel_credentials.cc",
- "src/node/ext/completion_queue_threadpool.cc",
- "src/node/ext/completion_queue_uv.cc",
+ "src/node/ext/completion_queue.cc",
"src/node/ext/node_grpc.cc",
"src/node/ext/server.cc",
"src/node/ext/server_credentials.cc",
- "src/node/ext/server_generic.cc",
- "src/node/ext/server_uv.cc",
"src/node/ext/slice.cc",
"src/node/ext/timeval.cc",
],
"dependencies": [
"grpc",
"gpr",
- "node_modules/cares/deps/cares/cares.gyp:cares",
]
},
{
diff --git a/build.yaml b/build.yaml
index 781118f..3af5906 100644
--- a/build.yaml
+++ b/build.yaml
@@ -12,9 +12,9 @@
'#08': Use "-preN" suffixes to identify pre-release versions
'#09': Per-language overrides are possible with (eg) ruby_version tag here
'#10': See the expand_version.py for all the quirks here
- core_version: 3.0.0-pre1
+ core_version: 3.0.0
g_stands_for: gentle
- version: 1.3.0-pre1
+ version: 1.3.5
filegroups:
- name: census
public_headers:
@@ -2586,6 +2586,18 @@
- grpc
- gpr_test_util
- gpr
+- name: num_external_connectivity_watchers_test
+ build: test
+ language: c
+ src:
+ - test/core/surface/num_external_connectivity_watchers_test.c
+ deps:
+ - grpc_test_util
+ - grpc
+ - gpr_test_util
+ - gpr
+ exclude_iomgrs:
+ - uv
- name: parse_address_test
build: test
language: c
@@ -4407,10 +4419,11 @@
UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1:suppressions=tools/ubsan_suppressions.txt
defaults:
ares:
- CFLAGS: -Wno-sign-conversion -Wno-invalid-source-encoding
+ CFLAGS: -Wno-sign-conversion $(if $(subst MINGW32,,$(SYSTEM)),-Wno-invalid-source-encoding,)
CPPFLAGS: -Ithird_party/cares -Ithird_party/cares/cares $(if $(subst Linux,,$(SYSTEM)),,-Ithird_party/cares/config_linux)
$(if $(subst Darwin,,$(SYSTEM)),,-Ithird_party/cares/config_darwin) -fvisibility=hidden
- -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DHAVE_CONFIG_H
+ -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX $(if $(subst
+ MINGW32,,$(SYSTEM)),-DHAVE_CONFIG_H,)
benchmark:
CPPFLAGS: -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
boringssl:
@@ -4456,13 +4469,10 @@
- src/node/ext/call_credentials.cc
- src/node/ext/channel.cc
- src/node/ext/channel_credentials.cc
- - src/node/ext/completion_queue_threadpool.cc
- - src/node/ext/completion_queue_uv.cc
+ - src/node/ext/completion_queue.cc
- src/node/ext/node_grpc.cc
- src/node/ext/server.cc
- src/node/ext/server_credentials.cc
- - src/node/ext/server_generic.cc
- - src/node/ext/server_uv.cc
- src/node/ext/slice.cc
- src/node/ext/timeval.cc
openssl_fallback:
@@ -4473,7 +4483,6 @@
deps:
- grpc
- gpr
- - ares
- boringssl
headers:
- src/php/ext/grpc/byte_buffer.h
diff --git a/config.m4 b/config.m4
index 74b60c924..f80a205 100644
--- a/config.m4
+++ b/config.m4
@@ -8,8 +8,6 @@
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include)
- PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/cares)
- PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/cares/cares)
LIBS="-lpthread $LIBS"
@@ -21,10 +19,8 @@
case $host in
*darwin*)
- PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/cares/config_darwin)
;;
*)
- PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/cares/config_linux)
PHP_ADD_LIBRARY(rt,,GRPC_SHARED_LIBADD)
PHP_ADD_LIBRARY(rt)
;;
@@ -626,59 +622,10 @@
third_party/boringssl/ssl/tls13_server.c \
third_party/boringssl/ssl/tls_method.c \
third_party/boringssl/ssl/tls_record.c \
- third_party/cares/cares/ares__close_sockets.c \
- third_party/cares/cares/ares__get_hostent.c \
- third_party/cares/cares/ares__read_line.c \
- third_party/cares/cares/ares__timeval.c \
- third_party/cares/cares/ares_cancel.c \
- third_party/cares/cares/ares_create_query.c \
- third_party/cares/cares/ares_data.c \
- third_party/cares/cares/ares_destroy.c \
- third_party/cares/cares/ares_expand_name.c \
- third_party/cares/cares/ares_expand_string.c \
- third_party/cares/cares/ares_fds.c \
- third_party/cares/cares/ares_free_hostent.c \
- third_party/cares/cares/ares_free_string.c \
- third_party/cares/cares/ares_getenv.c \
- third_party/cares/cares/ares_gethostbyaddr.c \
- third_party/cares/cares/ares_gethostbyname.c \
- third_party/cares/cares/ares_getnameinfo.c \
- third_party/cares/cares/ares_getopt.c \
- third_party/cares/cares/ares_getsock.c \
- third_party/cares/cares/ares_init.c \
- third_party/cares/cares/ares_library_init.c \
- third_party/cares/cares/ares_llist.c \
- third_party/cares/cares/ares_mkquery.c \
- third_party/cares/cares/ares_nowarn.c \
- third_party/cares/cares/ares_options.c \
- third_party/cares/cares/ares_parse_a_reply.c \
- third_party/cares/cares/ares_parse_aaaa_reply.c \
- third_party/cares/cares/ares_parse_mx_reply.c \
- third_party/cares/cares/ares_parse_naptr_reply.c \
- third_party/cares/cares/ares_parse_ns_reply.c \
- third_party/cares/cares/ares_parse_ptr_reply.c \
- third_party/cares/cares/ares_parse_soa_reply.c \
- third_party/cares/cares/ares_parse_srv_reply.c \
- third_party/cares/cares/ares_parse_txt_reply.c \
- third_party/cares/cares/ares_platform.c \
- third_party/cares/cares/ares_process.c \
- third_party/cares/cares/ares_query.c \
- third_party/cares/cares/ares_search.c \
- third_party/cares/cares/ares_send.c \
- third_party/cares/cares/ares_strcasecmp.c \
- third_party/cares/cares/ares_strdup.c \
- third_party/cares/cares/ares_strerror.c \
- third_party/cares/cares/ares_timeout.c \
- third_party/cares/cares/ares_version.c \
- third_party/cares/cares/ares_writev.c \
- third_party/cares/cares/bitncmp.c \
- third_party/cares/cares/inet_net_pton.c \
- third_party/cares/cares/inet_ntop.c \
- third_party/cares/cares/windows_port.c \
, $ext_shared, , -Wall -Werror \
-Wno-parentheses-equality -Wno-unused-value -std=c11 \
-fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN \
- -D_HAS_EXCEPTIONS=0 -DNOMINMAX)
+ -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DGRPC_ARES=0)
PHP_ADD_BUILD_DIR($ext_builddir/src/php/ext/grpc)
@@ -771,6 +718,5 @@
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/x509)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/crypto/x509v3)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/boringssl/ssl)
- PHP_ADD_BUILD_DIR($ext_builddir/third_party/cares/cares)
PHP_ADD_BUILD_DIR($ext_builddir/third_party/nanopb)
fi
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index bd129f7..5d1ba61 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -37,7 +37,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-Core'
- version = '1.3.0-pre1'
+ version = '1.3.5'
s.version = version
s.summary = 'Core cross-platform gRPC library, written in C'
s.homepage = 'http://www.grpc.io'
diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec
index de30032..e60ea7c 100644
--- a/gRPC-ProtoRPC.podspec
+++ b/gRPC-ProtoRPC.podspec
@@ -36,7 +36,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-ProtoRPC'
- version = '1.3.0-pre1'
+ version = '1.3.5'
s.version = version
s.summary = 'RPC library for Protocol Buffers, based on gRPC'
s.homepage = 'http://www.grpc.io'
diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec
index 642b4ca..d82130a 100644
--- a/gRPC-RxLibrary.podspec
+++ b/gRPC-RxLibrary.podspec
@@ -36,7 +36,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC-RxLibrary'
- version = '1.3.0-pre1'
+ version = '1.3.5'
s.version = version
s.summary = 'Reactive Extensions library for iOS/OSX.'
s.homepage = 'http://www.grpc.io'
diff --git a/gRPC.podspec b/gRPC.podspec
index ac3057e..5aa8a86 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -35,7 +35,7 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
- version = '1.3.0-pre1'
+ version = '1.3.5'
s.version = version
s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'http://www.grpc.io'
diff --git a/grpc.def b/grpc.def
index 1589316..534a23d 100644
--- a/grpc.def
+++ b/grpc.def
@@ -65,6 +65,7 @@
grpc_alarm_cancel
grpc_alarm_destroy
grpc_channel_check_connectivity_state
+ grpc_channel_num_external_connectivity_watchers
grpc_channel_watch_connectivity_state
grpc_channel_create_call
grpc_channel_ping
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index e088435..bdb8617 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -225,6 +225,12 @@
GRPCAPI grpc_connectivity_state grpc_channel_check_connectivity_state(
grpc_channel *channel, int try_to_connect);
+/** Number of active "external connectivity state watchers" attached to a
+ * channel.
+ * Useful for testing. **/
+GRPCAPI int grpc_channel_num_external_connectivity_watchers(
+ grpc_channel *channel);
+
/** Watch for a change in connectivity state.
Once the channel connectivity state is different from last_observed_state,
tag will be enqueued on cq with success=1.
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index 813e08b..a149279 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -189,7 +189,7 @@
#ifdef __GLIBC__
#define GPR_POSIX_CRASH_HANDLER 1
#else /* musl libc */
-#define GRPC_MSG_IOVLEN_TYPE int
+#define GPR_MUSL_LIBC_COMPAT 1
#endif
#elif defined(__APPLE__)
#include <Availability.h>
diff --git a/package.json b/package.json
index d4f7b56..c83f51c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc",
- "version": "1.3.0-pre1",
+ "version": "1.3.5",
"author": "Google Inc.",
"description": "gRPC Library for Node",
"homepage": "http://www.grpc.io/",
@@ -34,8 +34,7 @@
"lodash": "^4.15.0",
"nan": "^2.0.0",
"node-pre-gyp": "^0.6.0",
- "protobufjs": "^6.7.0",
- "cares": "^1.1.5"
+ "protobufjs": "^5.0.0"
},
"devDependencies": {
"async": "^2.0.1",
diff --git a/package.xml b/package.xml
index 54a7bae..1c91f1c 100644
--- a/package.xml
+++ b/package.xml
@@ -10,11 +10,11 @@
<email>grpc-packages@google.com</email>
<active>yes</active>
</lead>
- <date>2017-03-01</date>
+ <date>2017-05-05</date>
<time>16:06:07</time>
<version>
- <release>1.3.0RC1</release>
- <api>1.3.0RC1</api>
+ <release>1.3.5</release>
+ <api>1.3.5</api>
</version>
<stability>
<release>beta</release>
@@ -22,8 +22,7 @@
</stability>
<license>BSD</license>
<notes>
-- Added arg info macros #9751
-- Updated codegen to be consistent with protobuf #9492
+- Fixed some memory leaks #9559, #10996
</notes>
<contents>
<dir baseinstalldir="/" name="/">
@@ -1027,79 +1026,7 @@
<file baseinstalldir="/" name="third_party/boringssl/ssl/tls13_server.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/tls_method.c" role="src" />
<file baseinstalldir="/" name="third_party/boringssl/ssl/tls_record.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_data.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_dns.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_getenv.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_getopt.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_inet_net_pton.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_iphlpapi.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_ipv6.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_library_init.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_llist.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_nowarn.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_platform.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_private.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_rules.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_setup.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_strcasecmp.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_strdup.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_version.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/bitncmp.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/config-win32.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/setup_once.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/ares_build.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/config_linux/ares_config.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/config_darwin/ares_config.h" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares__close_sockets.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares__get_hostent.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares__read_line.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares__timeval.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_cancel.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_create_query.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_data.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_destroy.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_expand_name.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_expand_string.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_fds.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_free_hostent.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_free_string.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_getenv.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_gethostbyaddr.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_gethostbyname.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_getnameinfo.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_getopt.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_getsock.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_init.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_library_init.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_llist.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_mkquery.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_nowarn.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_options.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_parse_a_reply.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_parse_aaaa_reply.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_parse_mx_reply.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_parse_naptr_reply.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_parse_ns_reply.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_parse_ptr_reply.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_parse_soa_reply.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_parse_srv_reply.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_parse_txt_reply.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_platform.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_process.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_query.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_search.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_send.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_strcasecmp.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_strdup.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_strerror.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_timeout.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_version.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/ares_writev.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/bitncmp.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/inet_net_pton.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/inet_ntop.c" role="src" />
- <file baseinstalldir="/" name="third_party/cares/cares/windows_port.c" role="src" />
+ <file name="LICENSE" role="doc" />
</dir>
</contents>
<dependencies>
@@ -1415,5 +1342,21 @@
- Updated codegen to be consistent with protobuf #9492
</notes>
</release>
+ <release>
+ <version>
+ <release>1.2.0</release>
+ <api>1.2.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <date>2017-03-20</date>
+ <license>BSD</license>
+ <notes>
+- Added arg info macros #9751
+- Updated codegen to be consistent with protobuf #9492
+ </notes>
+ </release>
</changelog>
</package>
diff --git a/setup.py b/setup.py
index e050646..b1ac4f3 100644
--- a/setup.py
+++ b/setup.py
@@ -141,6 +141,8 @@
CYTHON_HELPER_C_FILES = ()
CORE_C_FILES = tuple(grpc_core_dependencies.CORE_SOURCE_FILES)
+if "win32" in sys.platform and "64bit" in platform.architecture()[0]:
+ CORE_C_FILES = filter(lambda x: 'third_party/cares' not in x, CORE_C_FILES)
EXTENSION_INCLUDE_DIRECTORIES = (
(PYTHON_STEM,) + CORE_INCLUDE + BORINGSSL_INCLUDE + ZLIB_INCLUDE +
@@ -160,7 +162,9 @@
if "win32" in sys.platform:
DEFINE_MACROS += (('WIN32_LEAN_AND_MEAN', 1), ('CARES_STATICLIB', 1),)
if '64bit' in platform.architecture()[0]:
- DEFINE_MACROS += (('MS_WIN64', 1),)
+ # TODO(zyc): Re-enble c-ares on x64 windows after fixing the
+ # ares_library_init compilation issue
+ DEFINE_MACROS += (('MS_WIN64', 1), ('GRPC_ARES', 0),)
elif sys.version_info >= (3, 5):
# For some reason, this is needed to get access to inet_pton/inet_ntop
# on msvc, but only for 32 bits
diff --git a/src/core/ext/filters/client_channel/channel_connectivity.c b/src/core/ext/filters/client_channel/channel_connectivity.c
index 62f58fb..5f3ffd4 100644
--- a/src/core/ext/filters/client_channel/channel_connectivity.c
+++ b/src/core/ext/filters/client_channel/channel_connectivity.c
@@ -67,9 +67,8 @@
typedef enum {
WAITING,
- CALLING_BACK,
+ READY_TO_CALL_BACK,
CALLING_BACK_AND_FINISHED,
- CALLED_BACK
} callback_phase;
typedef struct {
@@ -77,11 +76,13 @@
callback_phase phase;
grpc_closure on_complete;
grpc_closure on_timeout;
+ grpc_closure watcher_timer_init;
grpc_timer alarm;
grpc_connectivity_state state;
grpc_completion_queue *cq;
grpc_cq_completion completion_storage;
grpc_channel *channel;
+ grpc_error *error;
void *tag;
} state_watcher;
@@ -105,11 +106,8 @@
gpr_mu_lock(&w->mu);
switch (w->phase) {
case WAITING:
- case CALLED_BACK:
+ case READY_TO_CALL_BACK:
GPR_UNREACHABLE_CODE(return );
- case CALLING_BACK:
- w->phase = CALLED_BACK;
- break;
case CALLING_BACK_AND_FINISHED:
delete = 1;
break;
@@ -123,10 +121,14 @@
static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
bool due_to_completion, grpc_error *error) {
- int delete = 0;
-
if (due_to_completion) {
grpc_timer_cancel(exec_ctx, &w->alarm);
+ } else {
+ grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(
+ grpc_channel_get_channel_stack(w->channel));
+ grpc_client_channel_watch_connectivity_state(exec_ctx, client_channel_elem,
+ grpc_cq_pollset(w->cq), NULL,
+ &w->on_complete, NULL);
}
gpr_mu_lock(&w->mu);
@@ -147,25 +149,27 @@
}
switch (w->phase) {
case WAITING:
- w->phase = CALLING_BACK;
- grpc_cq_end_op(exec_ctx, w->cq, w->tag, GRPC_ERROR_REF(error),
- finished_completion, w, &w->completion_storage);
+ GRPC_ERROR_REF(error);
+ w->error = error;
+ w->phase = READY_TO_CALL_BACK;
break;
- case CALLING_BACK:
+ case READY_TO_CALL_BACK:
+ if (error != GRPC_ERROR_NONE) {
+ GPR_ASSERT(!due_to_completion);
+ GRPC_ERROR_UNREF(w->error);
+ GRPC_ERROR_REF(error);
+ w->error = error;
+ }
w->phase = CALLING_BACK_AND_FINISHED;
+ grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->error, finished_completion, w,
+ &w->completion_storage);
break;
case CALLING_BACK_AND_FINISHED:
GPR_UNREACHABLE_CODE(return );
- case CALLED_BACK:
- delete = 1;
break;
}
gpr_mu_unlock(&w->mu);
- if (delete) {
- delete_state_watcher(exec_ctx, w);
- }
-
GRPC_ERROR_UNREF(error);
}
@@ -179,6 +183,28 @@
partly_done(exec_ctx, pw, false, GRPC_ERROR_REF(error));
}
+int grpc_channel_num_external_connectivity_watchers(grpc_channel *channel) {
+ grpc_channel_element *client_channel_elem =
+ grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
+ return grpc_client_channel_num_external_connectivity_watchers(
+ client_channel_elem);
+}
+
+typedef struct watcher_timer_init_arg {
+ state_watcher *w;
+ gpr_timespec deadline;
+} watcher_timer_init_arg;
+
+static void watcher_timer_init(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error_ignored) {
+ watcher_timer_init_arg *wa = (watcher_timer_init_arg *)arg;
+
+ grpc_timer_init(exec_ctx, &wa->w->alarm,
+ gpr_convert_clock_type(wa->deadline, GPR_CLOCK_MONOTONIC),
+ &wa->w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
+ gpr_free(wa);
+}
+
void grpc_channel_watch_connectivity_state(
grpc_channel *channel, grpc_connectivity_state last_observed_state,
gpr_timespec deadline, grpc_completion_queue *cq, void *tag) {
@@ -208,16 +234,19 @@
w->cq = cq;
w->tag = tag;
w->channel = channel;
+ w->error = NULL;
- grpc_timer_init(&exec_ctx, &w->alarm,
- gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
- &w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
+ watcher_timer_init_arg *wa = gpr_malloc(sizeof(watcher_timer_init_arg));
+ wa->w = w;
+ wa->deadline = deadline;
+ grpc_closure_init(&w->watcher_timer_init, watcher_timer_init, wa,
+ grpc_schedule_on_exec_ctx);
if (client_channel_elem->filter == &grpc_client_channel_filter) {
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
- grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem,
- grpc_cq_pollset(cq), &w->state,
- &w->on_complete);
+ grpc_client_channel_watch_connectivity_state(
+ &exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state,
+ &w->on_complete, &w->watcher_timer_init);
} else {
abort();
}
diff --git a/src/core/ext/filters/client_channel/client_channel.c b/src/core/ext/filters/client_channel/client_channel.c
index 83e3b8f..4bd153e 100644
--- a/src/core/ext/filters/client_channel/client_channel.c
+++ b/src/core/ext/filters/client_channel/client_channel.c
@@ -174,6 +174,8 @@
return value;
}
+struct external_connectivity_watcher;
+
/*************************************************************************
* CHANNEL-WIDE FUNCTIONS
*/
@@ -209,6 +211,11 @@
/** interested parties (owned) */
grpc_pollset_set *interested_parties;
+ /* external_connectivity_watcher_list head is guarded by its own mutex, since
+ * counts need to be grabbed immediately without polling on a cq */
+ gpr_mu external_connectivity_watcher_list_mu;
+ struct external_connectivity_watcher *external_connectivity_watcher_list_head;
+
/* the following properties are guarded by a mutex since API's require them
to be instantaneously available */
gpr_mu info_mu;
@@ -632,6 +639,12 @@
// Initialize data members.
chand->combiner = grpc_combiner_create(NULL);
gpr_mu_init(&chand->info_mu);
+ gpr_mu_init(&chand->external_connectivity_watcher_list_mu);
+
+ gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
+ chand->external_connectivity_watcher_list_head = NULL;
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
+
chand->owning_stack = args->channel_stack;
grpc_closure_init(&chand->on_resolver_result_changed,
on_resolver_result_changed_locked, chand,
@@ -718,6 +731,7 @@
grpc_pollset_set_destroy(exec_ctx, chand->interested_parties);
GRPC_COMBINER_UNREF(exec_ctx, chand->combiner, "client_channel");
gpr_mu_destroy(&chand->info_mu);
+ gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu);
}
/*************************************************************************
@@ -1361,14 +1375,79 @@
return out;
}
-typedef struct {
+typedef struct external_connectivity_watcher {
channel_data *chand;
grpc_pollset *pollset;
grpc_closure *on_complete;
+ grpc_closure *watcher_timer_init;
grpc_connectivity_state *state;
grpc_closure my_closure;
+ struct external_connectivity_watcher *next;
} external_connectivity_watcher;
+static external_connectivity_watcher *lookup_external_connectivity_watcher(
+ channel_data *chand, grpc_closure *on_complete) {
+ gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
+ external_connectivity_watcher *w =
+ chand->external_connectivity_watcher_list_head;
+ while (w != NULL && w->on_complete != on_complete) {
+ w = w->next;
+ }
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
+ return w;
+}
+
+static void external_connectivity_watcher_list_append(
+ channel_data *chand, external_connectivity_watcher *w) {
+ GPR_ASSERT(!lookup_external_connectivity_watcher(chand, w->on_complete));
+
+ gpr_mu_lock(&w->chand->external_connectivity_watcher_list_mu);
+ GPR_ASSERT(!w->next);
+ w->next = chand->external_connectivity_watcher_list_head;
+ chand->external_connectivity_watcher_list_head = w;
+ gpr_mu_unlock(&w->chand->external_connectivity_watcher_list_mu);
+}
+
+static void external_connectivity_watcher_list_remove(
+ channel_data *chand, external_connectivity_watcher *too_remove) {
+ GPR_ASSERT(
+ lookup_external_connectivity_watcher(chand, too_remove->on_complete));
+ gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
+ if (too_remove == chand->external_connectivity_watcher_list_head) {
+ chand->external_connectivity_watcher_list_head = too_remove->next;
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
+ return;
+ }
+ external_connectivity_watcher *w =
+ chand->external_connectivity_watcher_list_head;
+ while (w != NULL) {
+ if (w->next == too_remove) {
+ w->next = w->next->next;
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
+ return;
+ }
+ w = w->next;
+ }
+ GPR_UNREACHABLE_CODE(return );
+}
+
+int grpc_client_channel_num_external_connectivity_watchers(
+ grpc_channel_element *elem) {
+ channel_data *chand = elem->channel_data;
+ int count = 0;
+
+ gpr_mu_lock(&chand->external_connectivity_watcher_list_mu);
+ external_connectivity_watcher *w =
+ chand->external_connectivity_watcher_list_head;
+ while (w != NULL) {
+ count++;
+ w = w->next;
+ }
+ gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu);
+
+ return count;
+}
+
static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
external_connectivity_watcher *w = arg;
@@ -1377,6 +1456,7 @@
w->pollset);
GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
"external_connectivity_watcher");
+ external_connectivity_watcher_list_remove(w->chand, w);
gpr_free(w);
grpc_closure_run(exec_ctx, follow_up, GRPC_ERROR_REF(error));
}
@@ -1384,21 +1464,42 @@
static void watch_connectivity_state_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error_ignored) {
external_connectivity_watcher *w = arg;
- grpc_closure_init(&w->my_closure, on_external_watch_complete, w,
- grpc_schedule_on_exec_ctx);
- grpc_connectivity_state_notify_on_state_change(
- exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure);
+ external_connectivity_watcher *found = NULL;
+ if (w->state != NULL) {
+ external_connectivity_watcher_list_append(w->chand, w);
+ grpc_closure_run(exec_ctx, w->watcher_timer_init, GRPC_ERROR_NONE);
+ grpc_closure_init(&w->my_closure, on_external_watch_complete, w,
+ grpc_schedule_on_exec_ctx);
+ grpc_connectivity_state_notify_on_state_change(
+ exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure);
+ } else {
+ GPR_ASSERT(w->watcher_timer_init == NULL);
+ found = lookup_external_connectivity_watcher(w->chand, w->on_complete);
+ if (found) {
+ GPR_ASSERT(found->on_complete == w->on_complete);
+ grpc_connectivity_state_notify_on_state_change(
+ exec_ctx, &found->chand->state_tracker, NULL, &found->my_closure);
+ }
+ grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties,
+ w->pollset);
+ GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
+ "external_connectivity_watcher");
+ gpr_free(w);
+ }
}
void grpc_client_channel_watch_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
- grpc_connectivity_state *state, grpc_closure *on_complete) {
+ grpc_connectivity_state *state, grpc_closure *on_complete,
+ grpc_closure *watcher_timer_init) {
channel_data *chand = elem->channel_data;
- external_connectivity_watcher *w = gpr_malloc(sizeof(*w));
+ external_connectivity_watcher *w = gpr_zalloc(sizeof(*w));
w->chand = chand;
w->pollset = pollset;
w->on_complete = on_complete;
w->state = state;
+ w->watcher_timer_init = watcher_timer_init;
+
grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset);
GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
"external_connectivity_watcher");
diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h
index 8d2490e..356a7ab 100644
--- a/src/core/ext/filters/client_channel/client_channel.h
+++ b/src/core/ext/filters/client_channel/client_channel.h
@@ -53,9 +53,13 @@
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
+int grpc_client_channel_num_external_connectivity_watchers(
+ grpc_channel_element *elem);
+
void grpc_client_channel_watch_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
- grpc_connectivity_state *state, grpc_closure *on_complete);
+ grpc_connectivity_state *state, grpc_closure *on_complete,
+ grpc_closure *watcher_timer_init);
/* Debug helper: pull the subchannel call from a call stack element */
grpc_subchannel_call *grpc_client_channel_get_subchannel_call(
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index 269dc35..2a553f4 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -88,6 +88,7 @@
#ifndef __GLIBC__
#define GRPC_LINUX_EPOLL 1
#define GRPC_LINUX_EVENTFD 1
+#define GRPC_MSG_IOVLEN_TYPE int
#endif
#ifndef GRPC_LINUX_EVENTFD
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
diff --git a/src/core/lib/iomgr/tcp_server_uv.c b/src/core/lib/iomgr/tcp_server_uv.c
index e924694..d446e53 100644
--- a/src/core/lib/iomgr/tcp_server_uv.c
+++ b/src/core/lib/iomgr/tcp_server_uv.c
@@ -56,6 +56,8 @@
int port;
/* linked list */
struct grpc_tcp_listener *next;
+
+ bool closed;
};
struct grpc_tcp_server {
@@ -77,6 +79,8 @@
/* shutdown callback */
grpc_closure *shutdown_complete;
+ bool shutdown;
+
grpc_resource_quota *resource_quota;
};
@@ -109,6 +113,7 @@
s->shutdown_starting.head = NULL;
s->shutdown_starting.tail = NULL;
s->shutdown_complete = shutdown_complete;
+ s->shutdown = false;
*server = s;
return GRPC_ERROR_NONE;
}
@@ -125,6 +130,7 @@
}
static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
+ GPR_ASSERT(s->shutdown);
if (s->shutdown_complete != NULL) {
grpc_closure_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE);
}
@@ -144,21 +150,31 @@
grpc_tcp_listener *sp = (grpc_tcp_listener *)handle->data;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
sp->server->open_ports--;
- if (sp->server->open_ports == 0) {
+ if (sp->server->open_ports == 0 && sp->server->shutdown) {
finish_shutdown(&exec_ctx, sp->server);
}
grpc_exec_ctx_finish(&exec_ctx);
}
+static void close_listener(grpc_tcp_listener *sp) {
+ if (!sp->closed) {
+ sp->closed = true;
+ uv_close((uv_handle_t *)sp->handle, handle_close_callback);
+ }
+}
+
static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
int immediately_done = 0;
grpc_tcp_listener *sp;
+ GPR_ASSERT(!s->shutdown);
+ s->shutdown = true;
+
if (s->open_ports == 0) {
immediately_done = 1;
}
for (sp = s->head; sp; sp = sp->next) {
- uv_close((uv_handle_t *)sp->handle, handle_close_callback);
+ close_listener(sp);
}
if (immediately_done) {
@@ -196,9 +212,14 @@
int err;
if (status < 0) {
- gpr_log(GPR_INFO, "Skipping on_accept due to error: %s",
- uv_strerror(status));
- return;
+ switch (status) {
+ case UV_EINTR:
+ case UV_EAGAIN:
+ return;
+ default:
+ close_listener(sp);
+ return;
+ }
}
client = gpr_malloc(sizeof(uv_tcp_t));
@@ -287,6 +308,7 @@
sp->handle = handle;
sp->port = port;
sp->port_index = port_index;
+ sp->closed = false;
handle->data = sp;
s->open_ports++;
GPR_ASSERT(sp->handle);
diff --git a/src/core/lib/iomgr/tcp_uv.c b/src/core/lib/iomgr/tcp_uv.c
index 8e8db9f..b9ca1a3 100644
--- a/src/core/lib/iomgr/tcp_uv.c
+++ b/src/core/lib/iomgr/tcp_uv.c
@@ -88,12 +88,12 @@
#ifdef GRPC_TCP_REFCOUNT_DEBUG
#define TCP_UNREF(exec_ctx, tcp, reason) \
tcp_unref((exec_ctx), (tcp), (reason), __FILE__, __LINE__)
-#define TCP_REF(tcp, reason) \
- tcp_ref((exec_ctx), (tcp), (reason), __FILE__, __LINE__)
+#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
const char *reason, const char *file, int line) {
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
- reason, tcp->refcount.count, tcp->refcount.count - 1);
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+ "TCP unref %p : %s %" PRIiPTR " -> %" PRIiPTR, tcp, reason,
+ tcp->refcount.count, tcp->refcount.count - 1);
if (gpr_unref(&tcp->refcount)) {
tcp_free(exec_ctx, tcp);
}
@@ -101,8 +101,9 @@
static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
int line) {
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp,
- reason, tcp->refcount.count, tcp->refcount.count + 1);
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+ "TCP ref %p : %s %" PRIiPTR " -> %" PRIiPTR, tcp, reason,
+ tcp->refcount.count, tcp->refcount.count + 1);
gpr_ref(&tcp->refcount);
}
#else
@@ -311,6 +312,7 @@
tcp->shutting_down = true;
uv_shutdown_t *req = &tcp->shutdown_req;
uv_shutdown(req, (uv_stream_t *)tcp->handle, shutdown_callback);
+ grpc_resource_user_shutdown(exec_ctx, tcp->resource_user);
}
GRPC_ERROR_UNREF(why);
}
diff --git a/src/core/lib/support/cpu_linux.c b/src/core/lib/support/cpu_linux.c
index 1e50f59..b826dde 100644
--- a/src/core/lib/support/cpu_linux.c
+++ b/src/core/lib/support/cpu_linux.c
@@ -67,16 +67,16 @@
}
unsigned gpr_cpu_current_cpu(void) {
-#ifdef __GLIBC__
+#ifdef GPR_MUSL_LIBC_COMPAT
+ // sched_getcpu() is undefined on musl
+ return 0;
+#else
int cpu = sched_getcpu();
if (cpu < 0) {
gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno));
return 0;
}
return (unsigned)cpu;
-#else
- // sched_getcpu() is undefined on musl
- return 0;
#endif
}
diff --git a/src/core/lib/support/wrap_memcpy.c b/src/core/lib/support/wrap_memcpy.c
index 050cc6d..deb8d6b 100644
--- a/src/core/lib/support/wrap_memcpy.c
+++ b/src/core/lib/support/wrap_memcpy.c
@@ -31,6 +31,8 @@
*
*/
+#include <grpc/support/port_platform.h>
+
#include <string.h>
/* Provide a wrapped memcpy for targets that need to be backwards
@@ -40,7 +42,7 @@
*/
#ifdef __linux__
-#if defined(__x86_64__) && defined(__GNU_LIBRARY__)
+#if defined(__x86_64__) && !defined(GPR_MUSL_LIBC_COMPAT)
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
void *__wrap_memcpy(void *destination, const void *source, size_t num) {
return memcpy(destination, source, num);
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index 959b45d..b800e03 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -36,6 +36,6 @@
#include <grpc/grpc.h>
-const char *grpc_version_string(void) { return "3.0.0-pre1"; }
+const char *grpc_version_string(void) { return "3.0.0"; }
const char *grpc_g_stands_for(void) { return "gentle"; }
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
index 16a295d..0a1b725 100644
--- a/src/cpp/common/version_cc.cc
+++ b/src/cpp/common/version_cc.cc
@@ -37,5 +37,5 @@
#include <grpc++/grpc++.h>
namespace grpc {
-grpc::string Version() { return "1.3.0-pre1"; }
+grpc::string Version() { return "1.3.5"; }
}
diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
index 4d90470..c57c260 100644
--- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
+++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
@@ -141,7 +141,8 @@
{
if (server == null)
{
- server = new Server
+ // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
+ server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { serviceDefinition },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index 4f29c35..51ae11f 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -59,6 +59,8 @@
readonly ChannelSafeHandle handle;
readonly Dictionary<string, ChannelOption> options;
+ readonly Task connectivityWatcherTask;
+
bool shutdownRequested;
/// <summary>
@@ -99,6 +101,9 @@
this.handle = ChannelSafeHandle.CreateInsecure(target, nativeChannelArgs);
}
}
+ // TODO(jtattermusch): Workaround for https://github.com/GoogleCloudPlatform/google-cloud-dotnet/issues/822.
+ // Remove once retries are supported in C core
+ this.connectivityWatcherTask = RunConnectivityWatcherAsync();
GrpcEnvironment.RegisterChannel(this);
}
@@ -244,7 +249,7 @@
handle.Dispose();
- await GrpcEnvironment.ReleaseAsync().ConfigureAwait(false);
+ await Task.WhenAll(GrpcEnvironment.ReleaseAsync(), connectivityWatcherTask).ConfigureAwait(false);
}
internal ChannelSafeHandle Handle
@@ -299,6 +304,40 @@
}
}
+ /// <summary>
+ /// Constantly Watches channel connectivity status to work around https://github.com/GoogleCloudPlatform/google-cloud-dotnet/issues/822
+ /// </summary>
+ private async Task RunConnectivityWatcherAsync()
+ {
+ try
+ {
+ var lastState = State;
+ while (lastState != ChannelState.Shutdown)
+ {
+ lock (myLock)
+ {
+ if (shutdownRequested)
+ {
+ break;
+ }
+ }
+
+ try
+ {
+ await WaitForStateChangedAsync(lastState, DateTime.UtcNow.AddSeconds(1)).ConfigureAwait(false);
+ }
+ catch (TaskCanceledException)
+ {
+ // ignore timeout
+ }
+ lastState = State;
+ }
+ }
+ catch (ObjectDisposedException) {
+ // during shutdown, channel is going to be disposed.
+ }
+ }
+
private static void EnsureUserAgentChannelOption(Dictionary<string, ChannelOption> options)
{
var key = ChannelOptions.PrimaryUserAgentString;
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index 46a2c66..5de9b1e 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -172,6 +172,9 @@
/// <summary>Secondary user agent: goes at the end of the user-agent metadata</summary>
public const string SecondaryUserAgentString = "grpc.secondary_user_agent";
+ /// <summary>If non-zero, allow the use of SO_REUSEPORT for server if it's available (default 1)</summary>
+ public const string SoReuseport = "grpc.so_reuseport";
+
/// <summary>
/// Creates native object for a collection of channel options.
/// </summary>
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index 5409c98..63536ec 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
<!-- This file is generated -->
<Project>
<PropertyGroup>
- <GrpcCsharpVersion>1.3.0-pre1</GrpcCsharpVersion>
+ <GrpcCsharpVersion>1.3.5</GrpcCsharpVersion>
<GoogleProtobufVersion>3.2.0</GoogleProtobufVersion>
</PropertyGroup>
</Project>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 03d4a96..fed3829 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -48,11 +48,11 @@
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
- public const string CurrentAssemblyFileVersion = "1.3.0.0";
+ public const string CurrentAssemblyFileVersion = "1.3.5.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "1.3.0-pre1";
+ public const string CurrentVersion = "1.3.5";
}
}
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 50dacc2..02bcd18 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -55,7 +55,8 @@
[TestFixtureSetUp]
public void Init()
{
- server = new Server
+ // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
+ server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { Math.BindService(new MathServiceImpl()) },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
index 25a58fb..0ebc3c3 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -57,7 +57,8 @@
{
serviceImpl = new HealthServiceImpl();
- server = new Server
+ // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
+ server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { Grpc.Health.V1.Health.BindService(serviceImpl) },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
diff --git a/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs b/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
index 4216dc1..780a9b7 100644
--- a/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
@@ -54,7 +54,8 @@
[SetUp]
public void Init()
{
- server = new Server
+ // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
+ server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { TestService.BindService(new UnimplementedTestServiceImpl()) },
Ports = { { Host, ServerPort.PickUnused, SslServerCredentials.Insecure } }
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index 4960a53..04f833f 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -56,7 +56,8 @@
[TestFixtureSetUp]
public void Init()
{
- server = new Server
+ // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
+ server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { TestService.BindService(new TestServiceImpl()) },
Ports = { { Host, ServerPort.PickUnused, TestCredentials.CreateSslServerCredentials() } }
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
index d55e658..ef63f53 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -56,7 +56,8 @@
[SetUp]
public void Init()
{
- server = new Server
+ // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
+ server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { TestService.BindService(new FakeTestService()) },
Ports = { { Host, ServerPort.PickUnused, TestCredentials.CreateSslServerCredentials() } }
diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
index 377dad6..48ecc23 100644
--- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
@@ -67,7 +67,8 @@
var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, true);
var clientCredentials = new SslCredentials(rootCert, keyCertPair);
- server = new Server
+ // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
+ server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { TestService.BindService(new SslCredentialsTestServiceImpl()) },
Ports = { { Host, ServerPort.PickUnused, serverCredentials } }
diff --git a/src/csharp/Grpc.Reflection.Tests/ReflectionClientServerTest.cs b/src/csharp/Grpc.Reflection.Tests/ReflectionClientServerTest.cs
index 1d0845e..22edbed 100644
--- a/src/csharp/Grpc.Reflection.Tests/ReflectionClientServerTest.cs
+++ b/src/csharp/Grpc.Reflection.Tests/ReflectionClientServerTest.cs
@@ -58,7 +58,8 @@
{
serviceImpl = new ReflectionServiceImpl(ServerReflection.Descriptor);
- server = new Server
+ // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
+ server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { ServerReflection.BindService(serviceImpl) },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 2f8d5b8..3aec7aa 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -28,7 +28,7 @@
@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@rem Current package versions
-set VERSION=1.3.0-pre1
+set VERSION=1.3.5
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
@@ -60,11 +60,11 @@
@rem To be able to build, we also need to put grpc_csharp_ext to its normal location
xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release\
-%DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error
-%DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error
-%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error
-%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
-%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Auth --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ..\..\..\artifacts || goto :error
%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index 3096b3e..da585cb 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -64,13 +64,13 @@
mkdir -p ../../libs/opt
cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt
-dotnet pack --configuration Release Grpc.Core --output ../../../artifacts
-dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts
-dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts
-dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
-dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
+dotnet pack --configuration Release --include-symbols --include-source Grpc.Core --output ../../../artifacts
+dotnet pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ../../../artifacts
+dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth --output ../../../artifacts
+dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts
+dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts
-nuget pack Grpc.nuspec -Version "1.3.0-pre1" -OutputDirectory ../../artifacts
-nuget pack Grpc.Tools.nuspec -Version "1.3.0-pre1" -OutputDirectory ../../artifacts
+nuget pack Grpc.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts
+nuget pack Grpc.Tools.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts
(cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg)
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index bd60775..2cc9f63 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -46,7 +46,6 @@
#include "call.h"
#include "channel.h"
#include "completion_queue.h"
-#include "completion_queue_async_worker.h"
#include "call_credentials.h"
#include "slice.h"
#include "timeval.h"
@@ -722,6 +721,14 @@
}
Local<Function> callback_func = info[1].As<Function>();
Call *call = ObjectWrap::Unwrap<Call>(info.This());
+ if (call->wrapped_call == NULL) {
+ /* This implies that the call has completed and has been destroyed. To emulate
+ * previous behavior, we should call the callback immediately with an error,
+ * as though the batch had failed in core */
+ Local<Value> argv[] = {Nan::Error("The async function failed because the call has completed")};
+ Nan::Call(callback_func, Nan::New<Object>(), 1, argv);
+ return;
+ }
Local<Object> obj = Nan::To<Object>(info[0]).ToLocalChecked();
Local<Array> keys = Nan::GetOwnPropertyNames(obj).ToLocalChecked();
size_t nops = keys->Length();
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index 1263cc0..2c533f0 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -42,7 +42,6 @@
#include "call.h"
#include "channel.h"
#include "completion_queue.h"
-#include "completion_queue_async_worker.h"
#include "channel_credentials.h"
#include "timeval.h"
diff --git a/src/node/ext/completion_queue_uv.cc b/src/node/ext/completion_queue.cc
similarity index 98%
rename from src/node/ext/completion_queue_uv.cc
rename to src/node/ext/completion_queue.cc
index 0f6f7da..a743784 100644
--- a/src/node/ext/completion_queue_uv.cc
+++ b/src/node/ext/completion_queue.cc
@@ -31,8 +31,6 @@
*
*/
-#ifdef GRPC_UV
-
#include <uv.h>
#include <node.h>
#include <v8.h>
@@ -97,5 +95,3 @@
} // namespace node
} // namespace grpc
-
-#endif /* GRPC_UV */
diff --git a/src/node/ext/completion_queue_async_worker.h b/src/node/ext/completion_queue_async_worker.h
deleted file mode 100644
index 6e54116..0000000
--- a/src/node/ext/completion_queue_async_worker.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-#ifndef NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_
-#define NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_
-#include <nan.h>
-
-#include "grpc/grpc.h"
-
-namespace grpc {
-namespace node {
-
-/* A worker that asynchronously calls completion_queue_next, and queues onto the
- node event loop a call to the function stored in the event's tag. */
-class CompletionQueueAsyncWorker : public Nan::AsyncWorker {
- public:
- CompletionQueueAsyncWorker();
-
- ~CompletionQueueAsyncWorker();
- /* Calls completion_queue_next with the provided deadline, and stores the
- event if there was one or sets an error message if there was not */
- void Execute();
-
- /* Returns the completion queue attached to this class */
- static grpc_completion_queue *GetQueue();
-
- /* Convenience function to create a worker with the given arguments and queue
- it to run asynchronously */
- static void Next();
-
- /* Initialize the CompletionQueueAsyncWorker class */
- static void Init(v8::Local<v8::Object> exports);
-
- protected:
- /* Called when Execute has succeeded (completed without setting an error
- message). Calls the saved callback with the event that came from
- completion_queue_next */
- void HandleOKCallback();
-
- void HandleErrorCallback();
-
- private:
- grpc_event result;
-
- static grpc_completion_queue *queue;
-
- // Number of grpc_completion_queue_next calls in the thread pool
- static int current_threads;
- // Number of grpc_completion_queue_next calls waiting to enter the thread pool
- static int waiting_next_calls;
-};
-
-} // namespace node
-} // namespace grpc
-
-#endif // NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_
diff --git a/src/node/ext/completion_queue_threadpool.cc b/src/node/ext/completion_queue_threadpool.cc
deleted file mode 100644
index 7b1bdda..0000000
--- a/src/node/ext/completion_queue_threadpool.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-/* I don't like using #ifndef, but I don't see a better way to do this */
-#ifndef GRPC_UV
-
-#include <node.h>
-#include <nan.h>
-
-#include "grpc/grpc.h"
-#include "grpc/support/log.h"
-#include "grpc/support/time.h"
-#include "completion_queue.h"
-#include "call.h"
-
-namespace grpc {
-namespace node {
-
-namespace {
-
-/* A worker that asynchronously calls completion_queue_next, and queues onto the
- node event loop a call to the function stored in the event's tag. */
-class CompletionQueueAsyncWorker : public Nan::AsyncWorker {
- public:
- CompletionQueueAsyncWorker();
-
- ~CompletionQueueAsyncWorker();
- /* Calls completion_queue_next with the provided deadline, and stores the
- event if there was one or sets an error message if there was not */
- void Execute();
-
- /* Returns the completion queue attached to this class */
- static grpc_completion_queue *GetQueue();
-
- /* Convenience function to create a worker with the given arguments and queue
- it to run asynchronously */
- static void Next();
-
- /* Initialize the CompletionQueueAsyncWorker class */
- static void Init(v8::Local<v8::Object> exports);
-
- protected:
- /* Called when Execute has succeeded (completed without setting an error
- message). Calls the saved callback with the event that came from
- completion_queue_next */
- void HandleOKCallback();
-
- void HandleErrorCallback();
-
- private:
- static void TryAddWorker();
-
- grpc_event result;
-
- static grpc_completion_queue *queue;
-
- // Number of grpc_completion_queue_next calls in the thread pool
- static int current_threads;
- // Number of grpc_completion_queue_next calls waiting to enter the thread pool
- static int waiting_next_calls;
-};
-
-const int max_queue_threads = 2;
-
-using v8::Function;
-using v8::Local;
-using v8::Object;
-using v8::Value;
-
-grpc_completion_queue *CompletionQueueAsyncWorker::queue;
-
-// Invariants: current_threads <= max_queue_threads
-// (current_threads == max_queue_threads) || (waiting_next_calls == 0)
-
-int CompletionQueueAsyncWorker::current_threads;
-int CompletionQueueAsyncWorker::waiting_next_calls;
-
-CompletionQueueAsyncWorker::CompletionQueueAsyncWorker()
- : Nan::AsyncWorker(NULL) {}
-
-CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {}
-
-void CompletionQueueAsyncWorker::Execute() {
- result =
- grpc_completion_queue_next(queue, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
- if (!result.success) {
- SetErrorMessage("The async function encountered an error");
- }
-}
-
-grpc_completion_queue *CompletionQueueAsyncWorker::GetQueue() { return queue; }
-
-void CompletionQueueAsyncWorker::TryAddWorker() {
- if (current_threads < max_queue_threads && waiting_next_calls > 0) {
- current_threads += 1;
- waiting_next_calls -= 1;
- CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker();
- Nan::AsyncQueueWorker(worker);
- }
- GPR_ASSERT(current_threads <= max_queue_threads);
- GPR_ASSERT((current_threads == max_queue_threads) ||
- (waiting_next_calls == 0));
-}
-
-void CompletionQueueAsyncWorker::Next() {
- waiting_next_calls += 1;
- TryAddWorker();
-}
-
-void CompletionQueueAsyncWorker::Init(Local<Object> exports) {
- Nan::HandleScope scope;
- current_threads = 0;
- waiting_next_calls = 0;
- queue = grpc_completion_queue_create(NULL);
-}
-
-void CompletionQueueAsyncWorker::HandleOKCallback() {
- Nan::HandleScope scope;
- current_threads -= 1;
- TryAddWorker();
- CompleteTag(result.tag, NULL);
-
- DestroyTag(result.tag);
-}
-
-void CompletionQueueAsyncWorker::HandleErrorCallback() {
- Nan::HandleScope scope;
- current_threads -= 1;
- TryAddWorker();
- CompleteTag(result.tag, ErrorMessage());
-
- DestroyTag(result.tag);
-}
-
-} // namespace
-
-grpc_completion_queue *GetCompletionQueue() {
- return CompletionQueueAsyncWorker::GetQueue();
-}
-
-void CompletionQueueNext() {
- CompletionQueueAsyncWorker::Next();
-}
-
-void CompletionQueueInit(Local<Object> exports) {
- CompletionQueueAsyncWorker::Init(exports);
-}
-
-} // namespace node
-} // namespace grpc
-
-#endif /* GRPC_UV */
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index 122e5e6..f600cb9 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -43,18 +43,15 @@
#include "grpc/support/time.h"
// TODO(murgatroid99): Remove this when the endpoint API becomes public
-#ifdef GRPC_UV
extern "C" {
#include "src/core/lib/iomgr/pollset_uv.h"
}
-#endif
#include "call.h"
#include "call_credentials.h"
#include "channel.h"
#include "channel_credentials.h"
#include "server.h"
-#include "completion_queue_async_worker.h"
#include "server_credentials.h"
#include "slice.h"
#include "timeval.h"
@@ -438,9 +435,7 @@
InitWriteFlags(exports);
InitLogConstants(exports);
-#ifdef GRPC_UV
grpc_pollset_work_run_loop = 0;
-#endif
grpc::node::Call::Init(exports);
grpc::node::CallCredentials::Init(exports);
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 5384305..f7c62a3 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -41,7 +41,6 @@
#include <vector>
#include "call.h"
#include "completion_queue.h"
-#include "completion_queue_async_worker.h"
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
#include "grpc/support/log.h"
@@ -78,6 +77,30 @@
Nan::Callback *Server::constructor;
Persistent<FunctionTemplate> Server::fun_tpl;
+static Callback *shutdown_callback = NULL;
+
+class ServerShutdownOp : public Op {
+ public:
+ ServerShutdownOp(grpc_server *server) : server(server) {}
+
+ ~ServerShutdownOp() {}
+
+ Local<Value> GetNodeValue() const { return Nan::Null(); }
+
+ bool ParseOp(Local<Value> value, grpc_op *out) { return true; }
+ bool IsFinalOp() { return false; }
+ void OnComplete(bool success) {
+ /* Because cancel_all_calls was called, we assume that shutdown_and_notify
+ completes successfully */
+ grpc_server_destroy(server);
+ }
+
+ grpc_server *server;
+
+ protected:
+ std::string GetTypeString() const { return "shutdown"; }
+};
+
class NewCallOp : public Op {
public:
NewCallOp() {
@@ -156,6 +179,10 @@
server_persist;
};
+Server::Server(grpc_server *server) : wrapped_server(server) {}
+
+Server::~Server() { this->ShutdownServer(); }
+
void Server::Init(Local<Object> exports) {
HandleScope scope;
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
@@ -184,6 +211,36 @@
}
}
+NAN_METHOD(ServerShutdownCallback) {
+ if (!info[0]->IsNull()) {
+ return Nan::ThrowError("forceShutdown failed somehow");
+ }
+}
+
+void Server::ShutdownServer() {
+ Nan::HandleScope scope;
+ if (this->wrapped_server != NULL) {
+ if (shutdown_callback == NULL) {
+ Local<FunctionTemplate> callback_tpl =
+ Nan::New<FunctionTemplate>(ServerShutdownCallback);
+ shutdown_callback =
+ new Callback(Nan::GetFunction(callback_tpl).ToLocalChecked());
+ }
+
+ ServerShutdownOp *op = new ServerShutdownOp(this->wrapped_server);
+ unique_ptr<OpVec> ops(new OpVec());
+ ops->push_back(unique_ptr<Op>(op));
+
+ grpc_server_shutdown_and_notify(
+ this->wrapped_server, GetCompletionQueue(),
+ new struct tag(new Callback(**shutdown_callback), ops.release(), NULL,
+ Nan::Null()));
+ grpc_server_cancel_all_calls(this->wrapped_server);
+ CompletionQueueNext();
+ this->wrapped_server = NULL;
+ }
+}
+
NAN_METHOD(Server::New) {
/* If this is not a constructor call, make a constructor call and return
the result */
diff --git a/src/node/ext/server_generic.cc b/src/node/ext/server_generic.cc
deleted file mode 100644
index 0cf20f7..0000000
--- a/src/node/ext/server_generic.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *
- * Copyright 2017, 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.
- *
- */
-
-#ifndef GRPC_UV
-
-#include "server.h"
-
-#include <node.h>
-#include <nan.h>
-#include "grpc/grpc.h"
-#include "grpc/support/time.h"
-
-namespace grpc {
-namespace node {
-
-Server::Server(grpc_server *server) : wrapped_server(server) {
- shutdown_queue = grpc_completion_queue_create(NULL);
- grpc_server_register_non_listening_completion_queue(server, shutdown_queue,
- NULL);
-}
-
-Server::~Server() {
- this->ShutdownServer();
- grpc_completion_queue_shutdown(this->shutdown_queue);
- grpc_completion_queue_destroy(this->shutdown_queue);
-}
-
-void Server::ShutdownServer() {
- if (this->wrapped_server != NULL) {
- grpc_server_shutdown_and_notify(this->wrapped_server, this->shutdown_queue,
- NULL);
- grpc_server_cancel_all_calls(this->wrapped_server);
- grpc_completion_queue_pluck(this->shutdown_queue, NULL,
- gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
- grpc_server_destroy(this->wrapped_server);
- this->wrapped_server = NULL;
- }
-}
-
-} // namespace grpc
-} // namespace node
-
-#endif /* GRPC_UV */
diff --git a/src/node/ext/server_uv.cc b/src/node/ext/server_uv.cc
deleted file mode 100644
index 7899383..0000000
--- a/src/node/ext/server_uv.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- *
- * Copyright 2017, 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.
- *
- */
-
-#ifdef GRPC_UV
-
-#include "server.h"
-
-#include <node.h>
-#include <nan.h>
-#include "grpc/grpc.h"
-#include "grpc/support/time.h"
-
-#include "call.h"
-#include "completion_queue.h"
-
-namespace grpc {
-namespace node {
-
-using Nan::Callback;
-using Nan::MaybeLocal;
-
-using v8::External;
-using v8::Function;
-using v8::FunctionTemplate;
-using v8::Local;
-using v8::Object;
-using v8::Value;
-
-static Callback *shutdown_callback = NULL;
-
-class ServerShutdownOp : public Op {
- public:
- ServerShutdownOp(grpc_server *server): server(server) {
- }
-
- ~ServerShutdownOp() {
- }
-
- Local<Value> GetNodeValue() const {
- return Nan::Null();
- }
-
- bool ParseOp(Local<Value> value, grpc_op *out) {
- return true;
- }
- bool IsFinalOp() {
- return false;
- }
- void OnComplete(bool success) {
- /* Because cancel_all_calls was called, we assume that shutdown_and_notify
- completes successfully */
- grpc_server_destroy(server);
- }
-
- grpc_server *server;
-
- protected:
- std::string GetTypeString() const { return "shutdown"; }
-};
-
-Server::Server(grpc_server *server) : wrapped_server(server) {
-}
-
-Server::~Server() {
- this->ShutdownServer();
-}
-
-NAN_METHOD(ServerShutdownCallback) {
- if (!info[0]->IsNull()) {
- return Nan::ThrowError("forceShutdown failed somehow");
- }
-}
-
-void Server::ShutdownServer() {
- Nan::HandleScope scope;
- if (this->wrapped_server != NULL) {
- if (shutdown_callback == NULL) {
- Local<FunctionTemplate>callback_tpl =
- Nan::New<FunctionTemplate>(ServerShutdownCallback);
- shutdown_callback = new Callback(
- Nan::GetFunction(callback_tpl).ToLocalChecked());
- }
-
- ServerShutdownOp *op = new ServerShutdownOp(this->wrapped_server);
- unique_ptr<OpVec> ops(new OpVec());
- ops->push_back(unique_ptr<Op>(op));
-
- grpc_server_shutdown_and_notify(
- this->wrapped_server, GetCompletionQueue(),
- new struct tag(new Callback(**shutdown_callback), ops.release(), NULL,
- Nan::Null()));
- grpc_server_cancel_all_calls(this->wrapped_server);
- CompletionQueueNext();
- this->wrapped_server = NULL;
- }
-}
-
-} // namespace grpc
-} // namespace node
-
-#endif /* GRPC_UV */
diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json
index 3d33118..2fdcb12 100644
--- a/src/node/health_check/package.json
+++ b/src/node/health_check/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc-health-check",
- "version": "1.3.0-pre1",
+ "version": "1.3.5",
"author": "Google Inc.",
"description": "Health check service for use with gRPC",
"repository": {
@@ -15,7 +15,7 @@
}
],
"dependencies": {
- "grpc": "^1.3.0-pre1",
+ "grpc": "^1.3.5",
"lodash": "^3.9.3",
"google-protobuf": "^3.0.0"
},
diff --git a/src/node/index.js b/src/node/index.js
index 071bfd7..fb313ac 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -64,8 +64,6 @@
* Buffers. Defaults to false
* - longsAsStrings: deserialize long values as strings instead of objects.
* Defaults to true
- * - enumsAsStrings: deserialize enum values as strings instead of numbers.
- * Defaults to true
* - deprecatedArgumentOrder: Use the beta method argument order for client
* methods, with optional arguments after the callback. Defaults to false.
* This option is only a temporary stopgap measure to smooth an API breakage.
@@ -99,10 +97,6 @@
switch (protobufjsVersion) {
case 6: return protobuf_js_6_common.loadObject(value, options);
case 5:
- var deprecation_message = 'Calling grpc.loadObject with an object ' +
- 'generated by ProtoBuf.js 5 is deprecated. Please upgrade to ' +
- 'ProtoBuf.js 6.';
- common.log(grpc.logVerbosity.INFO, deprecation_message);
return protobuf_js_5_common.loadObject(value, options);
default:
throw new Error('Unrecognized protobufjsVersion', protobufjsVersion);
@@ -111,19 +105,6 @@
var loadObject = exports.loadObject;
-function applyProtoRoot(filename, root) {
- if (_.isString(filename)) {
- return filename;
- }
- filename.root = path.resolve(filename.root) + '/';
- root.resolvePath = function(originPath, importPath, alreadyNormalized) {
- return ProtoBuf.util.path.resolve(filename.root,
- importPath,
- alreadyNormalized);
- };
- return filename.file;
-}
-
/**
* Load a gRPC object from a .proto file. The options object can provide the
* following options:
@@ -133,8 +114,6 @@
* Buffers. Defaults to false
* - longsAsStrings: deserialize long values as strings instead of objects.
* Defaults to true
- * - enumsAsStrings: deserialize enum values as strings instead of numbers.
- * Defaults to true
* - deprecatedArgumentOrder: Use the beta method argument order for client
* methods, with optional arguments after the callback. Defaults to false.
* This option is only a temporary stopgap measure to smooth an API breakage.
@@ -146,17 +125,31 @@
* @return {Object<string, *>} The resulting gRPC object
*/
exports.load = function load(filename, format, options) {
- /* Note: format is currently unused, because the API for loading a proto
- file or a JSON file is identical in Protobuf.js 6. In the future, there is
- still the possibility of adding other formats that would be loaded
- differently */
options = _.defaults(options, common.defaultGrpcOptions);
- options.protobufjs_version = 6;
- var root = new ProtoBuf.Root();
- var parse_options = {keepCase: !options.convertFieldsToCamelCase};
- return loadObject(root.loadSync(applyProtoRoot(filename, root),
- parse_options),
- options);
+ options.protobufjsVersion = 5;
+ if (!format) {
+ format = 'proto';
+ }
+ var convertFieldsToCamelCaseOriginal = ProtoBuf.convertFieldsToCamelCase;
+ if(options && options.hasOwnProperty('convertFieldsToCamelCase')) {
+ ProtoBuf.convertFieldsToCamelCase = options.convertFieldsToCamelCase;
+ }
+ var builder;
+ try {
+ switch(format) {
+ case 'proto':
+ builder = ProtoBuf.loadProtoFile(filename);
+ break;
+ case 'json':
+ builder = ProtoBuf.loadJsonFile(filename);
+ break;
+ default:
+ throw new Error('Unrecognized format "' + format + '"');
+ }
+ } finally {
+ ProtoBuf.convertFieldsToCamelCase = convertFieldsToCamelCaseOriginal;
+ }
+ return loadObject(builder.ns, options);
};
var log_template = _.template(
diff --git a/src/node/performance/benchmark_client.js b/src/node/performance/benchmark_client.js
index 5ef5260..e7c426b 100644
--- a/src/node/performance/benchmark_client.js
+++ b/src/node/performance/benchmark_client.js
@@ -88,7 +88,10 @@
*/
function BenchmarkClient(server_targets, channels, histogram_params,
security_params) {
- var options = {};
+ var options = {
+ "grpc.max_receive_message_length": -1,
+ "grpc.max_send_message_length": -1
+ };
var creds;
if (security_params) {
var ca_path;
@@ -180,6 +183,8 @@
self.last_wall_time = process.hrtime();
+ self.last_usage = process.cpuUsage();
+
var makeCall;
var argument;
@@ -270,6 +275,8 @@
self.last_wall_time = process.hrtime();
+ self.last_usage = process.cpuUsage();
+
var makeCall;
var argument;
@@ -354,9 +361,11 @@
*/
BenchmarkClient.prototype.mark = function(reset) {
var wall_time_diff = process.hrtime(this.last_wall_time);
+ var usage_diff = process.cpuUsage(this.last_usage);
var histogram = this.histogram;
if (reset) {
this.last_wall_time = process.hrtime();
+ this.last_usage = process.cpuUsage();
this.histogram = new Histogram(histogram.resolution,
histogram.max_possible);
}
@@ -371,9 +380,8 @@
count: histogram.getCount()
},
time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
- // Not sure how to measure these values
- time_user: 0,
- time_system: 0
+ time_user: usage_diff.user / 1000000,
+ time_system: usage_diff.system / 1000000
};
};
diff --git a/src/node/performance/benchmark_client_express.js b/src/node/performance/benchmark_client_express.js
index e749956..157bf1b 100644
--- a/src/node/performance/benchmark_client_express.js
+++ b/src/node/performance/benchmark_client_express.js
@@ -95,7 +95,6 @@
var host_port;
host_port = server_targets[i % server_targets.length].split(':');
var new_options = _.assign({hostname: host_port[0], port: +host_port[1]}, options);
- new_options.agent = new protocol.Agent(new_options);
this.client_options[i] = new_options;
}
@@ -137,6 +136,7 @@
}
self.last_wall_time = process.hrtime();
+ self.last_usage = process.cpuUsage();
var argument = {
response_size: resp_size,
@@ -207,6 +207,7 @@
}
self.last_wall_time = process.hrtime();
+ self.last_usage = process.cpuUsage();
var argument = {
response_size: resp_size,
@@ -264,9 +265,11 @@
*/
BenchmarkClient.prototype.mark = function(reset) {
var wall_time_diff = process.hrtime(this.last_wall_time);
+ var usage_diff = process.cpuUsage(this.last_usage);
var histogram = this.histogram;
if (reset) {
this.last_wall_time = process.hrtime();
+ this.last_usage = process.cpuUsage();
this.histogram = new Histogram(histogram.resolution,
histogram.max_possible);
}
@@ -281,9 +284,8 @@
count: histogram.getCount()
},
time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
- // Not sure how to measure these values
- time_user: 0,
- time_system: 0
+ time_user: usage_diff.user / 1000000,
+ time_system: usage_diff.system / 1000000
};
};
diff --git a/src/node/performance/benchmark_server.js b/src/node/performance/benchmark_server.js
index ea85029..a4d5ee1 100644
--- a/src/node/performance/benchmark_server.js
+++ b/src/node/performance/benchmark_server.js
@@ -132,7 +132,12 @@
server_creds = grpc.ServerCredentials.createInsecure();
}
- var server = new grpc.Server();
+ var options = {
+ "grpc.max_receive_message_length": -1,
+ "grpc.max_send_message_length": -1
+ };
+
+ var server = new grpc.Server(options);
this.port = server.bind(host + ':' + port, server_creds);
if (generic) {
server.addService(genericService, {
@@ -156,6 +161,7 @@
BenchmarkServer.prototype.start = function() {
this.server.start();
this.last_wall_time = process.hrtime();
+ this.last_usage = process.cpuUsage();
this.emit('started');
};
@@ -175,14 +181,15 @@
*/
BenchmarkServer.prototype.mark = function(reset) {
var wall_time_diff = process.hrtime(this.last_wall_time);
+ var usage_diff = process.cpuUsage(this.last_usage);
if (reset) {
this.last_wall_time = process.hrtime();
+ this.last_usage = process.cpuUsage();
}
return {
time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
- // Not sure how to measure these values
- time_user: 0,
- time_system: 0
+ time_user: usage_diff.user / 1000000,
+ time_system: usage_diff.system / 1000000
};
};
diff --git a/src/node/performance/benchmark_server_express.js b/src/node/performance/benchmark_server_express.js
index 4b695eb..fab4f53 100644
--- a/src/node/performance/benchmark_server_express.js
+++ b/src/node/performance/benchmark_server_express.js
@@ -81,6 +81,7 @@
var self = this;
this.server.listen(this.input_port, this.input_hostname, function() {
self.last_wall_time = process.hrtime();
+ self.last_usage = process.cpuUsage();
self.emit('started');
});
};
@@ -91,14 +92,15 @@
BenchmarkServer.prototype.mark = function(reset) {
var wall_time_diff = process.hrtime(this.last_wall_time);
+ var usage_diff = process.cpuUsage(this.last_usage);
if (reset) {
this.last_wall_time = process.hrtime();
+ this.last_usage = process.cpuUsage();
}
return {
time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
- // Not sure how to measure these values
- time_user: 0,
- time_system: 0
+ time_user: usage_diff.user / 1000000,
+ time_system: usage_diff.system / 1000000
};
};
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 1aaf35c..2073d3e 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -100,6 +100,12 @@
/* jshint validthis: true */
var batch = {};
var message;
+ var self = this;
+ if (this.writeFailed) {
+ /* Once a write fails, just call the callback immediately to let the caller
+ flush any pending writes. */
+ setImmediate(callback);
+ }
try {
message = this.serialize(chunk);
} catch (e) {
@@ -119,8 +125,10 @@
batch[grpc.opType.SEND_MESSAGE] = message;
this.call.startBatch(batch, function(err, event) {
if (err) {
- // Something has gone wrong. Stop writing by failing to call callback
- return;
+ /* Assume that the call is complete and that writing failed because a
+ status was received. In that case, set a flag to discard all future
+ writes */
+ self.writeFailed = true;
}
callback();
});
diff --git a/src/node/src/protobuf_js_5_common.js b/src/node/src/protobuf_js_5_common.js
index 62cf2f4..4041e05 100644
--- a/src/node/src/protobuf_js_5_common.js
+++ b/src/node/src/protobuf_js_5_common.js
@@ -45,8 +45,7 @@
* objects. Defaults to true
* @return {function(Buffer):cls} The deserialization function
*/
-exports.deserializeCls = function deserializeCls(cls, binaryAsBase64,
- longsAsStrings) {
+exports.deserializeCls = function deserializeCls(cls, options) {
/**
* Deserialize a buffer to a message object
* @param {Buffer} arg_buf The buffer to deserialize
@@ -55,7 +54,8 @@
return function deserialize(arg_buf) {
// Convert to a native object with binary fields as Buffers (first argument)
// and longs as strings (second argument)
- return cls.decode(arg_buf).toRaw(binaryAsBase64, longsAsStrings);
+ return cls.decode(arg_buf).toRaw(options.binaryAsBase64,
+ options.longsAsStrings);
};
};
@@ -128,10 +128,10 @@
responseType: method.resolvedResponseType,
requestSerialize: serializeCls(method.resolvedRequestType.build()),
requestDeserialize: deserializeCls(method.resolvedRequestType.build(),
- binaryAsBase64, longsAsStrings),
+ options),
responseSerialize: serializeCls(method.resolvedResponseType.build()),
responseDeserialize: deserializeCls(method.resolvedResponseType.build(),
- binaryAsBase64, longsAsStrings)
+ options)
};
}));
};
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 3450abe..25640a0 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -779,6 +779,11 @@
});
};
+var logAddProtoServiceDeprecationOnce = _.once(function() {
+ common.log(grpc.logVerbosity.INFO,
+ 'Server#addProtoService is deprecated. Use addService instead');
+});
+
/**
* Add a proto service to the server, with a corresponding implementation
* @deprecated Use grpc.load and Server#addService instead
@@ -790,8 +795,7 @@
var options;
var protobuf_js_5_common = require('./protobuf_js_5_common');
var protobuf_js_6_common = require('./protobuf_js_6_common');
- common.log(grpc.logVerbosity.INFO,
- 'Server#addProtoService is deprecated. Use addService instead');
+ logAddProtoServiceDeprecationOnce();
if (protobuf_js_5_common.isProbablyProtobufJs5(service)) {
options = _.defaults(service.grpc_options, common.defaultGrpcOptions);
this.addService(
diff --git a/src/node/test/common_test.js b/src/node/test/common_test.js
index e1ce864..b7c2c6a 100644
--- a/src/node/test/common_test.js
+++ b/src/node/test/common_test.js
@@ -37,16 +37,15 @@
var _ = require('lodash');
var common = require('../src/common');
-var protobuf_js_6_common = require('../src/protobuf_js_6_common');
+var protobuf_js_5_common = require('../src/protobuf_js_5_common');
-var serializeCls = protobuf_js_6_common.serializeCls;
-var deserializeCls = protobuf_js_6_common.deserializeCls;
+var serializeCls = protobuf_js_5_common.serializeCls;
+var deserializeCls = protobuf_js_5_common.deserializeCls;
var ProtoBuf = require('protobufjs');
-var messages_proto = new ProtoBuf.Root();
-messages_proto = messages_proto.loadSync(
- __dirname + '/test_messages.proto', {keepCase: true}).resolveAll();
+var messages_proto = ProtoBuf.loadProtoFile(
+ __dirname + '/test_messages.proto').build();
var default_options = common.defaultGrpcOptions;
@@ -101,6 +100,7 @@
var longNumDeserialize = deserializeCls(messages_proto.LongValues,
num_options);
var serialized = longSerialize({int_64: pos_value});
+ console.log(longDeserialize(serialized));
assert.strictEqual(typeof longDeserialize(serialized).int_64, 'string');
/* With the longsAsStrings option disabled, long values are represented as
* objects with 3 keys: low, high, and unsigned */
@@ -136,7 +136,8 @@
var serialized = sequenceSerialize({repeated_field: [10]});
assert.strictEqual(expected_serialize.compare(serialized), 0);
});
- it('should deserialize packed or unpacked repeated', function() {
+ // This tests a bug that was fixed in Protobuf.js 6
+ it.skip('should deserialize packed or unpacked repeated', function() {
var expectedDeserialize = {
bytes_field: new Buffer(''),
repeated_field: [10]
@@ -155,7 +156,8 @@
assert.deepEqual(unpackedDeserialized, expectedDeserialize);
});
});
-describe('Proto message oneof serialize and deserialize', function() {
+// This tests a bug that was fixed in Protobuf.js 6
+describe.skip('Proto message oneof serialize and deserialize', function() {
var oneofSerialize = serializeCls(messages_proto.OneOfValues);
var oneofDeserialize = deserializeCls(
messages_proto.OneOfValues, default_options);
@@ -193,7 +195,8 @@
assert.deepEqual(enumDeserialize(nameSerialized),
enumDeserialize(numberSerialized));
});
- it('Should deserialize as a string the enumsAsStrings option', function() {
+ // This tests a bug that was fixed in Protobuf.js 6
+ it.skip('Should correctly handle the enumsAsStrings option', function() {
var serialized = enumSerialize({enum_value: 'TWO'});
var nameDeserialized = enumDeserialize(serialized);
var numberDeserialized = enumIntDeserialize(serialized);
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 783028f..d2f0511 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -43,9 +43,8 @@
var grpc = require('..');
-var math_proto = new ProtoBuf.Root();
-math_proto = math_proto.loadSync(__dirname +
- '/../../proto/math/math.proto', {keepCase: true});
+var math_proto = ProtoBuf.loadProtoFile(__dirname +
+ '/../../proto/math/math.proto');
var mathService = math_proto.lookup('math.Math');
var mathServiceAttrs = grpc.loadObject(
@@ -332,9 +331,7 @@
var server;
var client;
before(function() {
- var test_proto = new ProtoBuf.Root();
- test_proto = test_proto.loadSync(__dirname + '/echo_service.proto',
- {keepCase: true});
+ var test_proto = ProtoBuf.loadProtoFile(__dirname + '/echo_service.proto');
var echo_service = test_proto.lookup('EchoService');
var Client = grpc.loadObject(echo_service);
server = new grpc.Server();
@@ -357,6 +354,13 @@
done();
});
});
+ it('Should convert an undefined argument to default values', function(done) {
+ client.echo(undefined, function(error, response) {
+ assert.ifError(error);
+ assert.deepEqual(response, {value: '', value2: 0});
+ done();
+ });
+ });
});
describe('Generic client and server', function() {
function toString(val) {
@@ -457,9 +461,7 @@
var server;
var metadata;
before(function() {
- var test_proto = new ProtoBuf.Root();
- test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
- {keepCase: true});
+ var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
var test_service = test_proto.lookup('TestService');
var Client = grpc.loadObject(test_service);
server = new grpc.Server();
@@ -560,9 +562,7 @@
var client;
var badArg = new Buffer([0xFF]);
before(function() {
- var test_proto = new ProtoBuf.Root();
- test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
- {keepCase: true});
+ var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
var test_service = test_proto.lookup('TestService');
var malformed_test_service = {
unary: {
@@ -669,9 +669,7 @@
var client;
var server;
before(function() {
- var test_proto = new ProtoBuf.Root();
- test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
- {keepCase: true});
+ var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
var test_service = test_proto.lookup('TestService');
var malformed_test_service = {
unary: {
@@ -772,16 +770,13 @@
});
});
describe('Other conditions', function() {
- var test_service;
var Client;
var client;
var server;
var port;
before(function() {
- var test_proto = new ProtoBuf.Root();
- test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
- {keepCase: true});
- test_service = test_proto.lookup('TestService');
+ var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+ var test_service = test_proto.lookup('TestService');
Client = grpc.loadObject(test_service);
server = new grpc.Server();
var trailer_metadata = new grpc.Metadata();
@@ -1121,15 +1116,12 @@
var proxy;
var proxy_impl;
- var test_service;
var Client;
var client;
var server;
before(function() {
- var test_proto = new ProtoBuf.Root();
- test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
- {keepCase: true});
- test_service = test_proto.lookup('TestService');
+ var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+ var test_service = test_proto.lookup('TestService');
server = new grpc.Server();
Client = grpc.loadObject(test_service);
server.addService(Client.service, {
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
index 056f28a..cabd403 100644
--- a/src/node/tools/package.json
+++ b/src/node/tools/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc-tools",
- "version": "1.3.0-pre1",
+ "version": "1.3.5",
"author": "Google Inc.",
"description": "Tools for developing with gRPC on Node.js",
"homepage": "http://www.grpc.io/",
diff --git "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec" "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
index e636d9c..23f9186 100644
--- "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
+++ "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
@@ -42,7 +42,7 @@
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCPlugin'
- v = '1.3.0-pre1'
+ v = '1.3.5'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
s.description = <<-DESC
diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h
index b53033d..43ab9bd 100644
--- a/src/objective-c/GRPCClient/private/version.h
+++ b/src/objective-c/GRPCClient/private/version.h
@@ -38,4 +38,4 @@
// `tools/buildgen/generate_projects.sh`.
-#define GRPC_OBJC_VERSION_STRING @"1.3.0-pre1"
+#define GRPC_OBJC_VERSION_STRING @"1.3.5"
diff --git a/src/php/composer.json b/src/php/composer.json
index 2b14007..08f2b9a 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
"name": "grpc/grpc-dev",
"description": "gRPC library for PHP - for Developement use only",
"license": "BSD-3-Clause",
- "version": "1.3.0",
+ "version": "1.3.5",
"require": {
"php": ">=5.5.0",
"google/protobuf": "^v3.1.0"
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 48a374f..86bd40e 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -125,7 +125,12 @@
php_grpc_add_next_index_stringl(inner_array, str_val,
GRPC_SLICE_LENGTH(elem->value), false);
add_assoc_zval(array, str_key, inner_array);
+ PHP_GRPC_FREE_STD_ZVAL(inner_array);
}
+ efree(str_key);
+#if PHP_MAJOR_VERSION >= 7
+ efree(str_val);
+#endif
}
return array;
}
@@ -256,8 +261,6 @@
object_init(result);
php_grpc_ulong index;
zval *recv_status;
- PHP_GRPC_MAKE_STD_ZVAL(recv_status);
- object_init(recv_status);
zval *value;
zval *inner_value;
zval *message_value;
@@ -439,7 +442,7 @@
grpc_completion_queue_pluck(completion_queue, call->wrapped,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
#if PHP_MAJOR_VERSION >= 7
- zval recv_md;
+ zval *recv_md;
#endif
for (int i = 0; i < op_num; i++) {
switch(ops[i].op) {
@@ -460,8 +463,10 @@
array = grpc_parse_metadata_array(&recv_metadata TSRMLS_CC);
add_property_zval(result, "metadata", array);
#else
- recv_md = *grpc_parse_metadata_array(&recv_metadata);
- add_property_zval(result, "metadata", &recv_md);
+ recv_md = grpc_parse_metadata_array(&recv_metadata);
+ add_property_zval(result, "metadata", recv_md);
+ zval_ptr_dtor(recv_md);
+ PHP_GRPC_FREE_STD_ZVAL(recv_md);
#endif
PHP_GRPC_DELREF(array);
break;
@@ -475,12 +480,16 @@
}
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ PHP_GRPC_MAKE_STD_ZVAL(recv_status);
+ object_init(recv_status);
#if PHP_MAJOR_VERSION < 7
array = grpc_parse_metadata_array(&recv_trailing_metadata TSRMLS_CC);
add_property_zval(recv_status, "metadata", array);
#else
- recv_md = *grpc_parse_metadata_array(&recv_trailing_metadata);
- add_property_zval(recv_status, "metadata", &recv_md);
+ recv_md = grpc_parse_metadata_array(&recv_trailing_metadata);
+ add_property_zval(recv_status, "metadata", recv_md);
+ zval_ptr_dtor(recv_md);
+ PHP_GRPC_FREE_STD_ZVAL(recv_md);
#endif
PHP_GRPC_DELREF(array);
add_property_long(recv_status, "code", status);
@@ -489,6 +498,9 @@
true);
gpr_free(status_details_text);
add_property_zval(result, "status", recv_status);
+#if PHP_MAJOR_VERSION >= 7
+ zval_ptr_dtor(recv_status);
+#endif
PHP_GRPC_DELREF(recv_status);
PHP_GRPC_FREE_STD_ZVAL(recv_status);
break;
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index 625c0c6..da7100f 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -172,34 +172,54 @@
object_init(arg);
php_grpc_add_property_string(arg, "service_url", context.service_url, true);
php_grpc_add_property_string(arg, "method_name", context.method_name, true);
- zval *retval;
- PHP_GRPC_MAKE_STD_ZVAL(retval);
+ zval *retval = NULL;
#if PHP_MAJOR_VERSION < 7
zval **params[1];
params[0] = &arg;
state->fci->params = params;
state->fci->retval_ptr_ptr = &retval;
#else
+ PHP_GRPC_MAKE_STD_ZVAL(retval);
state->fci->params = arg;
state->fci->retval = retval;
#endif
state->fci->param_count = 1;
+ PHP_GRPC_DELREF(arg);
+
/* call the user callback function */
zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
grpc_status_code code = GRPC_STATUS_OK;
grpc_metadata_array metadata;
+ bool cleanup = true;
if (Z_TYPE_P(retval) != IS_ARRAY) {
+ cleanup = false;
code = GRPC_STATUS_INVALID_ARGUMENT;
} else if (!create_metadata_array(retval, &metadata)) {
- grpc_metadata_array_destroy(&metadata);
code = GRPC_STATUS_INVALID_ARGUMENT;
}
+ if (retval != NULL) {
+#if PHP_MAJOR_VERSION < 7
+ zval_ptr_dtor(&retval);
+#else
+ zval_ptr_dtor(arg);
+ zval_ptr_dtor(retval);
+ PHP_GRPC_FREE_STD_ZVAL(arg);
+ PHP_GRPC_FREE_STD_ZVAL(retval);
+#endif
+ }
+
/* Pass control back to core */
cb(user_data, metadata.metadata, metadata.count, code, NULL);
+ if (cleanup) {
+ for (int i = 0; i < metadata.count; i++) {
+ grpc_slice_unref(metadata.metadata[i].value);
+ }
+ grpc_metadata_array_destroy(&metadata);
+ }
}
/* Cleanup function for plugin creds API */
@@ -207,8 +227,10 @@
plugin_state *state = (plugin_state *)ptr;
efree(state->fci);
efree(state->fci_cache);
+#if PHP_MAJOR_VERSION < 7
PHP_GRPC_FREE_STD_ZVAL(state->fci->params);
PHP_GRPC_FREE_STD_ZVAL(state->fci->retval);
+#endif
efree(state);
}
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index a37630a..52b1397 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
-VERSION='1.3.0rc1'
+VERSION='1.3.5'
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index c08110e..143c1ed 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
-VERSION='1.3.0rc1'
+VERSION='1.3.5'
diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py
index 4565732..66f1ff9 100644
--- a/src/python/grpcio_reflection/grpc_version.py
+++ b/src/python/grpcio_reflection/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
-VERSION='1.3.0rc1'
+VERSION='1.3.5'
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index aadfabf..a6da39c 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
-VERSION='1.3.0rc1'
+VERSION='1.3.5'
diff --git a/src/ruby/end2end/channel_closing_driver.rb b/src/ruby/end2end/channel_closing_driver.rb
index d3e5373..bed8c43 100755
--- a/src/ruby/end2end/channel_closing_driver.rb
+++ b/src/ruby/end2end/channel_closing_driver.rb
@@ -61,6 +61,11 @@
'channel is closed while connectivity is watched'
end
+ client_exit_code = $CHILD_STATUS
+ if client_exit_code != 0
+ fail "channel closing client failed, exit code #{client_exit_code}"
+ end
+
server_runner.stop
end
diff --git a/src/ruby/end2end/channel_state_driver.rb b/src/ruby/end2end/channel_state_driver.rb
index 80fb628..9910076 100755
--- a/src/ruby/end2end/channel_state_driver.rb
+++ b/src/ruby/end2end/channel_state_driver.rb
@@ -58,6 +58,9 @@
'It likely hangs when ended abruptly'
end
+ # The interrupt in the child process should cause it to
+ # exit a non-zero status, so don't check it here.
+ # This test mainly tries to catch deadlock.
server_runner.stop
end
diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb
index ee79292..e73ca76 100755
--- a/src/ruby/end2end/grpc_class_init_client.rb
+++ b/src/ruby/end2end/grpc_class_init_client.rb
@@ -34,44 +34,110 @@
require_relative './end2end_common'
-def main
- grpc_class = ''
- OptionParser.new do |opts|
- opts.on('--grpc_class=P', String) do |p|
- grpc_class = p
+def construct_many(test_proc)
+ thds = []
+ 4.times do
+ thds << Thread.new do
+ 20.times do
+ test_proc.call
+ end
end
- end.parse!
+ end
+ 20.times do
+ test_proc.call
+ end
+ thds.each(&:join)
+end
- test_proc = nil
+def run_gc_stress_test(test_proc)
+ GC.disable
+ construct_many(test_proc)
+ GC.enable
+ construct_many(test_proc)
+
+ GC.start(full_mark: true, immediate_sweep: true)
+ construct_many(test_proc)
+end
+
+def run_concurrency_stress_test(test_proc)
+ 100.times do
+ Thread.new do
+ test_proc.call
+ end
+ end
+
+ test_proc.call
+
+ fail 'exception thrown while child thread initing class'
+end
+
+# default (no gc_stress and no concurrency_stress)
+def run_default_test(test_proc)
+ thd = Thread.new do
+ test_proc.call
+ end
+ test_proc.call
+ thd.join
+end
+
+def get_test_proc(grpc_class)
case grpc_class
when 'channel'
- test_proc = proc do
+ return proc do
GRPC::Core::Channel.new('dummy_host', nil, :this_channel_is_insecure)
end
when 'server'
- test_proc = proc do
+ return proc do
GRPC::Core::Server.new({})
end
when 'channel_credentials'
- test_proc = proc do
+ return proc do
GRPC::Core::ChannelCredentials.new
end
when 'call_credentials'
- test_proc = proc do
+ return proc do
GRPC::Core::CallCredentials.new(proc { |noop| noop })
end
when 'compression_options'
- test_proc = proc do
+ return proc do
GRPC::Core::CompressionOptions.new
end
else
fail "bad --grpc_class=#{grpc_class} param"
end
+end
- th = Thread.new { test_proc.call }
- test_proc.call
- th.join
+def main
+ grpc_class = ''
+ stress_test = ''
+ OptionParser.new do |opts|
+ opts.on('--grpc_class=P', String) do |p|
+ grpc_class = p
+ end
+ opts.on('--stress_test=P') do |p|
+ stress_test = p
+ end
+ end.parse!
+
+ test_proc = get_test_proc(grpc_class)
+
+ # the different test configs need to be ran
+ # in separate processes, since each one tests
+ # clean shutdown in a different way
+ case stress_test
+ when 'gc'
+ p 'run gc stress'
+ run_gc_stress_test(test_proc)
+ when 'concurrency'
+ p 'run concurrency stress'
+ run_concurrency_stress_test(test_proc)
+ when ''
+ p 'run default'
+ run_default_test(test_proc)
+ else
+ fail "bad --stress_test=#{stress_test} param"
+ end
end
main
diff --git a/src/ruby/end2end/grpc_class_init_driver.rb b/src/ruby/end2end/grpc_class_init_driver.rb
index 764d029..c65ed54 100755
--- a/src/ruby/end2end/grpc_class_init_driver.rb
+++ b/src/ruby/end2end/grpc_class_init_driver.rb
@@ -38,29 +38,40 @@
call_credentials
compression_options )
- native_grpc_classes.each do |grpc_class|
- STDERR.puts 'start client'
- this_dir = File.expand_path(File.dirname(__FILE__))
- client_path = File.join(this_dir, 'grpc_class_init_client.rb')
- client_pid = Process.spawn(RbConfig.ruby,
- client_path,
- "--grpc_class=#{grpc_class}")
- begin
- Timeout.timeout(10) do
- Process.wait(client_pid)
- end
- rescue Timeout::Error
- STDERR.puts "timeout waiting for client pid #{client_pid}"
- Process.kill('SIGKILL', client_pid)
- Process.wait(client_pid)
- STDERR.puts 'killed client child'
- raise 'Timed out waiting for client process. ' \
- 'It likely hangs when the first constructed gRPC object has ' \
- "type: #{grpc_class}"
- end
+ # there is room for false positives in this test,
+ # do a few runs for each config
+ 4.times do
+ native_grpc_classes.each do |grpc_class|
+ ['', 'gc', 'concurrency'].each do |stress_test_type|
+ STDERR.puts 'start client'
+ this_dir = File.expand_path(File.dirname(__FILE__))
+ client_path = File.join(this_dir, 'grpc_class_init_client.rb')
+ client_pid = Process.spawn(RbConfig.ruby,
+ client_path,
+ "--grpc_class=#{grpc_class}",
+ "--stress_test=#{stress_test_type}")
+ begin
+ Timeout.timeout(10) do
+ Process.wait(client_pid)
+ end
+ rescue Timeout::Error
+ STDERR.puts "timeout waiting for client pid #{client_pid}"
+ Process.kill('SIGKILL', client_pid)
+ Process.wait(client_pid)
+ STDERR.puts 'killed client child'
+ raise 'Timed out waiting for client process. ' \
+ 'It likely hangs when the first constructed gRPC object has ' \
+ "type: #{grpc_class}"
+ end
- client_exit_code = $CHILD_STATUS
- fail "client failed, exit code #{client_exit_code}" if client_exit_code != 0
+ client_exit_code = $CHILD_STATUS
+ # concurrency stress test type is expected to exit with a
+ # non-zero status due to an exception being raised
+ if client_exit_code != 0 && stress_test_type != 'concurrency'
+ fail "client failed, exit code #{client_exit_code}"
+ end
+ end
+ end
end
end
diff --git a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb
new file mode 100755
index 0000000..206ec8e
--- /dev/null
+++ b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb
@@ -0,0 +1,63 @@
+#!/usr/bin/env ruby
+
+# 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.
+
+require_relative './end2end_common'
+
+Thread.abort_on_exception = true
+
+include GRPC::Core::ConnectivityStates
+
+def watch_state(ch)
+ thd = Thread.new do
+ state = ch.connectivity_state(false)
+ fail "non-idle state: #{state}" unless state == IDLE
+ ch.watch_connectivity_state(IDLE, Time.now + 360)
+ end
+ sleep 0.1
+ thd.kill
+end
+
+def main
+ channels = []
+ 10.times do
+ ch = GRPC::Core::Channel.new('dummy_host',
+ nil, :this_channel_is_insecure)
+ watch_state(ch)
+ channels << ch
+ end
+
+ # checking state should still be safe to call
+ channels.each do |c|
+ fail unless c.connectivity_state(false) == FATAL_FAILURE
+ end
+end
+
+main
diff --git a/src/ruby/end2end/sig_int_during_channel_watch_client.rb b/src/ruby/end2end/sig_int_during_channel_watch_client.rb
index 389fc5b..0c6a374 100755
--- a/src/ruby/end2end/sig_int_during_channel_watch_client.rb
+++ b/src/ruby/end2end/sig_int_during_channel_watch_client.rb
@@ -46,6 +46,8 @@
end
end.parse!
+ trap('SIGINT') { exit 0 }
+
thd = Thread.new do
child_thread_channel = GRPC::Core::Channel.new("localhost:#{server_port}",
{},
diff --git a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
index 670cda0..79a8c13 100755
--- a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
+++ b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
@@ -63,6 +63,11 @@
'SIGINT is sent while there is an active connectivity_state call'
end
+ client_exit_code = $CHILD_STATUS
+ if client_exit_code != 0
+ fail "sig_int_during_channel_watch_client failed: #{client_exit_code}"
+ end
+
server_runner.stop
end
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index fb610f5..7aaa71e 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -34,9 +34,9 @@
#include <ruby/ruby.h>
#include <ruby/thread.h>
-#include "rb_grpc_imports.generated.h"
#include "rb_byte_buffer.h"
#include "rb_channel.h"
+#include "rb_grpc_imports.generated.h"
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
@@ -68,29 +68,53 @@
/* Used during the conversion of a hash to channel args during channel setup */
static VALUE grpc_rb_cChannelArgs;
+typedef struct bg_watched_channel {
+ grpc_channel *channel;
+ // these fields must only be accessed under global_connection_polling_mu
+ struct bg_watched_channel *next;
+ int channel_destroyed;
+ int refcount;
+} bg_watched_channel;
+
/* grpc_rb_channel wraps a grpc_channel. */
typedef struct grpc_rb_channel {
VALUE credentials;
- /* The actual channel */
- grpc_channel *wrapped;
- int request_safe_destroy;
- int safe_to_destroy;
- grpc_connectivity_state current_connectivity_state;
-
- int mu_init_done;
- int abort_watch_connectivity_state;
- gpr_mu channel_mu;
- gpr_cv channel_cv;
+ /* The actual channel (protected in a wrapper to tell when it's safe to
+ * destroy) */
+ bg_watched_channel *bg_wrapped;
} grpc_rb_channel;
-/* Forward declarations of functions involved in temporary fix to
- * https://github.com/grpc/grpc/issues/9941 */
+typedef enum { CONTINUOUS_WATCH, WATCH_STATE_API } watch_state_op_type;
+
+typedef struct watch_state_op {
+ watch_state_op_type op_type;
+ // from event.success
+ union {
+ struct {
+ int success;
+ // has been called back due to a cq next call
+ int called_back;
+ } api_callback_args;
+ struct {
+ bg_watched_channel *bg;
+ } continuous_watch_callback_args;
+ } op;
+} watch_state_op;
+
+static bg_watched_channel *bg_watched_channel_list_head = NULL;
+
static void grpc_rb_channel_try_register_connection_polling(
- grpc_rb_channel *wrapper);
-static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper);
-static void *wait_until_channel_polling_thread_started_no_gil(void*);
-static void wait_until_channel_polling_thread_started_unblocking_func(void*);
+ bg_watched_channel *bg);
+static void *wait_until_channel_polling_thread_started_no_gil(void *);
+static void wait_until_channel_polling_thread_started_unblocking_func(void *);
+static void *channel_init_try_register_connection_polling_without_gil(
+ void *arg);
+
+typedef struct channel_init_try_register_stack {
+ grpc_channel *channel;
+ grpc_rb_channel *wrapper;
+} channel_init_try_register_stack;
static grpc_completion_queue *channel_polling_cq;
static gpr_mu global_connection_polling_mu;
@@ -98,6 +122,42 @@
static int abort_channel_polling = 0;
static int channel_polling_thread_started = 0;
+static int bg_watched_channel_list_lookup(bg_watched_channel *bg);
+static bg_watched_channel *bg_watched_channel_list_create_and_add(
+ grpc_channel *channel);
+static void bg_watched_channel_list_free_and_remove(bg_watched_channel *bg);
+static void run_poll_channels_loop_unblocking_func(void *arg);
+
+// Needs to be called under global_connection_polling_mu
+static void grpc_rb_channel_watch_connection_state_op_complete(
+ watch_state_op *op, int success) {
+ GPR_ASSERT(!op->op.api_callback_args.called_back);
+ op->op.api_callback_args.called_back = 1;
+ op->op.api_callback_args.success = success;
+ // wake up the watch API call thats waiting on this op
+ gpr_cv_broadcast(&global_connection_polling_cv);
+}
+
+/* Avoids destroying a channel twice. */
+static void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) {
+ gpr_mu_lock(&global_connection_polling_mu);
+ GPR_ASSERT(bg_watched_channel_list_lookup(bg));
+ if (!bg->channel_destroyed) {
+ grpc_channel_destroy(bg->channel);
+ bg->channel_destroyed = 1;
+ }
+ bg->refcount--;
+ if (bg->refcount == 0) {
+ bg_watched_channel_list_free_and_remove(bg);
+ }
+ gpr_mu_unlock(&global_connection_polling_mu);
+}
+
+static void *channel_safe_destroy_without_gil(void *arg) {
+ grpc_rb_channel_safe_destroy((bg_watched_channel *)arg);
+ return NULL;
+}
+
/* Destroys Channel instances. */
static void grpc_rb_channel_free(void *p) {
grpc_rb_channel *ch = NULL;
@@ -106,14 +166,13 @@
};
ch = (grpc_rb_channel *)p;
- if (ch->wrapped != NULL) {
- grpc_rb_channel_safe_destroy(ch);
- ch->wrapped = NULL;
- }
-
- if (ch->mu_init_done) {
- gpr_mu_destroy(&ch->channel_mu);
- gpr_cv_destroy(&ch->channel_cv);
+ if (ch->bg_wrapped != NULL) {
+ /* assumption made here: it's ok to directly gpr_mu_lock the global
+ * connection polling mutex becuse we're in a finalizer,
+ * and we can count on this thread to not be interrupted or
+ * yield the gil. */
+ grpc_rb_channel_safe_destroy(ch->bg_wrapped);
+ ch->bg_wrapped = NULL;
}
xfree(p);
@@ -146,7 +205,7 @@
/* Allocates grpc_rb_channel instances. */
static VALUE grpc_rb_channel_alloc(VALUE cls) {
grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel);
- wrapper->wrapped = NULL;
+ wrapper->bg_wrapped = NULL;
wrapper->credentials = Qnil;
return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper);
}
@@ -168,17 +227,21 @@
grpc_channel_credentials *creds = NULL;
char *target_chars = NULL;
grpc_channel_args args;
+ channel_init_try_register_stack stack;
+ int stop_waiting_for_thread_start = 0;
MEMZERO(&args, grpc_channel_args, 1);
grpc_ruby_once_init();
- rb_thread_call_without_gvl(wait_until_channel_polling_thread_started_no_gil, NULL,
- wait_until_channel_polling_thread_started_unblocking_func, NULL);
+ rb_thread_call_without_gvl(
+ wait_until_channel_polling_thread_started_no_gil,
+ &stop_waiting_for_thread_start,
+ wait_until_channel_polling_thread_started_unblocking_func,
+ &stop_waiting_for_thread_start);
/* "3" == 3 mandatory args */
rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials);
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
- wrapper->mu_init_done = 0;
target_chars = StringValueCStr(target);
grpc_rb_hash_convert_to_channel_args(channel_args, &args);
if (TYPE(credentials) == T_SYMBOL) {
@@ -195,24 +258,11 @@
}
GPR_ASSERT(ch);
-
- wrapper->wrapped = ch;
-
- gpr_mu_init(&wrapper->channel_mu);
- gpr_cv_init(&wrapper->channel_cv);
- wrapper->mu_init_done = 1;
-
- gpr_mu_lock(&wrapper->channel_mu);
- wrapper->abort_watch_connectivity_state = 0;
- wrapper->current_connectivity_state = grpc_channel_check_connectivity_state(wrapper->wrapped, 0);
- wrapper->safe_to_destroy = 0;
- wrapper->request_safe_destroy = 0;
-
- gpr_cv_broadcast(&wrapper->channel_cv);
- gpr_mu_unlock(&wrapper->channel_mu);
-
-
- grpc_rb_channel_try_register_connection_polling(wrapper);
+ stack.channel = ch;
+ stack.wrapper = wrapper;
+ rb_thread_call_without_gvl(
+ channel_init_try_register_connection_polling_without_gil, &stack, NULL,
+ NULL);
if (args.args != NULL) {
xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
@@ -223,10 +273,31 @@
return Qnil;
}
rb_ivar_set(self, id_target, target);
- wrapper->wrapped = ch;
return self;
}
+typedef struct get_state_stack {
+ bg_watched_channel *bg;
+ int try_to_connect;
+ int out;
+} get_state_stack;
+
+static void *get_state_without_gil(void *arg) {
+ get_state_stack *stack = (get_state_stack *)arg;
+
+ gpr_mu_lock(&global_connection_polling_mu);
+ GPR_ASSERT(abort_channel_polling || channel_polling_thread_started);
+ if (stack->bg->channel_destroyed) {
+ stack->out = GRPC_CHANNEL_SHUTDOWN;
+ } else {
+ stack->out = grpc_channel_check_connectivity_state(stack->bg->channel,
+ stack->try_to_connect);
+ }
+ gpr_mu_unlock(&global_connection_polling_mu);
+
+ return NULL;
+}
+
/*
call-seq:
ch.connectivity_state -> state
@@ -239,59 +310,70 @@
static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv,
VALUE self) {
VALUE try_to_connect_param = Qfalse;
- int grpc_try_to_connect = 0;
grpc_rb_channel *wrapper = NULL;
- grpc_channel *ch = NULL;
+ get_state_stack stack;
/* "01" == 0 mandatory args, 1 (try_to_connect) is optional */
rb_scan_args(argc, argv, "01", &try_to_connect_param);
- grpc_try_to_connect = RTEST(try_to_connect_param) ? 1 : 0;
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
- ch = wrapper->wrapped;
- if (ch == NULL) {
+ if (wrapper->bg_wrapped == NULL) {
rb_raise(rb_eRuntimeError, "closed!");
return Qnil;
}
- return LONG2NUM(grpc_channel_check_connectivity_state(wrapper->wrapped, grpc_try_to_connect));
+
+ stack.bg = wrapper->bg_wrapped;
+ stack.try_to_connect = RTEST(try_to_connect_param) ? 1 : 0;
+ rb_thread_call_without_gvl(get_state_without_gil, &stack, NULL, NULL);
+
+ return LONG2NUM(stack.out);
}
typedef struct watch_state_stack {
- grpc_rb_channel *wrapper;
+ grpc_channel *channel;
gpr_timespec deadline;
int last_state;
} watch_state_stack;
-static void *watch_channel_state_without_gvl(void *arg) {
- watch_state_stack *stack = (watch_state_stack*)arg;
- gpr_timespec deadline = stack->deadline;
- grpc_rb_channel *wrapper = stack->wrapper;
- int last_state = stack->last_state;
- void *return_value = (void*)0;
+static void *wait_for_watch_state_op_complete_without_gvl(void *arg) {
+ watch_state_stack *stack = (watch_state_stack *)arg;
+ watch_state_op *op = NULL;
+ void *success = (void *)0;
- gpr_mu_lock(&wrapper->channel_mu);
- while(wrapper->current_connectivity_state == last_state &&
- !wrapper->request_safe_destroy &&
- !wrapper->safe_to_destroy &&
- !wrapper->abort_watch_connectivity_state &&
- gpr_time_cmp(deadline, gpr_now(GPR_CLOCK_REALTIME)) > 0) {
- gpr_cv_wait(&wrapper->channel_cv, &wrapper->channel_mu, deadline);
+ gpr_mu_lock(&global_connection_polling_mu);
+ // its unsafe to do a "watch" after "channel polling abort" because the cq has
+ // been shut down.
+ if (abort_channel_polling) {
+ gpr_mu_unlock(&global_connection_polling_mu);
+ return (void *)0;
}
- if (wrapper->current_connectivity_state != last_state) {
- return_value = (void*)1;
- }
- gpr_mu_unlock(&wrapper->channel_mu);
+ op = gpr_zalloc(sizeof(watch_state_op));
+ op->op_type = WATCH_STATE_API;
+ grpc_channel_watch_connectivity_state(stack->channel, stack->last_state,
+ stack->deadline, channel_polling_cq,
+ op);
- return return_value;
+ while (!op->op.api_callback_args.called_back) {
+ gpr_cv_wait(&global_connection_polling_cv, &global_connection_polling_mu,
+ gpr_inf_future(GPR_CLOCK_REALTIME));
+ }
+ if (op->op.api_callback_args.success) {
+ success = (void *)1;
+ }
+ gpr_free(op);
+ gpr_mu_unlock(&global_connection_polling_mu);
+
+ return success;
}
-static void watch_channel_state_unblocking_func(void *arg) {
- grpc_rb_channel *wrapper = (grpc_rb_channel*)arg;
- gpr_log(GPR_DEBUG, "GRPC_RUBY: watch channel state unblocking func called");
- gpr_mu_lock(&wrapper->channel_mu);
- wrapper->abort_watch_connectivity_state = 1;
- gpr_cv_broadcast(&wrapper->channel_cv);
- gpr_mu_unlock(&wrapper->channel_mu);
+static void wait_for_watch_state_op_complete_unblocking_func(void *arg) {
+ bg_watched_channel *bg = (bg_watched_channel *)arg;
+ gpr_mu_lock(&global_connection_polling_mu);
+ if (!bg->channel_destroyed) {
+ grpc_channel_destroy(bg->channel);
+ bg->channel_destroyed = 1;
+ }
+ gpr_mu_unlock(&global_connection_polling_mu);
}
/* Wait until the channel's connectivity state becomes different from
@@ -306,28 +388,31 @@
VALUE deadline) {
grpc_rb_channel *wrapper = NULL;
watch_state_stack stack;
- void* out;
+ void *op_success = 0;
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
- if (wrapper->wrapped == NULL) {
+ if (wrapper->bg_wrapped == NULL) {
rb_raise(rb_eRuntimeError, "closed!");
return Qnil;
}
if (!FIXNUM_P(last_state)) {
- rb_raise(rb_eTypeError, "bad type for last_state. want a GRPC::Core::ChannelState constant");
+ rb_raise(
+ rb_eTypeError,
+ "bad type for last_state. want a GRPC::Core::ChannelState constant");
return Qnil;
}
- stack.wrapper = wrapper;
- stack.deadline = grpc_rb_time_timeval(deadline, 0);
+ stack.channel = wrapper->bg_wrapped->channel;
+ stack.deadline = grpc_rb_time_timeval(deadline, 0),
stack.last_state = NUM2LONG(last_state);
- out = rb_thread_call_without_gvl(watch_channel_state_without_gvl, &stack, watch_channel_state_unblocking_func, wrapper);
- if (out) {
- return Qtrue;
- }
- return Qfalse;
+
+ op_success = rb_thread_call_without_gvl(
+ wait_for_watch_state_op_complete_without_gvl, &stack,
+ wait_for_watch_state_op_complete_unblocking_func, wrapper->bg_wrapped);
+
+ return op_success ? Qtrue : Qfalse;
}
/* Create a call given a grpc_channel, in order to call method. The request
@@ -339,7 +424,6 @@
grpc_rb_channel *wrapper = NULL;
grpc_call *call = NULL;
grpc_call *parent_call = NULL;
- grpc_channel *ch = NULL;
grpc_completion_queue *cq = NULL;
int flags = GRPC_PROPAGATE_DEFAULTS;
grpc_slice method_slice;
@@ -361,8 +445,7 @@
cq = grpc_completion_queue_create(NULL);
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
- ch = wrapper->wrapped;
- if (ch == NULL) {
+ if (wrapper->bg_wrapped == NULL) {
rb_raise(rb_eRuntimeError, "closed!");
return Qnil;
}
@@ -370,8 +453,8 @@
method_slice =
grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method));
- call = grpc_channel_create_call(ch, parent_call, flags, cq, method_slice,
- host_slice_ptr,
+ call = grpc_channel_create_call(wrapper->bg_wrapped->channel, parent_call,
+ flags, cq, method_slice, host_slice_ptr,
grpc_rb_time_timeval(deadline,
/* absolute time */ 0),
NULL);
@@ -396,15 +479,16 @@
}
/* Closes the channel, calling it's destroy method */
+/* Note this is an API-level call; a wrapped channel's finalizer doesn't call
+ * this */
static VALUE grpc_rb_channel_destroy(VALUE self) {
grpc_rb_channel *wrapper = NULL;
- grpc_channel *ch = NULL;
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
- ch = wrapper->wrapped;
- if (ch != NULL) {
- grpc_rb_channel_safe_destroy(wrapper);
- wrapper->wrapped = NULL;
+ if (wrapper->bg_wrapped != NULL) {
+ rb_thread_call_without_gvl(channel_safe_destroy_without_gil,
+ wrapper->bg_wrapped, NULL, NULL);
+ wrapper->bg_wrapped = NULL;
}
return Qnil;
@@ -417,64 +501,110 @@
char *target = NULL;
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
- target = grpc_channel_get_target(wrapper->wrapped);
+ target = grpc_channel_get_target(wrapper->bg_wrapped->channel);
res = rb_str_new2(target);
gpr_free(target);
return res;
}
-// Either start polling channel connection state or signal that it's free to
-// destroy.
-// Not safe to call while a channel's connection state is polled.
-static void grpc_rb_channel_try_register_connection_polling(
- grpc_rb_channel *wrapper) {
- grpc_connectivity_state conn_state;
- gpr_timespec sleep_time = gpr_time_add(
- gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(20, GPR_TIMESPAN));
+/* Needs to be called under global_connection_polling_mu */
+static int bg_watched_channel_list_lookup(bg_watched_channel *target) {
+ bg_watched_channel *cur = bg_watched_channel_list_head;
- GPR_ASSERT(wrapper);
- GPR_ASSERT(wrapper->wrapped);
- gpr_mu_lock(&wrapper->channel_mu);
- if (wrapper->request_safe_destroy) {
- wrapper->safe_to_destroy = 1;
- gpr_cv_broadcast(&wrapper->channel_cv);
- gpr_mu_unlock(&wrapper->channel_mu);
- return;
+ while (cur != NULL) {
+ if (cur == target) {
+ return 1;
+ }
+ cur = cur->next;
}
- gpr_mu_lock(&global_connection_polling_mu);
- GPR_ASSERT(channel_polling_thread_started || abort_channel_polling);
- conn_state = grpc_channel_check_connectivity_state(wrapper->wrapped, 0);
- if (conn_state != wrapper->current_connectivity_state) {
- wrapper->current_connectivity_state = conn_state;
- gpr_cv_broadcast(&wrapper->channel_cv);
- }
- // avoid posting work to the channel polling cq if it's been shutdown
- if (!abort_channel_polling && conn_state != GRPC_CHANNEL_SHUTDOWN) {
- grpc_channel_watch_connectivity_state(
- wrapper->wrapped, conn_state, sleep_time, channel_polling_cq, wrapper);
- } else {
- wrapper->safe_to_destroy = 1;
- gpr_cv_broadcast(&wrapper->channel_cv);
- }
- gpr_mu_unlock(&global_connection_polling_mu);
- gpr_mu_unlock(&wrapper->channel_mu);
+ return 0;
}
-// Note requires wrapper->wrapped, wrapper->channel_mu/cv initialized
-static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper) {
- gpr_mu_lock(&wrapper->channel_mu);
- wrapper->request_safe_destroy = 1;
+/* Needs to be called under global_connection_polling_mu */
+static bg_watched_channel *bg_watched_channel_list_create_and_add(
+ grpc_channel *channel) {
+ bg_watched_channel *watched = gpr_zalloc(sizeof(bg_watched_channel));
- while (!wrapper->safe_to_destroy) {
- gpr_cv_wait(&wrapper->channel_cv, &wrapper->channel_mu,
- gpr_inf_future(GPR_CLOCK_REALTIME));
+ watched->channel = channel;
+ watched->next = bg_watched_channel_list_head;
+ watched->refcount = 1;
+ bg_watched_channel_list_head = watched;
+ return watched;
+}
+
+/* Needs to be called under global_connection_polling_mu */
+static void bg_watched_channel_list_free_and_remove(
+ bg_watched_channel *target) {
+ bg_watched_channel *bg = NULL;
+
+ GPR_ASSERT(bg_watched_channel_list_lookup(target));
+ GPR_ASSERT(target->channel_destroyed && target->refcount == 0);
+ if (bg_watched_channel_list_head == target) {
+ bg_watched_channel_list_head = target->next;
+ gpr_free(target);
+ return;
}
- GPR_ASSERT(wrapper->safe_to_destroy);
- gpr_mu_unlock(&wrapper->channel_mu);
+ bg = bg_watched_channel_list_head;
+ while (bg != NULL && bg->next != NULL) {
+ if (bg->next == target) {
+ bg->next = bg->next->next;
+ gpr_free(target);
+ return;
+ }
+ bg = bg->next;
+ }
+ GPR_ASSERT(0);
+}
- grpc_channel_destroy(wrapper->wrapped);
+/* Initialize a grpc_rb_channel's "protected grpc_channel" and try to push
+ * it onto the background thread for constant watches. */
+static void *channel_init_try_register_connection_polling_without_gil(
+ void *arg) {
+ channel_init_try_register_stack *stack =
+ (channel_init_try_register_stack *)arg;
+
+ gpr_mu_lock(&global_connection_polling_mu);
+ stack->wrapper->bg_wrapped =
+ bg_watched_channel_list_create_and_add(stack->channel);
+ grpc_rb_channel_try_register_connection_polling(stack->wrapper->bg_wrapped);
+ gpr_mu_unlock(&global_connection_polling_mu);
+ return NULL;
+}
+
+// Needs to be called under global_connection_poolling_mu
+static void grpc_rb_channel_try_register_connection_polling(
+ bg_watched_channel *bg) {
+ grpc_connectivity_state conn_state;
+ watch_state_op *op = NULL;
+
+ GPR_ASSERT(channel_polling_thread_started || abort_channel_polling);
+
+ if (bg->refcount == 0) {
+ GPR_ASSERT(bg->channel_destroyed);
+ bg_watched_channel_list_free_and_remove(bg);
+ return;
+ }
+ GPR_ASSERT(bg->refcount == 1);
+ if (bg->channel_destroyed || abort_channel_polling) {
+ return;
+ }
+
+ conn_state = grpc_channel_check_connectivity_state(bg->channel, 0);
+ if (conn_state == GRPC_CHANNEL_SHUTDOWN) {
+ return;
+ }
+ GPR_ASSERT(bg_watched_channel_list_lookup(bg));
+ // prevent bg from being free'd by GC while background thread is watching it
+ bg->refcount++;
+
+ op = gpr_zalloc(sizeof(watch_state_op));
+ op->op_type = CONTINUOUS_WATCH;
+ op->op.continuous_watch_callback_args.bg = bg;
+ grpc_channel_watch_connectivity_state(bg->channel, conn_state,
+ gpr_inf_future(GPR_CLOCK_REALTIME),
+ channel_polling_cq, op);
}
// Note this loop breaks out with a single call of
@@ -485,6 +615,8 @@
// early and falls back to current behavior.
static void *run_poll_channels_loop_no_gil(void *arg) {
grpc_event event;
+ watch_state_op *op = NULL;
+ bg_watched_channel *bg = NULL;
(void)arg;
gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_no_gil - begin");
@@ -500,29 +632,70 @@
if (event.type == GRPC_QUEUE_SHUTDOWN) {
break;
}
+ gpr_mu_lock(&global_connection_polling_mu);
if (event.type == GRPC_OP_COMPLETE) {
- grpc_rb_channel_try_register_connection_polling((grpc_rb_channel *)event.tag);
+ op = (watch_state_op *)event.tag;
+ if (op->op_type == CONTINUOUS_WATCH) {
+ bg = (bg_watched_channel *)op->op.continuous_watch_callback_args.bg;
+ bg->refcount--;
+ grpc_rb_channel_try_register_connection_polling(bg);
+ gpr_free(op);
+ } else if (op->op_type == WATCH_STATE_API) {
+ grpc_rb_channel_watch_connection_state_op_complete(
+ (watch_state_op *)event.tag, event.success);
+ } else {
+ GPR_ASSERT(0);
+ }
}
+ gpr_mu_unlock(&global_connection_polling_mu);
}
grpc_completion_queue_destroy(channel_polling_cq);
- gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_no_gil - exit connection polling loop");
+ gpr_log(GPR_DEBUG,
+ "GRPC_RUBY: run_poll_channels_loop_no_gil - exit connection polling "
+ "loop");
return NULL;
}
// Notify the channel polling loop to cleanup and shutdown.
static void run_poll_channels_loop_unblocking_func(void *arg) {
+ bg_watched_channel *bg = NULL;
(void)arg;
+
gpr_mu_lock(&global_connection_polling_mu);
- gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting connection polling");
+ gpr_log(GPR_DEBUG,
+ "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting "
+ "connection polling");
+ // early out after first time through
+ if (abort_channel_polling) {
+ gpr_mu_unlock(&global_connection_polling_mu);
+ return;
+ }
abort_channel_polling = 1;
+
+ // force pending watches to end by switching to shutdown state
+ bg = bg_watched_channel_list_head;
+ while (bg != NULL) {
+ if (!bg->channel_destroyed) {
+ grpc_channel_destroy(bg->channel);
+ bg->channel_destroyed = 1;
+ }
+ bg = bg->next;
+ }
+
grpc_completion_queue_shutdown(channel_polling_cq);
+ gpr_cv_broadcast(&global_connection_polling_cv);
gpr_mu_unlock(&global_connection_polling_mu);
+ gpr_log(GPR_DEBUG,
+ "GRPC_RUBY: run_poll_channels_loop_unblocking_func - end aborting "
+ "connection polling");
}
// Poll channel connectivity states in background thread without the GIL.
static VALUE run_poll_channels_loop(VALUE arg) {
(void)arg;
- gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop - create connection polling thread");
+ gpr_log(
+ GPR_DEBUG,
+ "GRPC_RUBY: run_poll_channels_loop - create connection polling thread");
rb_thread_call_without_gvl(run_poll_channels_loop_no_gil, NULL,
run_poll_channels_loop_unblocking_func, NULL);
@@ -530,10 +703,11 @@
}
static void *wait_until_channel_polling_thread_started_no_gil(void *arg) {
- (void)arg;
+ int *stop_waiting = (int *)arg;
gpr_log(GPR_DEBUG, "GRPC_RUBY: wait for channel polling thread to start");
gpr_mu_lock(&global_connection_polling_mu);
- while (!channel_polling_thread_started && !abort_channel_polling) {
+ while (!channel_polling_thread_started && !abort_channel_polling &&
+ !*stop_waiting) {
gpr_cv_wait(&global_connection_polling_cv, &global_connection_polling_mu,
gpr_inf_future(GPR_CLOCK_REALTIME));
}
@@ -542,13 +716,24 @@
return NULL;
}
-static void wait_until_channel_polling_thread_started_unblocking_func(void* arg) {
+static void wait_until_channel_polling_thread_started_unblocking_func(
+ void *arg) {
+ int *stop_waiting = (int *)arg;
+ gpr_mu_lock(&global_connection_polling_mu);
+ gpr_log(GPR_DEBUG,
+ "GRPC_RUBY: interrupt wait for channel polling thread to start");
+ *stop_waiting = 1;
+ gpr_cv_broadcast(&global_connection_polling_cv);
+ gpr_mu_unlock(&global_connection_polling_mu);
+}
+
+static void *set_abort_channel_polling_without_gil(void *arg) {
(void)arg;
gpr_mu_lock(&global_connection_polling_mu);
- gpr_log(GPR_DEBUG, "GRPC_RUBY: wait_until_channel_polling_thread_started_unblocking_func - begin aborting connection polling");
abort_channel_polling = 1;
gpr_cv_broadcast(&global_connection_polling_cv);
gpr_mu_unlock(&global_connection_polling_mu);
+ return NULL;
}
/* Temporary fix for
@@ -576,10 +761,8 @@
if (!RTEST(background_thread)) {
gpr_log(GPR_DEBUG, "GRPC_RUBY: failed to spawn channel polling thread");
- gpr_mu_lock(&global_connection_polling_mu);
- abort_channel_polling = 1;
- gpr_cv_broadcast(&global_connection_polling_cv);
- gpr_mu_unlock(&global_connection_polling_mu);
+ rb_thread_call_without_gvl(set_abort_channel_polling_without_gil, NULL,
+ NULL, NULL);
}
}
@@ -658,5 +841,5 @@
grpc_channel *grpc_rb_get_wrapped_channel(VALUE v) {
grpc_rb_channel *wrapper = NULL;
TypedData_Get_Struct(v, grpc_rb_channel, &grpc_channel_data_type, wrapper);
- return wrapper->wrapped;
+ return wrapper->bg_wrapped->channel;
}
diff --git a/src/ruby/ext/grpc/rb_event_thread.c b/src/ruby/ext/grpc/rb_event_thread.c
index 9e85bbc..f1a08a7 100644
--- a/src/ruby/ext/grpc/rb_event_thread.c
+++ b/src/ruby/ext/grpc/rb_event_thread.c
@@ -106,17 +106,17 @@
grpc_rb_event *event = NULL;
(void)param;
gpr_mu_lock(&event_queue.mu);
- while ((event = grpc_rb_event_queue_dequeue()) == NULL) {
+ while (!event_queue.abort) {
+ if ((event = grpc_rb_event_queue_dequeue()) != NULL) {
+ gpr_mu_unlock(&event_queue.mu);
+ return event;
+ }
gpr_cv_wait(&event_queue.cv,
&event_queue.mu,
gpr_inf_future(GPR_CLOCK_REALTIME));
- if (event_queue.abort) {
- gpr_mu_unlock(&event_queue.mu);
- return NULL;
- }
}
gpr_mu_unlock(&event_queue.mu);
- return event;
+ return NULL;
}
static void grpc_rb_event_unblocking_func(void *arg) {
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 584b5db..e0be5d7 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -295,11 +295,12 @@
static void grpc_ruby_once_init_internal() {
grpc_init();
- grpc_rb_event_queue_thread_start();
- grpc_rb_channel_polling_thread_start();
atexit(grpc_rb_shutdown);
}
+static VALUE bg_thread_init_rb_mu = Qundef;
+static int bg_thread_init_done = 0;
+
void grpc_ruby_once_init() {
/* ruby_vm_at_exit doesn't seem to be working. It would crash once every
* blue moon, and some users are getting it repeatedly. See the discussions
@@ -312,6 +313,18 @@
* schedule our initialization and destruction only once.
*/
gpr_once_init(&g_once_init, grpc_ruby_once_init_internal);
+
+ // Avoid calling calling into ruby library (when creating threads here)
+ // in gpr_once_init. In general, it appears to be unsafe to call
+ // into the ruby library while holding a non-ruby mutex, because a gil yield
+ // could end up trying to lock onto that same mutex and deadlocking.
+ rb_mutex_lock(bg_thread_init_rb_mu);
+ if (!bg_thread_init_done) {
+ grpc_rb_event_queue_thread_start();
+ grpc_rb_channel_polling_thread_start();
+ bg_thread_init_done = 1;
+ }
+ rb_mutex_unlock(bg_thread_init_rb_mu);
}
void Init_grpc_c() {
@@ -320,6 +333,9 @@
return;
}
+ bg_thread_init_rb_mu = rb_mutex_new();
+ rb_global_variable(&bg_thread_init_rb_mu);
+
grpc_rb_mGRPC = rb_define_module("GRPC");
grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
grpc_rb_sNewServerRpc =
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 063f921..332907c 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -103,6 +103,7 @@
grpc_alarm_cancel_type grpc_alarm_cancel_import;
grpc_alarm_destroy_type grpc_alarm_destroy_import;
grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import;
+grpc_channel_num_external_connectivity_watchers_type grpc_channel_num_external_connectivity_watchers_import;
grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import;
grpc_channel_create_call_type grpc_channel_create_call_import;
grpc_channel_ping_type grpc_channel_ping_import;
@@ -400,6 +401,7 @@
grpc_alarm_cancel_import = (grpc_alarm_cancel_type) GetProcAddress(library, "grpc_alarm_cancel");
grpc_alarm_destroy_import = (grpc_alarm_destroy_type) GetProcAddress(library, "grpc_alarm_destroy");
grpc_channel_check_connectivity_state_import = (grpc_channel_check_connectivity_state_type) GetProcAddress(library, "grpc_channel_check_connectivity_state");
+ grpc_channel_num_external_connectivity_watchers_import = (grpc_channel_num_external_connectivity_watchers_type) GetProcAddress(library, "grpc_channel_num_external_connectivity_watchers");
grpc_channel_watch_connectivity_state_import = (grpc_channel_watch_connectivity_state_type) GetProcAddress(library, "grpc_channel_watch_connectivity_state");
grpc_channel_create_call_import = (grpc_channel_create_call_type) GetProcAddress(library, "grpc_channel_create_call");
grpc_channel_ping_import = (grpc_channel_ping_type) GetProcAddress(library, "grpc_channel_ping");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index f5dcd68..e6a3f6d 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -260,6 +260,9 @@
typedef grpc_connectivity_state(*grpc_channel_check_connectivity_state_type)(grpc_channel *channel, int try_to_connect);
extern grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import;
#define grpc_channel_check_connectivity_state grpc_channel_check_connectivity_state_import
+typedef int(*grpc_channel_num_external_connectivity_watchers_type)(grpc_channel *channel);
+extern grpc_channel_num_external_connectivity_watchers_type grpc_channel_num_external_connectivity_watchers_import;
+#define grpc_channel_num_external_connectivity_watchers grpc_channel_num_external_connectivity_watchers_import
typedef void(*grpc_channel_watch_connectivity_state_type)(grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag);
extern grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import;
#define grpc_channel_watch_connectivity_state grpc_channel_watch_connectivity_state_import
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index fa80468..2759531 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
# GRPC contains the General RPC module.
module GRPC
- VERSION = '1.3.0.pre1'
+ VERSION = '1.3.5'
end
diff --git a/src/ruby/spec/channel_connection_spec.rb b/src/ruby/spec/channel_connection_spec.rb
index 940d68b..c8a7856 100644
--- a/src/ruby/spec/channel_connection_spec.rb
+++ b/src/ruby/spec/channel_connection_spec.rb
@@ -28,6 +28,10 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc'
+require 'timeout'
+
+include Timeout
+include GRPC::Core
# A test message
class EchoMsg
@@ -62,7 +66,7 @@
EchoStub = EchoService.rpc_stub_class
def start_server(port = 0)
- @srv = GRPC::RpcServer.new
+ @srv = GRPC::RpcServer.new(pool_size: 1)
server_port = @srv.add_http2_port("localhost:#{port}", :this_port_is_insecure)
@srv.handle(EchoService)
@server_thd = Thread.new { @srv.run }
@@ -138,4 +142,32 @@
stop_server
end
+
+ it 'concurrent watches on the same channel' do
+ timeout(180) do
+ port = start_server
+ ch = GRPC::Core::Channel.new("localhost:#{port}", {},
+ :this_channel_is_insecure)
+ stop_server
+
+ thds = []
+ 50.times do
+ thds << Thread.new do
+ while ch.connectivity_state(true) != ConnectivityStates::READY
+ ch.watch_connectivity_state(
+ ConnectivityStates::READY, Time.now + 60)
+ break
+ end
+ end
+ end
+
+ sleep 0.01
+
+ start_server(port)
+
+ thds.each(&:join)
+
+ stop_server
+ end
+ end
end
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index fa19aee..f93c1f1 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -29,6 +29,6 @@
module GRPC
module Tools
- VERSION = '1.3.0.pre1'
+ VERSION = '1.3.5'
end
end
diff --git a/templates/binding.gyp.template b/templates/binding.gyp.template
index a2e8c58..933174a 100644
--- a/templates/binding.gyp.template
+++ b/templates/binding.gyp.template
@@ -41,15 +41,16 @@
{
'variables': {
'runtime%': 'node',
- # UV integration in C core is enabled by default. It can be disabled
- # by setting this argument to anything else.
- 'grpc_uv%': 'true',
# Some Node installations use the system installation of OpenSSL, and on
# some systems, the system OpenSSL still does not have ALPN support. This
# will let users recompile gRPC to work without ALPN.
'grpc_alpn%': 'true',
# Indicates that the library should be built with gcov.
- 'grpc_gcov%': 'false'
+ 'grpc_gcov%': 'false',
+ # Indicates that the library should be built with compatibility for musl
+ # libc, so that it can run on Alpine Linux. This is only necessary if not
+ # building on Alpine Linux
+ 'grpc_alpine%': 'false'
},
'target_defaults': {
'configurations': {
@@ -83,17 +84,11 @@
'include'
],
'defines': [
- 'GPR_BACKWARDS_COMPATIBILITY_MODE'
+ 'GPR_BACKWARDS_COMPATIBILITY_MODE',
+ 'GRPC_ARES=0',
+ 'GRPC_UV'
],
'conditions': [
- ['grpc_uv=="true"', {
- 'defines': [
- 'GRPC_ARES=0',
- # Disabling this while bugs are ironed out. Uncomment this to
- # re-enable libuv integration in C core.
- 'GRPC_UV'
- ]
- }],
['grpc_gcov=="true"', {
% for arg, prop in [('CPPFLAGS', 'cflags'), ('DEFINES', 'defines'), ('LDFLAGS', 'ldflags')]:
% if configs['gcov'].get(arg, None) is not None:
@@ -105,6 +100,11 @@
% endif
% endfor
}],
+ ['grpc_alpine=="true"', {
+ 'defines': [
+ 'GPR_MUSL_LIBC_COMPAT'
+ ]
+ }],
['OS!="win" and runtime=="electron"', {
"defines": [
'OPENSSL_NO_THREADS'
@@ -233,6 +233,10 @@
}
]
},
+ ]
+ }],
+ ['OS == "win"', {
+ 'targets': [
# Only want to compile zlib under Windows
% for module in node_modules:
% for lib in libs:
@@ -264,13 +268,6 @@
}]
],
'targets': [
- <%
- for lib in libs:
- if 'grpc' in lib.transitive_deps or lib.name == 'grpc':
- lib.deps.append('node_modules/cares/deps/cares/cares.gyp:cares')
- for module in node_modules:
- module.deps.append('node_modules/cares/deps/cares/cares.gyp:cares')
- %>
% for module in node_modules:
% for lib in libs:
% if lib.name in module.transitive_deps and lib.name not in ('boringssl', 'z'):
diff --git a/templates/config.m4.template b/templates/config.m4.template
index 13ff738..38d86e6 100644
--- a/templates/config.m4.template
+++ b/templates/config.m4.template
@@ -10,8 +10,6 @@
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/include)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc)
PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include)
- PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/cares)
- PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/cares/cares)
LIBS="-lpthread $LIBS"
@@ -23,10 +21,8 @@
case $host in
*darwin*)
- PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/cares/config_darwin)
;;
*)
- PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/cares/config_linux)
PHP_ADD_LIBRARY(rt,,GRPC_SHARED_LIBADD)
PHP_ADD_LIBRARY(rt)
;;
@@ -46,7 +42,7 @@
, $ext_shared, , -Wall -Werror ${"\\"}
-Wno-parentheses-equality -Wno-unused-value -std=c11 ${"\\"}
-fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN ${"\\"}
- -D_HAS_EXCEPTIONS=0 -DNOMINMAX)
+ -D_HAS_EXCEPTIONS=0 -DNOMINMAX -DGRPC_ARES=0)
PHP_ADD_BUILD_DIR($ext_builddir/src/php/ext/grpc)
<%
diff --git a/templates/package.json.template b/templates/package.json.template
index b69fd28..551c25f 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -36,8 +36,7 @@
"lodash": "^4.15.0",
"nan": "^2.0.0",
"node-pre-gyp": "^0.6.0",
- "protobufjs": "^6.7.0",
- "cares": "^1.1.5"
+ "protobufjs": "^5.0.0"
},
"devDependencies": {
"async": "^2.0.1",
diff --git a/templates/package.xml.template b/templates/package.xml.template
index 8655cfa..394b815 100644
--- a/templates/package.xml.template
+++ b/templates/package.xml.template
@@ -12,7 +12,7 @@
<email>grpc-packages@google.com</email>
<active>yes</active>
</lead>
- <date>2017-03-01</date>
+ <date>2017-05-05</date>
<time>16:06:07</time>
<version>
<release>${settings.php_version.php()}</release>
@@ -24,8 +24,7 @@
</stability>
<license>BSD</license>
<notes>
- - Added arg info macros #9751
- - Updated codegen to be consistent with protobuf #9492
+ - Fixed some memory leaks #9559, #10996
</notes>
<contents>
<dir baseinstalldir="/" name="/">
@@ -43,6 +42,7 @@
% endfor
% endif
% endfor
+ <file name="LICENSE" role="doc" />
</dir>
</contents>
<dependencies>
@@ -358,5 +358,21 @@
- Updated codegen to be consistent with protobuf #9492
</notes>
</release>
+ <release>
+ <version>
+ <release>1.2.0</release>
+ <api>1.2.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <date>2017-03-20</date>
+ <license>BSD</license>
+ <notes>
+ - Added arg info macros #9751
+ - Updated codegen to be consistent with protobuf #9492
+ </notes>
+ </release>
</changelog>
</package>
diff --git a/templates/src/csharp/build_packages_dotnetcli.bat.template b/templates/src/csharp/build_packages_dotnetcli.bat.template
index 91808e0..5f6ffb9 100755
--- a/templates/src/csharp/build_packages_dotnetcli.bat.template
+++ b/templates/src/csharp/build_packages_dotnetcli.bat.template
@@ -62,11 +62,11 @@
@rem To be able to build, we also need to put grpc_csharp_ext to its normal location
xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release${"\\"}
- %%DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error
- %%DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error
- %%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error
- %%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
- %%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error
+ %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core --output ..\..\..\artifacts || goto :error
+ %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ..\..\..\artifacts || goto :error
+ %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Auth --output ..\..\..\artifacts || goto :error
+ %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
+ %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ..\..\..\artifacts || goto :error
%%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
diff --git a/templates/src/csharp/build_packages_dotnetcli.sh.template b/templates/src/csharp/build_packages_dotnetcli.sh.template
index 374b236..d37f4eb 100755
--- a/templates/src/csharp/build_packages_dotnetcli.sh.template
+++ b/templates/src/csharp/build_packages_dotnetcli.sh.template
@@ -66,11 +66,11 @@
mkdir -p ../../libs/opt
cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt
- dotnet pack --configuration Release Grpc.Core --output ../../../artifacts
- dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts
- dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts
- dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
- dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
+ dotnet pack --configuration Release --include-symbols --include-source Grpc.Core --output ../../../artifacts
+ dotnet pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ../../../artifacts
+ dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth --output ../../../artifacts
+ dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts
+ dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts
nuget pack Grpc.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts
nuget pack Grpc.Tools.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts
diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c
index 2f7c3df..73f2cd3 100644
--- a/test/core/surface/concurrent_connectivity_test.c
+++ b/test/core/surface/concurrent_connectivity_test.c
@@ -61,6 +61,14 @@
#define DELAY_MILLIS 10
#define POLL_MILLIS 3000
+#define NUM_OUTER_LOOPS_SHORT_TIMEOUTS 10
+#define NUM_INNER_LOOPS_SHORT_TIMEOUTS 100
+#define DELAY_MILLIS_SHORT_TIMEOUTS 1
+// in a successful test run, POLL_MILLIS should never be reached beause all runs
+// should
+// end after the shorter delay_millis
+#define POLL_MILLIS_SHORT_TIMEOUTS 30000
+
static void *tag(int n) { return (void *)(uintptr_t)n; }
static int detag(void *p) { return (int)(uintptr_t)p; }
@@ -79,6 +87,8 @@
grpc_timeout_milliseconds_to_deadline(POLL_MILLIS);
GPR_ASSERT(grpc_completion_queue_next(cq, poll_time, NULL).type ==
GRPC_OP_COMPLETE);
+ /* check that the watcher from "watch state" was free'd */
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(chan) == 0);
}
grpc_channel_destroy(chan);
grpc_completion_queue_destroy(cq);
@@ -166,11 +176,10 @@
gpr_free(pollset);
}
-int main(int argc, char **argv) {
+int run_concurrent_connectivity_test() {
struct server_thread_args args;
memset(&args, 0, sizeof(args));
- grpc_test_init(argc, argv);
grpc_init();
gpr_thd_id threads[NUM_THREADS];
@@ -240,3 +249,59 @@
grpc_shutdown();
return 0;
}
+
+void watches_with_short_timeouts(void *addr) {
+ for (int i = 0; i < NUM_OUTER_LOOPS_SHORT_TIMEOUTS; ++i) {
+ grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+ grpc_channel *chan = grpc_insecure_channel_create((char *)addr, NULL, NULL);
+
+ for (int j = 0; j < NUM_INNER_LOOPS_SHORT_TIMEOUTS; ++j) {
+ gpr_timespec later_time =
+ grpc_timeout_milliseconds_to_deadline(DELAY_MILLIS_SHORT_TIMEOUTS);
+ grpc_connectivity_state state =
+ grpc_channel_check_connectivity_state(chan, 0);
+ GPR_ASSERT(state == GRPC_CHANNEL_IDLE);
+ grpc_channel_watch_connectivity_state(chan, state, later_time, cq, NULL);
+ gpr_timespec poll_time =
+ grpc_timeout_milliseconds_to_deadline(POLL_MILLIS_SHORT_TIMEOUTS);
+ grpc_event ev = grpc_completion_queue_next(cq, poll_time, NULL);
+ GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+ GPR_ASSERT(ev.success == false);
+ /* check that the watcher from "watch state" was free'd */
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(chan) == 0);
+ }
+ grpc_channel_destroy(chan);
+ grpc_completion_queue_destroy(cq);
+ }
+}
+
+// This test tries to catch deadlock situations.
+// With short timeouts on "watches" and long timeouts on cq next calls,
+// so that a QUEUE_TIMEOUT likely means that something is stuck.
+int run_concurrent_watches_with_short_timeouts_test() {
+ grpc_init();
+
+ gpr_thd_id threads[NUM_THREADS];
+
+ char *localhost = gpr_strdup("localhost:54321");
+ gpr_thd_options options = gpr_thd_options_default();
+ gpr_thd_options_set_joinable(&options);
+
+ for (size_t i = 0; i < NUM_THREADS; ++i) {
+ gpr_thd_new(&threads[i], watches_with_short_timeouts, localhost, &options);
+ }
+ for (size_t i = 0; i < NUM_THREADS; ++i) {
+ gpr_thd_join(threads[i]);
+ }
+ gpr_free(localhost);
+
+ grpc_shutdown();
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+
+ run_concurrent_connectivity_test();
+ run_concurrent_watches_with_short_timeouts_test();
+}
diff --git a/test/core/surface/num_external_connectivity_watchers_test.c b/test/core/surface/num_external_connectivity_watchers_test.c
new file mode 100644
index 0000000..96288ab
--- /dev/null
+++ b/test/core/surface/num_external_connectivity_watchers_test.c
@@ -0,0 +1,221 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "test/core/end2end/data/ssl_test_data.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+typedef struct test_fixture {
+ const char *name;
+ grpc_channel *(*create_channel)(const char *addr);
+} test_fixture;
+
+static size_t next_tag = 1;
+
+static void channel_idle_start_watch(grpc_channel *channel,
+ grpc_completion_queue *cq) {
+ gpr_timespec connect_deadline = grpc_timeout_milliseconds_to_deadline(1);
+ GPR_ASSERT(grpc_channel_check_connectivity_state(channel, 0) ==
+ GRPC_CHANNEL_IDLE);
+
+ grpc_channel_watch_connectivity_state(
+ channel, GRPC_CHANNEL_IDLE, connect_deadline, cq, (void *)(next_tag++));
+ gpr_log(GPR_DEBUG, "number of active connect watchers: %d",
+ grpc_channel_num_external_connectivity_watchers(channel));
+}
+
+static void channel_idle_poll_for_timeout(grpc_channel *channel,
+ grpc_completion_queue *cq) {
+ grpc_event ev =
+ grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+
+ /* expect watch_connectivity_state to end with a timeout */
+ GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+ GPR_ASSERT(ev.success == false);
+ GPR_ASSERT(grpc_channel_check_connectivity_state(channel, 0) ==
+ GRPC_CHANNEL_IDLE);
+}
+
+/* Test and use the "num_external_watchers" call to make sure
+ * that "connectivity watcher" structs are free'd just after, if
+ * their corresponding timeouts occur. */
+static void run_timeouts_test(const test_fixture *fixture) {
+ gpr_log(GPR_INFO, "TEST: %s", fixture->name);
+
+ char *addr;
+
+ grpc_init();
+
+ gpr_join_host_port(&addr, "localhost", grpc_pick_unused_port_or_die());
+
+ grpc_channel *channel = fixture->create_channel(addr);
+ grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
+
+ /* start 1 watcher and then let it time out */
+ channel_idle_start_watch(channel, cq);
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1);
+ channel_idle_poll_for_timeout(channel, cq);
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0);
+
+ /* start 3 watchers and then let them all time out */
+ for (size_t i = 1; i <= 3; i++) {
+ channel_idle_start_watch(channel, cq);
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) ==
+ (int)i);
+ }
+ for (size_t i = 1; i <= 3; i++) {
+ channel_idle_poll_for_timeout(channel, cq);
+ }
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0);
+
+ /* start 3 watchers, see one time out, start another 3, and then see them all
+ * time out */
+ for (size_t i = 1; i <= 3; i++) {
+ channel_idle_start_watch(channel, cq);
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) ==
+ (int)i);
+ }
+ channel_idle_poll_for_timeout(channel, cq);
+ for (size_t i = 3; i <= 5; i++) {
+ channel_idle_start_watch(channel, cq);
+ }
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) >= 3);
+ for (size_t i = 1; i <= 5; i++) {
+ channel_idle_poll_for_timeout(channel, cq);
+ }
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0);
+
+ grpc_channel_destroy(channel);
+ grpc_completion_queue_shutdown(cq);
+ GPR_ASSERT(
+ grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL)
+ .type == GRPC_QUEUE_SHUTDOWN);
+ grpc_completion_queue_destroy(cq);
+
+ grpc_shutdown();
+ gpr_free(addr);
+}
+
+/* An edge scenario; sets channel state to explicitly, and outside
+ * of a polling call. */
+static void run_channel_shutdown_before_timeout_test(
+ const test_fixture *fixture) {
+ gpr_log(GPR_INFO, "TEST: %s", fixture->name);
+
+ char *addr;
+
+ grpc_init();
+
+ gpr_join_host_port(&addr, "localhost", grpc_pick_unused_port_or_die());
+
+ grpc_channel *channel = fixture->create_channel(addr);
+ grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
+
+ /* start 1 watcher and then shut down the channel before the timer goes off */
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0);
+
+ /* expecting a 30 second timeout to go off much later than the shutdown. */
+ gpr_timespec connect_deadline = grpc_timeout_seconds_to_deadline(30);
+ GPR_ASSERT(grpc_channel_check_connectivity_state(channel, 0) ==
+ GRPC_CHANNEL_IDLE);
+
+ grpc_channel_watch_connectivity_state(channel, GRPC_CHANNEL_IDLE,
+ connect_deadline, cq, (void *)1);
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1);
+ grpc_channel_destroy(channel);
+
+ grpc_event ev =
+ grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+ GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+ /* expect success with a state transition to CHANNEL_SHUTDOWN */
+ GPR_ASSERT(ev.success == true);
+
+ grpc_completion_queue_shutdown(cq);
+ GPR_ASSERT(
+ grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL)
+ .type == GRPC_QUEUE_SHUTDOWN);
+ grpc_completion_queue_destroy(cq);
+
+ grpc_shutdown();
+ gpr_free(addr);
+}
+
+static grpc_channel *insecure_test_create_channel(const char *addr) {
+ return grpc_insecure_channel_create(addr, NULL, NULL);
+}
+
+static const test_fixture insecure_test = {
+ "insecure", insecure_test_create_channel,
+};
+
+static grpc_channel *secure_test_create_channel(const char *addr) {
+ grpc_channel_credentials *ssl_creds =
+ grpc_ssl_credentials_create(test_root_cert, NULL, NULL);
+ grpc_arg ssl_name_override = {GRPC_ARG_STRING,
+ GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
+ {"foo.test.google.fr"}};
+ grpc_channel_args *new_client_args =
+ grpc_channel_args_copy_and_add(NULL, &ssl_name_override, 1);
+ grpc_channel *channel =
+ grpc_secure_channel_create(ssl_creds, addr, new_client_args, NULL);
+ {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_channel_args_destroy(&exec_ctx, new_client_args);
+ grpc_exec_ctx_finish(&exec_ctx);
+ }
+ grpc_channel_credentials_release(ssl_creds);
+ return channel;
+}
+
+static const test_fixture secure_test = {
+ "secure", secure_test_create_channel,
+};
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+
+ run_timeouts_test(&insecure_test);
+ run_timeouts_test(&secure_test);
+
+ run_channel_shutdown_before_timeout_test(&insecure_test);
+ run_channel_shutdown_before_timeout_test(&secure_test);
+}
diff --git a/test/core/surface/sequential_connectivity_test.c b/test/core/surface/sequential_connectivity_test.c
index 5f66f90..8a6dd69 100644
--- a/test/core/surface/sequential_connectivity_test.c
+++ b/test/core/surface/sequential_connectivity_test.c
@@ -99,6 +99,9 @@
connect_deadline, cq, NULL);
grpc_event ev = grpc_completion_queue_next(
cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+ /* check that the watcher from "watch state" was free'd */
+ GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channels[i]) ==
+ 0);
GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
GPR_ASSERT(ev.tag == NULL);
GPR_ASSERT(ev.success == true);
diff --git a/third_party/cares/ares_build.h b/third_party/cares/ares_build.h
index 7d69f1e..d6b3d49 100644
--- a/third_party/cares/ares_build.h
+++ b/third_party/cares/ares_build.h
@@ -251,4 +251,14 @@
typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t;
#endif
+/* Undefine UNICODE, as c-ares does not use the ANSI version of functions */
+/* explicitly. */
+#ifdef UNICODE
+# undef UNICODE
+#endif
+
+#ifdef _UNICODE
+# undef _UNICODE
+#endif
+
#endif /* __CARES_BUILD_H */
diff --git a/third_party/protobuf b/third_party/protobuf
index 4a0dd03..593e917 160000
--- a/third_party/protobuf
+++ b/third_party/protobuf
@@ -1 +1 @@
-Subproject commit 4a0dd03e52e09332c8fd0f8f26a8e0ae9f911182
+Subproject commit 593e917c176b5bc5aafa57bf9f6030d749d91cd5
diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
index 289c0b1..7178681 100644
--- a/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
-VERSION='1.3.0rc1'
+VERSION='1.3.5'
diff --git a/tools/distrib/python/grpcio_tools/protoc_lib_deps.py b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
index 7e8cd98..c2aa619 100644
--- a/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
+++ b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
@@ -29,7 +29,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# AUTO-GENERATED BY make_grpcio_tools.py!
-CC_FILES=['google/protobuf/compiler/zip_writer.cc', 'google/protobuf/compiler/subprocess.cc', 'google/protobuf/compiler/ruby/ruby_generator.cc', 'google/protobuf/compiler/python/python_generator.cc', 'google/protobuf/compiler/plugin.pb.cc', 'google/protobuf/compiler/plugin.cc', 'google/protobuf/compiler/php/php_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_primitive_field.cc', 'google/protobuf/compiler/objectivec/objectivec_oneof.cc', 'google/protobuf/compiler/objectivec/objectivec_message_field.cc', 'google/protobuf/compiler/objectivec/objectivec_message.cc', 'google/protobuf/compiler/objectivec/objectivec_map_field.cc', 'google/protobuf/compiler/objectivec/objectivec_helpers.cc', 'google/protobuf/compiler/objectivec/objectivec_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_file.cc', 'google/protobuf/compiler/objectivec/objectivec_field.cc', 'google/protobuf/compiler/objectivec/objectivec_extension.cc', 'google/protobuf/compiler/objectivec/objectivec_enum_field.cc', 'google/protobuf/compiler/objectivec/objectivec_enum.cc', 'google/protobuf/compiler/js/well_known_types_embed.cc', 'google/protobuf/compiler/js/js_generator.cc', 'google/protobuf/compiler/javanano/javanano_primitive_field.cc', 'google/protobuf/compiler/javanano/javanano_message_field.cc', 'google/protobuf/compiler/javanano/javanano_message.cc', 'google/protobuf/compiler/javanano/javanano_map_field.cc', 'google/protobuf/compiler/javanano/javanano_helpers.cc', 'google/protobuf/compiler/javanano/javanano_generator.cc', 'google/protobuf/compiler/javanano/javanano_file.cc', 'google/protobuf/compiler/javanano/javanano_field.cc', 'google/protobuf/compiler/javanano/javanano_extension.cc', 'google/protobuf/compiler/javanano/javanano_enum_field.cc', 'google/protobuf/compiler/javanano/javanano_enum.cc', 'google/protobuf/compiler/java/java_string_field_lite.cc', 'google/protobuf/compiler/java/java_string_field.cc', 'google/protobuf/compiler/java/java_shared_code_generator.cc', 'google/protobuf/compiler/java/java_service.cc', 'google/protobuf/compiler/java/java_primitive_field_lite.cc', 'google/protobuf/compiler/java/java_primitive_field.cc', 'google/protobuf/compiler/java/java_name_resolver.cc', 'google/protobuf/compiler/java/java_message_lite.cc', 'google/protobuf/compiler/java/java_message_field_lite.cc', 'google/protobuf/compiler/java/java_message_field.cc', 'google/protobuf/compiler/java/java_message_builder_lite.cc', 'google/protobuf/compiler/java/java_message_builder.cc', 'google/protobuf/compiler/java/java_message.cc', 'google/protobuf/compiler/java/java_map_field_lite.cc', 'google/protobuf/compiler/java/java_map_field.cc', 'google/protobuf/compiler/java/java_lazy_message_field_lite.cc', 'google/protobuf/compiler/java/java_lazy_message_field.cc', 'google/protobuf/compiler/java/java_helpers.cc', 'google/protobuf/compiler/java/java_generator_factory.cc', 'google/protobuf/compiler/java/java_generator.cc', 'google/protobuf/compiler/java/java_file.cc', 'google/protobuf/compiler/java/java_field.cc', 'google/protobuf/compiler/java/java_extension_lite.cc', 'google/protobuf/compiler/java/java_extension.cc', 'google/protobuf/compiler/java/java_enum_lite.cc', 'google/protobuf/compiler/java/java_enum_field_lite.cc', 'google/protobuf/compiler/java/java_enum_field.cc', 'google/protobuf/compiler/java/java_enum.cc', 'google/protobuf/compiler/java/java_doc_comment.cc', 'google/protobuf/compiler/java/java_context.cc', 'google/protobuf/compiler/csharp/csharp_wrapper_field.cc', 'google/protobuf/compiler/csharp/csharp_source_generator_base.cc', 'google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_message_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_reflection_class.cc', 'google/protobuf/compiler/csharp/csharp_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_message_field.cc', 'google/protobuf/compiler/csharp/csharp_message.cc', 'google/protobuf/compiler/csharp/csharp_map_field.cc', 'google/protobuf/compiler/csharp/csharp_helpers.cc', 'google/protobuf/compiler/csharp/csharp_generator.cc', 'google/protobuf/compiler/csharp/csharp_field_base.cc', 'google/protobuf/compiler/csharp/csharp_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_enum.cc', 'google/protobuf/compiler/csharp/csharp_doc_comment.cc', 'google/protobuf/compiler/cpp/cpp_string_field.cc', 'google/protobuf/compiler/cpp/cpp_service.cc', 'google/protobuf/compiler/cpp/cpp_primitive_field.cc', 'google/protobuf/compiler/cpp/cpp_message_field.cc', 'google/protobuf/compiler/cpp/cpp_message.cc', 'google/protobuf/compiler/cpp/cpp_map_field.cc', 'google/protobuf/compiler/cpp/cpp_helpers.cc', 'google/protobuf/compiler/cpp/cpp_generator.cc', 'google/protobuf/compiler/cpp/cpp_file.cc', 'google/protobuf/compiler/cpp/cpp_field.cc', 'google/protobuf/compiler/cpp/cpp_extension.cc', 'google/protobuf/compiler/cpp/cpp_enum_field.cc', 'google/protobuf/compiler/cpp/cpp_enum.cc', 'google/protobuf/compiler/command_line_interface.cc', 'google/protobuf/compiler/code_generator.cc', 'google/protobuf/wrappers.pb.cc', 'google/protobuf/wire_format.cc', 'google/protobuf/util/type_resolver_util.cc', 'google/protobuf/util/time_util.cc', 'google/protobuf/util/message_differencer.cc', 'google/protobuf/util/json_util.cc', 'google/protobuf/util/internal/utility.cc', 'google/protobuf/util/internal/type_info_test_helper.cc', 'google/protobuf/util/internal/type_info.cc', 'google/protobuf/util/internal/protostream_objectwriter.cc', 'google/protobuf/util/internal/protostream_objectsource.cc', 'google/protobuf/util/internal/proto_writer.cc', 'google/protobuf/util/internal/object_writer.cc', 'google/protobuf/util/internal/json_stream_parser.cc', 'google/protobuf/util/internal/json_objectwriter.cc', 'google/protobuf/util/internal/json_escaping.cc', 'google/protobuf/util/internal/field_mask_utility.cc', 'google/protobuf/util/internal/error_listener.cc', 'google/protobuf/util/internal/default_value_objectwriter.cc', 'google/protobuf/util/internal/datapiece.cc', 'google/protobuf/util/field_mask_util.cc', 'google/protobuf/util/field_comparator.cc', 'google/protobuf/util/delimited_message_util.cc', 'google/protobuf/unknown_field_set.cc', 'google/protobuf/type.pb.cc', 'google/protobuf/timestamp.pb.cc', 'google/protobuf/text_format.cc', 'google/protobuf/stubs/substitute.cc', 'google/protobuf/stubs/mathlimits.cc', 'google/protobuf/struct.pb.cc', 'google/protobuf/source_context.pb.cc', 'google/protobuf/service.cc', 'google/protobuf/reflection_ops.cc', 'google/protobuf/message.cc', 'google/protobuf/map_field.cc', 'google/protobuf/io/zero_copy_stream_impl.cc', 'google/protobuf/io/tokenizer.cc', 'google/protobuf/io/strtod.cc', 'google/protobuf/io/printer.cc', 'google/protobuf/io/gzip_stream.cc', 'google/protobuf/generated_message_reflection.cc', 'google/protobuf/field_mask.pb.cc', 'google/protobuf/extension_set_heavy.cc', 'google/protobuf/empty.pb.cc', 'google/protobuf/dynamic_message.cc', 'google/protobuf/duration.pb.cc', 'google/protobuf/descriptor_database.cc', 'google/protobuf/descriptor.pb.cc', 'google/protobuf/descriptor.cc', 'google/protobuf/compiler/parser.cc', 'google/protobuf/compiler/importer.cc', 'google/protobuf/api.pb.cc', 'google/protobuf/any.pb.cc', 'google/protobuf/any.cc', 'google/protobuf/wire_format_lite.cc', 'google/protobuf/stubs/time.cc', 'google/protobuf/stubs/strutil.cc', 'google/protobuf/stubs/structurally_valid.cc', 'google/protobuf/stubs/stringprintf.cc', 'google/protobuf/stubs/stringpiece.cc', 'google/protobuf/stubs/statusor.cc', 'google/protobuf/stubs/status.cc', 'google/protobuf/stubs/once.cc', 'google/protobuf/stubs/int128.cc', 'google/protobuf/stubs/common.cc', 'google/protobuf/stubs/bytestream.cc', 'google/protobuf/stubs/atomicops_internals_x86_msvc.cc', 'google/protobuf/stubs/atomicops_internals_x86_gcc.cc', 'google/protobuf/repeated_field.cc', 'google/protobuf/message_lite.cc', 'google/protobuf/io/zero_copy_stream_impl_lite.cc', 'google/protobuf/io/zero_copy_stream.cc', 'google/protobuf/io/coded_stream.cc', 'google/protobuf/generated_message_util.cc', 'google/protobuf/extension_set.cc', 'google/protobuf/arenastring.cc', 'google/protobuf/arena.cc', 'google/protobuf/compiler/js/embed.cc']
+CC_FILES=['google/protobuf/compiler/zip_writer.cc', 'google/protobuf/compiler/subprocess.cc', 'google/protobuf/compiler/ruby/ruby_generator.cc', 'google/protobuf/compiler/python/python_generator.cc', 'google/protobuf/compiler/plugin.pb.cc', 'google/protobuf/compiler/plugin.cc', 'google/protobuf/compiler/php/php_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_primitive_field.cc', 'google/protobuf/compiler/objectivec/objectivec_oneof.cc', 'google/protobuf/compiler/objectivec/objectivec_message_field.cc', 'google/protobuf/compiler/objectivec/objectivec_message.cc', 'google/protobuf/compiler/objectivec/objectivec_map_field.cc', 'google/protobuf/compiler/objectivec/objectivec_helpers.cc', 'google/protobuf/compiler/objectivec/objectivec_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_file.cc', 'google/protobuf/compiler/objectivec/objectivec_field.cc', 'google/protobuf/compiler/objectivec/objectivec_extension.cc', 'google/protobuf/compiler/objectivec/objectivec_enum_field.cc', 'google/protobuf/compiler/objectivec/objectivec_enum.cc', 'google/protobuf/compiler/js/well_known_types_embed.cc', 'google/protobuf/compiler/js/js_generator.cc', 'google/protobuf/compiler/javanano/javanano_primitive_field.cc', 'google/protobuf/compiler/javanano/javanano_message_field.cc', 'google/protobuf/compiler/javanano/javanano_message.cc', 'google/protobuf/compiler/javanano/javanano_map_field.cc', 'google/protobuf/compiler/javanano/javanano_helpers.cc', 'google/protobuf/compiler/javanano/javanano_generator.cc', 'google/protobuf/compiler/javanano/javanano_file.cc', 'google/protobuf/compiler/javanano/javanano_field.cc', 'google/protobuf/compiler/javanano/javanano_extension.cc', 'google/protobuf/compiler/javanano/javanano_enum_field.cc', 'google/protobuf/compiler/javanano/javanano_enum.cc', 'google/protobuf/compiler/java/java_string_field_lite.cc', 'google/protobuf/compiler/java/java_string_field.cc', 'google/protobuf/compiler/java/java_shared_code_generator.cc', 'google/protobuf/compiler/java/java_service.cc', 'google/protobuf/compiler/java/java_primitive_field_lite.cc', 'google/protobuf/compiler/java/java_primitive_field.cc', 'google/protobuf/compiler/java/java_name_resolver.cc', 'google/protobuf/compiler/java/java_message_lite.cc', 'google/protobuf/compiler/java/java_message_field_lite.cc', 'google/protobuf/compiler/java/java_message_field.cc', 'google/protobuf/compiler/java/java_message_builder_lite.cc', 'google/protobuf/compiler/java/java_message_builder.cc', 'google/protobuf/compiler/java/java_message.cc', 'google/protobuf/compiler/java/java_map_field_lite.cc', 'google/protobuf/compiler/java/java_map_field.cc', 'google/protobuf/compiler/java/java_lazy_message_field_lite.cc', 'google/protobuf/compiler/java/java_lazy_message_field.cc', 'google/protobuf/compiler/java/java_helpers.cc', 'google/protobuf/compiler/java/java_generator_factory.cc', 'google/protobuf/compiler/java/java_generator.cc', 'google/protobuf/compiler/java/java_file.cc', 'google/protobuf/compiler/java/java_field.cc', 'google/protobuf/compiler/java/java_extension_lite.cc', 'google/protobuf/compiler/java/java_extension.cc', 'google/protobuf/compiler/java/java_enum_lite.cc', 'google/protobuf/compiler/java/java_enum_field_lite.cc', 'google/protobuf/compiler/java/java_enum_field.cc', 'google/protobuf/compiler/java/java_enum.cc', 'google/protobuf/compiler/java/java_doc_comment.cc', 'google/protobuf/compiler/java/java_context.cc', 'google/protobuf/compiler/csharp/csharp_wrapper_field.cc', 'google/protobuf/compiler/csharp/csharp_source_generator_base.cc', 'google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_message_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_reflection_class.cc', 'google/protobuf/compiler/csharp/csharp_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_message_field.cc', 'google/protobuf/compiler/csharp/csharp_message.cc', 'google/protobuf/compiler/csharp/csharp_map_field.cc', 'google/protobuf/compiler/csharp/csharp_helpers.cc', 'google/protobuf/compiler/csharp/csharp_generator.cc', 'google/protobuf/compiler/csharp/csharp_field_base.cc', 'google/protobuf/compiler/csharp/csharp_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_enum.cc', 'google/protobuf/compiler/csharp/csharp_doc_comment.cc', 'google/protobuf/compiler/cpp/cpp_string_field.cc', 'google/protobuf/compiler/cpp/cpp_service.cc', 'google/protobuf/compiler/cpp/cpp_primitive_field.cc', 'google/protobuf/compiler/cpp/cpp_message_field.cc', 'google/protobuf/compiler/cpp/cpp_message.cc', 'google/protobuf/compiler/cpp/cpp_map_field.cc', 'google/protobuf/compiler/cpp/cpp_helpers.cc', 'google/protobuf/compiler/cpp/cpp_generator.cc', 'google/protobuf/compiler/cpp/cpp_file.cc', 'google/protobuf/compiler/cpp/cpp_field.cc', 'google/protobuf/compiler/cpp/cpp_extension.cc', 'google/protobuf/compiler/cpp/cpp_enum_field.cc', 'google/protobuf/compiler/cpp/cpp_enum.cc', 'google/protobuf/compiler/command_line_interface.cc', 'google/protobuf/compiler/code_generator.cc', 'google/protobuf/wrappers.pb.cc', 'google/protobuf/wire_format.cc', 'google/protobuf/util/type_resolver_util.cc', 'google/protobuf/util/time_util.cc', 'google/protobuf/util/message_differencer.cc', 'google/protobuf/util/json_util.cc', 'google/protobuf/util/internal/utility.cc', 'google/protobuf/util/internal/type_info_test_helper.cc', 'google/protobuf/util/internal/type_info.cc', 'google/protobuf/util/internal/protostream_objectwriter.cc', 'google/protobuf/util/internal/protostream_objectsource.cc', 'google/protobuf/util/internal/proto_writer.cc', 'google/protobuf/util/internal/object_writer.cc', 'google/protobuf/util/internal/json_stream_parser.cc', 'google/protobuf/util/internal/json_objectwriter.cc', 'google/protobuf/util/internal/json_escaping.cc', 'google/protobuf/util/internal/field_mask_utility.cc', 'google/protobuf/util/internal/error_listener.cc', 'google/protobuf/util/internal/default_value_objectwriter.cc', 'google/protobuf/util/internal/datapiece.cc', 'google/protobuf/util/field_mask_util.cc', 'google/protobuf/util/field_comparator.cc', 'google/protobuf/unknown_field_set.cc', 'google/protobuf/type.pb.cc', 'google/protobuf/timestamp.pb.cc', 'google/protobuf/text_format.cc', 'google/protobuf/stubs/substitute.cc', 'google/protobuf/stubs/mathlimits.cc', 'google/protobuf/struct.pb.cc', 'google/protobuf/source_context.pb.cc', 'google/protobuf/service.cc', 'google/protobuf/reflection_ops.cc', 'google/protobuf/message.cc', 'google/protobuf/map_field.cc', 'google/protobuf/io/zero_copy_stream_impl.cc', 'google/protobuf/io/tokenizer.cc', 'google/protobuf/io/strtod.cc', 'google/protobuf/io/printer.cc', 'google/protobuf/io/gzip_stream.cc', 'google/protobuf/generated_message_reflection.cc', 'google/protobuf/field_mask.pb.cc', 'google/protobuf/extension_set_heavy.cc', 'google/protobuf/empty.pb.cc', 'google/protobuf/dynamic_message.cc', 'google/protobuf/duration.pb.cc', 'google/protobuf/descriptor_database.cc', 'google/protobuf/descriptor.pb.cc', 'google/protobuf/descriptor.cc', 'google/protobuf/compiler/parser.cc', 'google/protobuf/compiler/importer.cc', 'google/protobuf/api.pb.cc', 'google/protobuf/any.pb.cc', 'google/protobuf/any.cc', 'google/protobuf/wire_format_lite.cc', 'google/protobuf/stubs/time.cc', 'google/protobuf/stubs/strutil.cc', 'google/protobuf/stubs/structurally_valid.cc', 'google/protobuf/stubs/stringprintf.cc', 'google/protobuf/stubs/stringpiece.cc', 'google/protobuf/stubs/statusor.cc', 'google/protobuf/stubs/status.cc', 'google/protobuf/stubs/once.cc', 'google/protobuf/stubs/int128.cc', 'google/protobuf/stubs/common.cc', 'google/protobuf/stubs/bytestream.cc', 'google/protobuf/stubs/atomicops_internals_x86_msvc.cc', 'google/protobuf/stubs/atomicops_internals_x86_gcc.cc', 'google/protobuf/repeated_field.cc', 'google/protobuf/message_lite.cc', 'google/protobuf/io/zero_copy_stream_impl_lite.cc', 'google/protobuf/io/zero_copy_stream.cc', 'google/protobuf/io/coded_stream.cc', 'google/protobuf/generated_message_util.cc', 'google/protobuf/extension_set.cc', 'google/protobuf/arenastring.cc', 'google/protobuf/arena.cc', 'google/protobuf/compiler/js/embed.cc']
PROTO_FILES=['google/protobuf/wrappers.proto', 'google/protobuf/type.proto', 'google/protobuf/timestamp.proto', 'google/protobuf/struct.proto', 'google/protobuf/source_context.proto', 'google/protobuf/field_mask.proto', 'google/protobuf/empty.proto', 'google/protobuf/duration.proto', 'google/protobuf/descriptor.proto', 'google/protobuf/compiler/plugin.proto', 'google/protobuf/api.proto', 'google/protobuf/any.proto']
CC_INCLUDE='third_party/protobuf/src'
diff --git a/tools/dockerfile/grpc_artifact_linux_armv6/Dockerfile b/tools/dockerfile/grpc_artifact_linux_armv6/Dockerfile
new file mode 100644
index 0000000..b085dd0
--- /dev/null
+++ b/tools/dockerfile/grpc_artifact_linux_armv6/Dockerfile
@@ -0,0 +1,39 @@
+# Copyright 2017, 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.
+
+# Docker file for building gRPC Raspbian binaries
+
+FROM quay.io/grpc/raspbian_armv6
+
+# Place any extra build instructions between these commands
+# Recommend modifying upstream docker image (quay.io/grpc/raspbian_armv6)
+# for build steps because running them under QEMU is very slow
+# (https://github.com/kpayson64/armv7hf-debian-qemu)
+# RUN [ "cross-build-start" ]
+# RUN [ "cross-build-end" ]
diff --git a/tools/dockerfile/grpc_artifact_linux_armv7/Dockerfile b/tools/dockerfile/grpc_artifact_linux_armv7/Dockerfile
new file mode 100644
index 0000000..d7759a6
--- /dev/null
+++ b/tools/dockerfile/grpc_artifact_linux_armv7/Dockerfile
@@ -0,0 +1,39 @@
+# Copyright 2017, 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.
+
+# Docker file for building gRPC Raspbian binaries
+
+FROM quay.io/grpc/raspbian_armv7
+
+# Place any extra build instructions between these commands
+# Recommend modifying upstream docker image (quay.io/grpc/raspbian_armv7)
+# for build steps because running them under QEMU is very slow
+# (https://github.com/kpayson64/armv7hf-debian-qemu)
+# RUN [ "cross-build-start" ]
+# RUN [ "cross-build-end" ]
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 01a2dfb..55980ea 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.3.0-pre1
+PROJECT_NUMBER = 1.3.5
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 7734d8b..7580617 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.3.0-pre1
+PROJECT_NUMBER = 1.3.5
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index d651c92..a4eacfb 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 3.0.0-pre1
+PROJECT_NUMBER = 3.0.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index f5ffe97..d623fc0 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 3.0.0-pre1
+PROJECT_NUMBER = 3.0.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/tools/grpcz/BUILD b/tools/grpcz/BUILD
index 5e1faf7..cac7df2 100644
--- a/tools/grpcz/BUILD
+++ b/tools/grpcz/BUILD
@@ -58,6 +58,5 @@
deps = [
"//external:gflags",
"monitoring_proto",
- "@mongoose_repo//:mongoose_lib",
],
)
diff --git a/tools/grpcz/grpcz_client.cc b/tools/grpcz/grpcz_client.cc
index 47eec8d..a5e66f7 100644
--- a/tools/grpcz/grpcz_client.cc
+++ b/tools/grpcz/grpcz_client.cc
@@ -38,7 +38,7 @@
#include <grpc/support/log.h>
#include "gflags/gflags.h"
-#include "mongoose.h"
+/* #include "mongoose.h" */
// TODO (makdharma): remove local copies of these protos
#include "tools/grpcz/census.grpc.pb.h"
@@ -122,8 +122,9 @@
std::unique_ptr<Monitoring::Stub> stub_;
};
-static struct mg_serve_http_opts s_http_server_opts;
std::unique_ptr<GrpczClient> g_grpcz_client;
+/*
+static struct mg_serve_http_opts s_http_server_opts;
static void ev_handler(struct mg_connection *nc, int ev, void *p) {
if (ev == MG_EV_HTTP_REQUEST) {
@@ -141,6 +142,7 @@
mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n%s", rendered_html.c_str());
nc->flags |= MG_F_SEND_AND_CLOSE;
}
+*/
int main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
@@ -156,6 +158,7 @@
return 0;
}
+ /*
// Set up a mongoose webserver handler
struct mg_mgr mgr;
mg_mgr_init(&mgr, NULL);
@@ -177,5 +180,6 @@
mg_mgr_poll(&mgr, k_sleep_millis);
}
mg_mgr_free(&mgr);
+ */
return 0;
}
diff --git a/tools/jenkins/run_c_cpp_test.sh b/tools/jenkins/run_c_cpp_test.sh
new file mode 100755
index 0000000..afa2e78
--- /dev/null
+++ b/tools/jenkins/run_c_cpp_test.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+# Copyright 2017, 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.
+#
+# This script is invoked by a Jenkins pull request job and executes all
+# args passed to this script if the pull request affect C/C++ code
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../..
+
+AFFECTS_C_CPP=`python -c 'import os; \
+ import sys; \
+ sys.path.insert(0, "tools/run_tests/python_utils"); \
+ import filter_pull_request_tests as filter; \
+ github_target_branch = os.environ.get("ghprbTargetBranch"); \
+ print(filter.affects_c_cpp("origin/%s" % github_target_branch))'`
+
+if [ $AFFECTS_C_CPP == "False" ] ; then
+ echo "This pull request does not affect C/C++. Tests do not need to be run."
+else
+ $@
+fi
diff --git a/tools/run_tests/artifacts/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py
index 04702ba..d64c484 100644
--- a/tools/run_tests/artifacts/artifact_targets.py
+++ b/tools/run_tests/artifacts/artifact_targets.py
@@ -41,7 +41,7 @@
def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
flake_retries=0, timeout_retries=0, timeout_seconds=30*60,
- docker_base_image=None):
+ docker_base_image=None, extra_docker_args=None):
"""Creates jobspec for a task running under docker."""
environ = environ.copy()
environ['RUN_COMMAND'] = shell_command
@@ -55,6 +55,8 @@
if docker_base_image is not None:
docker_env['DOCKER_BASE_IMAGE'] = docker_base_image
+ if extra_docker_args is not None:
+ docker_env['EXTRA_DOCKER_ARGS'] = extra_docker_args
jobspec = jobset.JobSpec(
cmdline=['tools/run_tests/dockerize/build_and_run_docker.sh'] + docker_args,
environ=docker_env,
@@ -102,7 +104,22 @@
def build_jobspec(self):
environ = {}
- if self.platform == 'linux':
+ if self.platform == 'linux_extra':
+ # Raspberry Pi build
+ environ['PYTHON'] = '/usr/local/bin/python{}'.format(self.py_version)
+ environ['PIP'] = '/usr/local/bin/pip{}'.format(self.py_version)
+ # https://github.com/resin-io-projects/armv7hf-debian-qemu/issues/9
+ # A QEMU bug causes submodule update to hang, so we copy directly
+ environ['RELATIVE_COPY_PATH'] = '.'
+ extra_args = ' --entrypoint=/usr/bin/qemu-arm-static '
+ return create_docker_jobspec(self.name,
+ 'tools/dockerfile/grpc_artifact_linux_{}'.format(self.arch),
+ 'tools/run_tests/artifacts/build_artifact_python.sh',
+ environ=environ,
+ timeout_seconds=60*60*5,
+ docker_base_image='quay.io/grpc/raspbian_{}'.format(self.arch),
+ extra_docker_args=extra_args)
+ elif self.platform == 'linux':
if self.arch == 'x86':
environ['SETARCH_CMD'] = 'linux32'
# Inside the manylinux container, the python installations are located in
@@ -332,6 +349,14 @@
PythonArtifact('linux', 'x86', 'cp34-cp34m'),
PythonArtifact('linux', 'x86', 'cp35-cp35m'),
PythonArtifact('linux', 'x86', 'cp36-cp36m'),
+ PythonArtifact('linux_extra', 'armv7', '2.7'),
+ PythonArtifact('linux_extra', 'armv7', '3.4'),
+ PythonArtifact('linux_extra', 'armv7', '3.5'),
+ PythonArtifact('linux_extra', 'armv7', '3.6'),
+ PythonArtifact('linux_extra', 'armv6', '2.7'),
+ PythonArtifact('linux_extra', 'armv6', '3.4'),
+ PythonArtifact('linux_extra', 'armv6', '3.5'),
+ PythonArtifact('linux_extra', 'armv6', '3.6'),
PythonArtifact('linux', 'x64', 'cp27-cp27m'),
PythonArtifact('linux', 'x64', 'cp27-cp27mu'),
PythonArtifact('linux', 'x64', 'cp34-cp34m'),
diff --git a/tools/run_tests/artifacts/build_artifact_node.sh b/tools/run_tests/artifacts/build_artifact_node.sh
index 2da2ac5..7a74755 100755
--- a/tools/run_tests/artifacts/build_artifact_node.sh
+++ b/tools/run_tests/artifacts/build_artifact_node.sh
@@ -48,7 +48,7 @@
for version in ${node_versions[@]}
do
- ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=$NODE_TARGET_ARCH
+ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=$NODE_TARGET_ARCH --grpc_alpine=true
cp -r build/stage/* artifacts/
done
diff --git a/tools/run_tests/dockerize/build_and_run_docker.sh b/tools/run_tests/dockerize/build_and_run_docker.sh
index 8c25c86..6189e9a 100755
--- a/tools/run_tests/dockerize/build_and_run_docker.sh
+++ b/tools/run_tests/dockerize/build_and_run_docker.sh
@@ -74,8 +74,9 @@
-v "$git_root:/var/local/jenkins/grpc:ro" \
-w /var/local/git/grpc \
--name=$CONTAINER_NAME \
+ $EXTRA_DOCKER_ARGS \
$DOCKER_IMAGE_NAME \
- bash -l "/var/local/jenkins/grpc/$DOCKER_RUN_SCRIPT" || FAILED="true"
+ /bin/bash -l "/var/local/jenkins/grpc/$DOCKER_RUN_SCRIPT" || FAILED="true"
# Copy output artifacts
if [ "$OUTPUT_DIR" != "" ]
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index f5653d6..5afeed3 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -1699,6 +1699,23 @@
"headers": [],
"is_filegroup": false,
"language": "c",
+ "name": "num_external_connectivity_watchers_test",
+ "src": [
+ "test/core/surface/num_external_connectivity_watchers_test.c"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc_test_util"
+ ],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c",
"name": "parse_address_test",
"src": [
"test/core/client_channel/parse_address_test.c"
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index a08caf3..7e35099 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -1773,6 +1773,30 @@
],
"cpu_cost": 1.0,
"exclude_configs": [],
+ "exclude_iomgrs": [
+ "uv"
+ ],
+ "flaky": false,
+ "gtest": false,
+ "language": "c",
+ "name": "num_external_connectivity_watchers_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ]
+ },
+ {
+ "args": [],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": false,
diff --git a/tools/run_tests/helper_scripts/build_node.sh b/tools/run_tests/helper_scripts/build_node.sh
index 2c4cf02..07ecf98 100755
--- a/tools/run_tests/helper_scripts/build_node.sh
+++ b/tools/run_tests/helper_scripts/build_node.sh
@@ -46,6 +46,4 @@
*) config_flag='--release' ;;
esac
-uv_flag=$2
-
-npm install --unsafe-perm --build-from-source $uv_flag $config_flag
+npm install --unsafe-perm --build-from-source $config_flag
diff --git a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
index 6688025..ab882d62 100755
--- a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
+++ b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
@@ -41,4 +41,5 @@
ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1
ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1
ruby src/ruby/end2end/grpc_class_init_driver.rb || EXIT_CODE=1
+ruby src/ruby/end2end/multiple_killed_watching_threads_driver.rb || EXIT_CODE=1
exit $EXIT_CODE
diff --git a/tools/run_tests/performance/build_performance.sh b/tools/run_tests/performance/build_performance.sh
index 3f7c9fe..5f8749d 100755
--- a/tools/run_tests/performance/build_performance.sh
+++ b/tools/run_tests/performance/build_performance.sh
@@ -61,9 +61,6 @@
"csharp")
python tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8 --compiler coreclr
;;
- "node")
- python tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8 --iomgr_platform=uv
- ;;
*)
python tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8
;;
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index 200da5e..ce080882 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -513,7 +513,22 @@
'node_protobuf_unary_ping_pong_1MB', rpc_type='UNARY',
client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
req_size=1024*1024, resp_size=1024*1024,
- categories=[SCALABLE, SMOKETEST])
+ categories=[SCALABLE])
+
+ sizes = [('1B', 1), ('1KB', 1024), ('10KB', 10 * 1024),
+ ('1MB', 1024 * 1024), ('10MB', 10 * 1024 * 1024),
+ ('100MB', 100 * 1024 * 1024)]
+
+ for size_name, size in sizes:
+ for secure in (True, False):
+ yield _ping_pong_scenario(
+ 'node_protobuf_unary_ping_pong_%s_resp_%s' %
+ (size_name, 'secure' if secure else 'insecure'),
+ rpc_type='UNARY',
+ client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
+ req_size=0, resp_size=size,
+ secure=secure,
+ categories=[SCALABLE])
# TODO(murgatroid99): fix bugs with this scenario and re-enable it
# yield _ping_pong_scenario(
@@ -528,11 +543,10 @@
# client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
# unconstrained_client='async')
- # TODO(jtattermusch): make this scenario work
- #yield _ping_pong_scenario(
- # 'node_to_cpp_protobuf_async_unary_ping_pong', rpc_type='UNARY',
- # client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
- # server_language='c++', async_server_threads=1)
+ yield _ping_pong_scenario(
+ 'node_to_cpp_protobuf_async_unary_ping_pong', rpc_type='UNARY',
+ client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
+ server_language='c++', async_server_threads=1)
# TODO(jtattermusch): make this scenario work
#yield _ping_pong_scenario(
@@ -829,6 +843,21 @@
unconstrained_client='async',
categories=[SCALABLE, SMOKETEST])
+ sizes = [('1B', 1), ('1KB', 1024), ('10KB', 10 * 1024),
+ ('1MB', 1024 * 1024), ('10MB', 10 * 1024 * 1024),
+ ('100MB', 100 * 1024 * 1024)]
+
+ for size_name, size in sizes:
+ for secure in (True, False):
+ yield _ping_pong_scenario(
+ 'node_express_json_unary_ping_pong_%s_resp_%s' %
+ (size_name, 'secure' if secure else 'insecure'),
+ rpc_type='UNARY',
+ client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
+ req_size=0, resp_size=size,
+ secure=secure,
+ categories=[SCALABLE])
+
def __str__(self):
return 'node_express'
diff --git a/tools/run_tests/python_utils/filter_pull_request_tests.py b/tools/run_tests/python_utils/filter_pull_request_tests.py
index e013376..958eb56 100644
--- a/tools/run_tests/python_utils/filter_pull_request_tests.py
+++ b/tools/run_tests/python_utils/filter_pull_request_tests.py
@@ -127,6 +127,9 @@
'setup\.py$': [_PYTHON_TEST_SUITE]
}
+# Regex that combines all keys in _WHITELIST_DICT
+_ALL_TRIGGERS = "(" + ")|(".join(_WHITELIST_DICT.keys()) + ")"
+
# Add all triggers to their respective test suites
for trigger, test_suites in six.iteritems(_WHITELIST_DICT):
for test_suite in test_suites:
@@ -169,6 +172,21 @@
test.labels[2] not in skippable_labels]
+def affects_c_cpp(base_branch):
+ """
+ Determines if a pull request's changes affect C/C++. This function exists because
+ there are pull request tests that only test C/C++ code
+ :param base_branch: branch that a pull request is requesting to merge into
+ :return: boolean indicating whether C/C++ changes are made in pull request
+ """
+ changed_files = _get_changed_files(base_branch)
+ # Run all tests if any changed file is not in the whitelist dictionary
+ for changed_file in changed_files:
+ if not re.match(_ALL_TRIGGERS, changed_file):
+ return True
+ return not _can_skip_tests(changed_files, _CPP_TEST_SUITE.triggers + _CORE_TEST_SUITE.triggers)
+
+
def filter_tests(tests, base_branch):
"""
Filters out tests that are safe to ignore
@@ -181,11 +199,9 @@
print(' %s' % changed_file)
print('')
- # Regex that combines all keys in _WHITELIST_DICT
- all_triggers = "(" + ")|(".join(_WHITELIST_DICT.keys()) + ")"
- # Check if all tests have to be run
+ # Run all tests if any changed file is not in the whitelist dictionary
for changed_file in changed_files:
- if not re.match(all_triggers, changed_file):
+ if not re.match(_ALL_TRIGGERS, changed_file):
return(tests)
# Figure out which language and platform tests to run
skippable_labels = []
@@ -196,4 +212,3 @@
skippable_labels.append(label)
tests = _remove_irrelevant_tests(tests, skippable_labels)
return tests
-
diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py
index 5d812f2..460f359 100755
--- a/tools/run_tests/python_utils/jobset.py
+++ b/tools/run_tests/python_utils/jobset.py
@@ -348,7 +348,7 @@
"""Manages one run of jobs."""
def __init__(self, check_cancelled, maxjobs, newline_on_success, travis,
- stop_on_failure, add_env, quiet_success):
+ stop_on_failure, add_env, quiet_success, max_time):
self._running = set()
self._check_cancelled = check_cancelled
self._cancelled = False
@@ -360,6 +360,7 @@
self._stop_on_failure = stop_on_failure
self._add_env = add_env
self._quiet_success = quiet_success
+ self._max_time = max_time
self.resultset = {}
self._remaining = None
self._start_time = time.time()
@@ -379,6 +380,12 @@
def start(self, spec):
"""Start a job. Return True on success, False on failure."""
while True:
+ if self._max_time > 0 and time.time() - self._start_time > self._max_time:
+ skipped_job_result = JobResult()
+ skipped_job_result.state = 'SKIPPED'
+ message('SKIPPED', spec.shortname, do_newline=True)
+ self.resultset[spec.shortname] = [skipped_job_result]
+ return True
if self.cancelled(): return False
current_cpu_cost = self.cpu_cost()
if current_cpu_cost == 0: break
@@ -474,7 +481,8 @@
stop_on_failure=False,
add_env={},
skip_jobs=False,
- quiet_success=False):
+ quiet_success=False,
+ max_time=-1):
if skip_jobs:
resultset = {}
skipped_job_result = JobResult()
@@ -486,7 +494,7 @@
js = Jobset(check_cancelled,
maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS,
newline_on_success, travis, stop_on_failure, add_env,
- quiet_success)
+ quiet_success, max_time)
for cmdline, remaining in tag_remaining(cmdlines):
if not js.start(cmdline):
break
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 9130bc9..b556328 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -430,10 +430,6 @@
_check_compiler(self.args.compiler, ['default', 'node0.12',
'node4', 'node5', 'node6',
'node7', 'electron1.3', 'electron1.6'])
- if args.iomgr_platform == "uv":
- self.use_uv = True
- else:
- self.use_uv = False
if self.args.compiler == 'default':
self.runtime = 'node'
self.node_version = '7'
@@ -481,7 +477,6 @@
else:
config_flag = '--release'
return [['tools\\run_tests\\helper_scripts\\build_node.bat',
- '--grpc_uv={}'.format('true' if self.use_uv else 'false'),
config_flag]]
else:
build_script = 'build_node'
@@ -490,8 +485,7 @@
# building for electron requires a patch version
self.node_version += '.0'
return [['tools/run_tests/helper_scripts/{}.sh'.format(build_script),
- self.node_version,
- '--grpc_uv={}'.format('true' if self.use_uv else 'false')]]
+ self.node_version]]
def post_tests_steps(self):
return []
@@ -1210,6 +1204,7 @@
'Useful when running many iterations of each test (argument -n).')
argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
help='Dont try to iterate over many polling strategies when they exist')
+argp.add_argument('--max_time', default=-1, type=int, help='Maximum test runtime in seconds')
args = argp.parse_args()
if args.force_default_poller:
@@ -1465,7 +1460,7 @@
not re.search(args.regex_exclude, spec.shortname))))
# When running on travis, we want out test runs to be as similar as possible
# for reproducibility purposes.
- if args.travis:
+ if args.travis and args.max_time <= 0:
massaged_one_run = sorted(one_run, key=lambda x: x.shortname)
else:
# whereas otherwise, we want to shuffle things up to give all tests a
@@ -1493,7 +1488,7 @@
all_runs, check_cancelled, newline_on_success=newline_on_success,
travis=args.travis, maxjobs=args.jobs,
stop_on_failure=args.stop_on_failure,
- quiet_success=args.quiet_success)
+ quiet_success=args.quiet_success, max_time=args.max_time)
if resultset:
for k, v in sorted(resultset.items()):
num_runs, num_failures = _calculate_num_runs_failures(v)
diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py
index 8bc8236..a8e1774 100755
--- a/tools/run_tests/run_tests_matrix.py
+++ b/tools/run_tests/run_tests_matrix.py
@@ -198,7 +198,7 @@
extra_args=extra_args,
inner_jobs=inner_jobs)
- for compiler in ['gcc4.8', 'gcc5.3', 'gcc_musl',
+ for compiler in ['gcc4.8', 'gcc5.3',
'clang3.5', 'clang3.6', 'clang3.7']:
test_jobs += _generate_jobs(languages=['c++'],
configs=['dbg'],
@@ -257,15 +257,6 @@
extra_args=extra_args,
inner_jobs=inner_jobs)
- test_jobs += _generate_jobs(languages=['python'],
- configs=['dbg'],
- platforms=['linux'],
- arch='default',
- compiler='python_alpine',
- labels=['portability'],
- extra_args=extra_args,
- inner_jobs=inner_jobs)
-
test_jobs += _generate_jobs(languages=['csharp'],
configs=['dbg'],
platforms=['linux'],
@@ -288,15 +279,6 @@
platforms=['linux'],
arch='default',
compiler='electron1.6',
- iomgr_platform='uv',
- labels=['portability'],
- extra_args=extra_args,
- inner_jobs=inner_jobs)
-
- test_jobs += _generate_jobs(languages=['node'],
- configs=['dbg'],
- platforms=['linux'],
- iomgr_platform='uv',
labels=['portability'],
extra_args=extra_args,
inner_jobs=inner_jobs)
@@ -386,6 +368,9 @@
argp.add_argument('-n', '--runs_per_test', default=1, type=_runs_per_test_type,
help='How many times to run each tests. >1 runs implies ' +
'omitting passing test from the output & reports.')
+ argp.add_argument('--max_time', default=-1, type=int,
+ help='Maximum amount of time to run tests for' +
+ '(other tests will be skipped)')
args = argp.parse_args()
extra_args = []
@@ -397,6 +382,8 @@
extra_args.append('-n')
extra_args.append('%s' % args.runs_per_test)
extra_args.append('--quiet_success')
+ if args.max_time > 0:
+ extra_args.extend(('--max_time', '%d' % args.max_time))
all_jobs = _create_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs) + \
_create_portability_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs)
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index eaf5a05..c5a0dbb 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -46,7 +46,7 @@
886e7d75368e3f4fab3f4d0d3584e4abfc557755 third_party/boringssl-with-bazel (version_for_cocoapods_7.0-857-g886e7d7)
30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e third_party/gflags (v2.2.0)
ec44c6c1675c25b9827aacd08c02433cccde7780 third_party/googletest (release-1.8.0)
- 4a0dd03e52e09332c8fd0f8f26a8e0ae9f911182 third_party/protobuf (v3.1.0-alpha-1-548-g4a0dd03e)
+ 593e917c176b5bc5aafa57bf9f6030d749d91cd5 third_party/protobuf (v3.1.0-alpha-1-326-g593e917)
bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c third_party/thrift (bcad917)
50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
7691f773af79bf75a62d1863fd0f13ebf9dc51b1 third_party/cares/cares (1.12.0)
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index c8fcacf..9cb966d 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -1284,6 +1284,17 @@
{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "num_external_connectivity_watchers_test", "vcxproj\test\num_external_connectivity_watchers_test\num_external_connectivity_watchers_test.vcxproj", "{4E856E4A-7497-1B1A-1AED-D4C01E5D873A}"
+ ProjectSection(myProperties) = preProject
+ lib = "False"
+ EndProjectSection
+ ProjectSection(ProjectDependencies) = postProject
+ {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+ {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+ {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+ {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "parse_address_test", "vcxproj\test\parse_address_test\parse_address_test.vcxproj", "{EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}"
ProjectSection(myProperties) = preProject
lib = "False"
@@ -3577,6 +3588,22 @@
{A66AC548-E2B9-74CD-293C-43526EE51DCE}.Release-DLL|Win32.Build.0 = Release|Win32
{A66AC548-E2B9-74CD-293C-43526EE51DCE}.Release-DLL|x64.ActiveCfg = Release|x64
{A66AC548-E2B9-74CD-293C-43526EE51DCE}.Release-DLL|x64.Build.0 = Release|x64
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|x64.ActiveCfg = Debug|x64
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|Win32.ActiveCfg = Release|Win32
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|x64.ActiveCfg = Release|x64
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|Win32.Build.0 = Debug|Win32
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|x64.Build.0 = Debug|x64
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|Win32.Build.0 = Release|Win32
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|x64.Build.0 = Release|x64
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|Win32.Build.0 = Debug|Win32
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|x64.ActiveCfg = Debug|x64
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|x64.Build.0 = Debug|x64
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|Win32.ActiveCfg = Release|Win32
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|Win32.Build.0 = Release|Win32
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|x64.ActiveCfg = Release|x64
+ {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|x64.Build.0 = Release|x64
{EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}.Debug|Win32.ActiveCfg = Debug|Win32
{EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}.Debug|x64.ActiveCfg = Debug|x64
{EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj
new file mode 100644
index 0000000..2b373e8
--- /dev/null
+++ b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{4E856E4A-7497-1B1A-1AED-D4C01E5D873A}</ProjectGuid>
+ <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+ <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+ <PlatformToolset>v110</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+ <TargetName>num_external_connectivity_watchers_test</TargetName>
+ <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+ <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+ <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+ <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'">
+ <TargetName>num_external_connectivity_watchers_test</TargetName>
+ <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+ <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+ <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+ <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemGroup>
+ <ClCompile Include="$(SolutionDir)\..\test\core\surface\num_external_connectivity_watchers_test.c">
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+ <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+ <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+ <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+ <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+ </ImportGroup>
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+ </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters
new file mode 100644
index 0000000..92a4198
--- /dev/null
+++ b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="$(SolutionDir)\..\test\core\surface\num_external_connectivity_watchers_test.c">
+ <Filter>test\core\surface</Filter>
+ </ClCompile>
+ </ItemGroup>
+
+ <ItemGroup>
+ <Filter Include="test">
+ <UniqueIdentifier>{9557f01e-947a-775e-4540-bf9a1fd9b19a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="test\core">
+ <UniqueIdentifier>{2b3a6de2-5820-e21f-5b39-66012c94bfbb}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="test\core\surface">
+ <UniqueIdentifier>{e3f23659-fc16-a4cc-a9e2-c73b625c38f5}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project>
+