aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--BUILD7
-rw-r--r--CMakeLists.txt132
-rw-r--r--Makefile176
-rw-r--r--bazel/grpc_build_system.bzl2
-rw-r--r--build.yaml59
-rw-r--r--config.m42
-rw-r--r--config.w322
-rw-r--r--doc/interop-test-descriptions.md5
-rw-r--r--etc/roots.pem23
-rw-r--r--gRPC-C++.podspec6
-rw-r--r--gRPC-Core.podspec9
-rw-r--r--grpc.gemspec4
-rw-r--r--grpc.gyp8
-rw-r--r--include/grpc/grpc.h5
-rw-r--r--include/grpc/grpc_security.h4
-rw-r--r--include/grpc/impl/codegen/grpc_types.h15
-rw-r--r--include/grpc/impl/codegen/port_platform.h1
-rw-r--r--include/grpcpp/alarm.h27
-rw-r--r--include/grpcpp/channel.h11
-rw-r--r--include/grpcpp/generic/generic_stub.h23
-rw-r--r--include/grpcpp/impl/codegen/async_stream.h47
-rw-r--r--include/grpcpp/impl/codegen/call.h16
-rw-r--r--include/grpcpp/impl/codegen/callback_common.h164
-rw-r--r--include/grpcpp/impl/codegen/channel_interface.h14
-rw-r--r--include/grpcpp/impl/codegen/client_callback.h95
-rw-r--r--include/grpcpp/impl/codegen/client_context.h4
-rw-r--r--include/grpcpp/impl/codegen/completion_queue.h3
-rw-r--r--include/grpcpp/impl/codegen/completion_queue_tag.h23
-rw-r--r--include/grpcpp/support/client_callback.h24
-rw-r--r--package.xml4
-rw-r--r--src/compiler/cpp_generator.cc148
-rw-r--r--src/compiler/ruby_generator.cc12
-rw-r--r--src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc6
-rw-r--r--src/core/ext/filters/client_channel/parse_address.cc30
-rw-r--r--src/core/ext/filters/client_channel/parse_address.h3
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc99
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h12
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc5
-rw-r--r--src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc70
-rw-r--r--src/core/ext/filters/client_channel/subchannel_index.cc6
-rw-r--r--src/core/ext/filters/http/client/http_client_filter.cc19
-rw-r--r--src/core/ext/filters/http/server/http_server_filter.cc18
-rw-r--r--src/core/ext/filters/message_size/message_size_filter.cc26
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.cc17
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_mapping.cc39
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_mapping.h38
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.cc29
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.h9
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.cc133
-rw-r--r--src/core/lib/channel/channel_trace.h2
-rw-r--r--src/core/lib/iomgr/ev_epollsig_linux.cc1743
-rw-r--r--src/core/lib/iomgr/ev_epollsig_linux.h35
-rw-r--r--src/core/lib/iomgr/ev_posix.cc15
-rw-r--r--src/core/lib/iomgr/port.h7
-rw-r--r--src/core/lib/iomgr/socket_utils_common_posix.cc90
-rw-r--r--src/core/lib/iomgr/socket_utils_posix.h7
-rw-r--r--src/core/lib/iomgr/tcp_client_posix.cc3
-rw-r--r--src/core/lib/iomgr/tcp_server_utils_posix_common.cc3
-rw-r--r--src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc3
-rw-r--r--src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc3
-rw-r--r--src/core/lib/security/transport/server_auth_filter.cc40
-rw-r--r--src/core/lib/surface/call.cc17
-rw-r--r--src/core/lib/surface/completion_queue.cc38
-rw-r--r--src/core/lib/surface/completion_queue.h19
-rw-r--r--src/core/lib/surface/completion_queue_factory.cc6
-rw-r--r--src/core/lib/surface/server.cc42
-rw-r--r--src/core/lib/transport/metadata.cc18
-rw-r--r--src/core/lib/transport/metadata.h3
-rw-r--r--src/core/lib/transport/metadata_batch.cc4
-rw-r--r--src/core/lib/transport/metadata_batch.h2
-rw-r--r--src/core/lib/transport/static_metadata.cc27
-rw-r--r--src/core/lib/transport/static_metadata.h2
-rw-r--r--src/cpp/client/channel_cc.cc50
-rw-r--r--src/cpp/client/generic_stub.cc14
-rw-r--r--src/cpp/common/alarm.cc47
-rw-r--r--src/cpp/ext/filters/census/server_filter.cc2
-rw-r--r--src/cpp/server/server_cc.cc1
-rw-r--r--src/cpp/server/server_context.cc3
-rw-r--r--src/objective-c/BoringSSL-GRPC.podspec5
-rw-r--r--src/objective-c/tests/CronetUnitTests/CronetUnitTests.m2
-rw-r--r--src/php/tests/unit_tests/ChannelTest.php4
-rw-r--r--src/proto/grpc/testing/package_options.proto28
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi10
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py2
-rw-r--r--src/ruby/ext/grpc/rb_call.c1
-rw-r--r--src/ruby/ext/grpc/rb_channel.c3
-rw-r--r--src/ruby/ext/grpc/rb_grpc.c32
-rw-r--r--src/ruby/ext/grpc/rb_grpc.h2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h8
-rw-r--r--src/ruby/ext/grpc/rb_server.c2
-rw-r--r--src/ruby/lib/grpc/generic/rpc_desc.rb6
-rw-r--r--src/ruby/lib/grpc/generic/rpc_server.rb2
-rw-r--r--src/ruby/spec/channel_spec.rb44
-rw-r--r--src/ruby/spec/client_auth_spec.rb10
-rw-r--r--src/ruby/spec/generic/client_stub_spec.rb22
-rw-r--r--src/ruby/spec/generic/rpc_server_spec.rb6
-rw-r--r--src/ruby/spec/pb/codegen/package_option_spec.rb53
-rw-r--r--src/ruby/spec/support/services.rb50
-rw-r--r--templates/gRPC-Core.podspec.template3
-rw-r--r--templates/src/objective-c/BoringSSL-GRPC.podspec.template5
-rwxr-xr-xtest/core/end2end/generate_tests.bzl564
-rw-r--r--test/core/end2end/inproc_callback_test.cc31
-rw-r--r--test/core/iomgr/BUILD32
-rw-r--r--test/core/iomgr/ev_epollsig_linux_test.cc321
-rw-r--r--test/core/iomgr/pollset_set_test.cc447
-rw-r--r--test/core/iomgr/resolve_address_test.cc40
-rw-r--r--test/core/surface/completion_queue_test.cc25
-rw-r--r--test/core/transport/chttp2/hpack_encoder_test.cc2
-rw-r--r--test/core/transport/metadata_test.cc5
-rw-r--r--test/core/tsi/alts/fake_handshaker/BUILD5
-rw-r--r--test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc31
-rw-r--r--test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h29
-rw-r--r--test/core/tsi/alts/fake_handshaker/fake_handshaker_server_main.cc53
-rw-r--r--test/core/util/port_isolated_runtime_environment.cc4
-rw-r--r--test/cpp/codegen/compiler_test_golden50
-rw-r--r--test/cpp/common/alarm_test.cc106
-rw-r--r--test/cpp/end2end/BUILD19
-rw-r--r--test/cpp/end2end/async_end2end_test.cc2
-rw-r--r--test/cpp/end2end/client_callback_end2end_test.cc241
-rw-r--r--test/cpp/end2end/client_lb_end2end_test.cc41
-rw-r--r--test/cpp/interop/client.cc8
-rw-r--r--test/cpp/interop/interop_client.cc28
-rw-r--r--test/cpp/interop/interop_client.h2
-rw-r--r--test/cpp/microbenchmarks/bm_chttp2_hpack.cc74
-rw-r--r--test/cpp/microbenchmarks/fullstack_fixtures.h1
-rw-r--r--test/cpp/microbenchmarks/helpers.cc2
-rw-r--r--test/cpp/microbenchmarks/helpers.h1
-rw-r--r--test/cpp/naming/address_sorting_test.cc52
-rw-r--r--test/cpp/util/cli_credentials.cc37
-rwxr-xr-xtest/distrib/csharp/run_distrib_test.sh3
-rwxr-xr-xtools/codegen/core/gen_static_metadata.py279
-rw-r--r--tools/doxygen/Doxyfile.c++3
-rw-r--r--tools/doxygen/Doxyfile.c++.internal4
-rw-r--r--tools/doxygen/Doxyfile.core.internal4
-rw-r--r--tools/interop_matrix/client_matrix.py15
-rw-r--r--tools/run_tests/generated/sources_and_headers.json58
-rw-r--r--tools/run_tests/generated/tests.json76
-rw-r--r--tools/run_tests/python_utils/upload_rbe_results.py17
-rwxr-xr-xtools/run_tests/run_tests.py4
-rwxr-xr-xtools/run_tests/run_tests_matrix.py15
141 files changed, 3325 insertions, 3587 deletions
diff --git a/AUTHORS b/AUTHORS
index e491a9e7f7..3e130afda2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1 +1,2 @@
Google Inc.
+WeWork Companies Inc.
diff --git a/BUILD b/BUILD
index 925e277cf7..6348c4e6ff 100644
--- a/BUILD
+++ b/BUILD
@@ -243,6 +243,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
+ "include/grpcpp/support/client_callback.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
@@ -706,7 +707,6 @@ grpc_cc_library(
"src/core/lib/iomgr/error.cc",
"src/core/lib/iomgr/ev_epoll1_linux.cc",
"src/core/lib/iomgr/ev_epollex_linux.cc",
- "src/core/lib/iomgr/ev_epollsig_linux.cc",
"src/core/lib/iomgr/ev_poll_posix.cc",
"src/core/lib/iomgr/ev_posix.cc",
"src/core/lib/iomgr/ev_windows.cc",
@@ -858,7 +858,6 @@ grpc_cc_library(
"src/core/lib/iomgr/error_internal.h",
"src/core/lib/iomgr/ev_epoll1_linux.h",
"src/core/lib/iomgr/ev_epollex_linux.h",
- "src/core/lib/iomgr/ev_epollsig_linux.h",
"src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h",
"src/core/lib/iomgr/exec_ctx.h",
@@ -1573,6 +1572,7 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/frame_window_update.cc",
"src/core/ext/transport/chttp2/transport/hpack_encoder.cc",
"src/core/ext/transport/chttp2/transport/hpack_parser.cc",
+ "src/core/ext/transport/chttp2/transport/hpack_mapping.cc",
"src/core/ext/transport/chttp2/transport/hpack_table.cc",
"src/core/ext/transport/chttp2/transport/http2_settings.cc",
"src/core/ext/transport/chttp2/transport/huffsyms.cc",
@@ -1597,6 +1597,7 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/frame_window_update.h",
"src/core/ext/transport/chttp2/transport/hpack_encoder.h",
"src/core/ext/transport/chttp2/transport/hpack_parser.h",
+ "src/core/ext/transport/chttp2/transport/hpack_mapping.h",
"src/core/ext/transport/chttp2/transport/hpack_table.h",
"src/core/ext/transport/chttp2/transport/http2_settings.h",
"src/core/ext/transport/chttp2/transport/huffsyms.h",
@@ -1979,7 +1980,9 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
+ "include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
+ "include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_context.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a21bb8b5fa..51788be108 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -253,9 +253,6 @@ add_dependencies(buildtests_c error_test)
if(_gRPC_PLATFORM_LINUX)
add_dependencies(buildtests_c ev_epollex_linux_test)
endif()
-if(_gRPC_PLATFORM_LINUX)
-add_dependencies(buildtests_c ev_epollsig_linux_test)
-endif()
add_dependencies(buildtests_c fake_resolver_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c fake_transport_security_test)
@@ -355,13 +352,11 @@ 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)
-add_dependencies(buildtests_c pollset_set_test)
-endif()
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c resolve_address_posix_test)
endif()
-add_dependencies(buildtests_c resolve_address_test)
+add_dependencies(buildtests_c resolve_address_using_ares_resolver_test)
+add_dependencies(buildtests_c resolve_address_using_native_resolver_test)
add_dependencies(buildtests_c resource_quota_test)
add_dependencies(buildtests_c secure_channel_create_test)
add_dependencies(buildtests_c secure_endpoint_test)
@@ -564,6 +559,7 @@ add_dependencies(buildtests_cxx check_gcp_environment_linux_test)
add_dependencies(buildtests_cxx check_gcp_environment_windows_test)
add_dependencies(buildtests_cxx chttp2_settings_timeout_test)
add_dependencies(buildtests_cxx cli_call_test)
+add_dependencies(buildtests_cxx client_callback_end2end_test)
add_dependencies(buildtests_cxx client_channel_stress_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx client_crash_test)
@@ -972,7 +968,6 @@ add_library(grpc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -1103,6 +1098,7 @@ add_library(grpc
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -1380,7 +1376,6 @@ add_library(grpc_cronet
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -1514,6 +1509,7 @@ add_library(grpc_cronet
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -1774,7 +1770,6 @@ add_library(grpc_test_util
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -1927,6 +1922,7 @@ add_library(grpc_test_util
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -2084,7 +2080,6 @@ add_library(grpc_test_util_unsecure
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -2237,6 +2232,7 @@ add_library(grpc_test_util_unsecure
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -2373,7 +2369,6 @@ add_library(grpc_unsecure
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -2505,6 +2500,7 @@ add_library(grpc_unsecure
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -2917,6 +2913,7 @@ foreach(_hdr
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
+ include/grpcpp/support/client_callback.h
include/grpcpp/support/config.h
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
@@ -3014,7 +3011,9 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@@ -3171,6 +3170,7 @@ add_library(grpc++_cronet
src/core/ext/transport/chttp2/transport/frame_settings.cc
src/core/ext/transport/chttp2/transport/frame_window_update.cc
src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc
src/core/ext/transport/chttp2/transport/hpack_parser.cc
src/core/ext/transport/chttp2/transport/hpack_table.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -3215,7 +3215,6 @@ add_library(grpc++_cronet
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/ev_epoll1_linux.cc
src/core/lib/iomgr/ev_epollex_linux.cc
- src/core/lib/iomgr/ev_epollsig_linux.cc
src/core/lib/iomgr/ev_poll_posix.cc
src/core/lib/iomgr/ev_posix.cc
src/core/lib/iomgr/ev_windows.cc
@@ -3486,6 +3485,7 @@ foreach(_hdr
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
+ include/grpcpp/support/client_callback.h
include/grpcpp/support/config.h
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
@@ -3583,7 +3583,9 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@@ -3993,7 +3995,9 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@@ -4171,7 +4175,9 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@@ -4392,6 +4398,7 @@ foreach(_hdr
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
+ include/grpcpp/support/client_callback.h
include/grpcpp/support/config.h
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
@@ -4489,7 +4496,9 @@ foreach(_hdr
include/grpcpp/impl/codegen/byte_buffer.h
include/grpcpp/impl/codegen/call.h
include/grpcpp/impl/codegen/call_hook.h
+ include/grpcpp/impl/codegen/callback_common.h
include/grpcpp/impl/codegen/channel_interface.h
+ include/grpcpp/impl/codegen/client_callback.h
include/grpcpp/impl/codegen/client_context.h
include/grpcpp/impl/codegen/client_unary_call.h
include/grpcpp/impl/codegen/completion_queue.h
@@ -6375,37 +6384,6 @@ target_link_libraries(ev_epollex_linux_test
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-if(_gRPC_PLATFORM_LINUX)
-
-add_executable(ev_epollsig_linux_test
- test/core/iomgr/ev_epollsig_linux_test.cc
-)
-
-
-target_include_directories(ev_epollsig_linux_test
- PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
- PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
- PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
- PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
- PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
- PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
- PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
- PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
- PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
- PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
-)
-
-target_link_libraries(ev_epollsig_linux_test
- ${_gRPC_ALLTARGETS_LIBRARIES}
- grpc_test_util
- grpc
- gpr_test_util
- gpr
-)
-
-endif()
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
add_executable(fake_resolver_test
test/core/client_channel/resolvers/fake_resolver_test.cc
@@ -8490,14 +8468,14 @@ target_link_libraries(percent_encoding_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-if(_gRPC_PLATFORM_LINUX)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
-add_executable(pollset_set_test
- test/core/iomgr/pollset_set_test.cc
+add_executable(resolve_address_posix_test
+ test/core/iomgr/resolve_address_posix_test.cc
)
-target_include_directories(pollset_set_test
+target_include_directories(resolve_address_posix_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8510,7 +8488,7 @@ target_include_directories(pollset_set_test
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(pollset_set_test
+target_link_libraries(resolve_address_posix_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8521,14 +8499,13 @@ target_link_libraries(pollset_set_test
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
-add_executable(resolve_address_posix_test
- test/core/iomgr/resolve_address_posix_test.cc
+add_executable(resolve_address_using_ares_resolver_test
+ test/core/iomgr/resolve_address_test.cc
)
-target_include_directories(resolve_address_posix_test
+target_include_directories(resolve_address_using_ares_resolver_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8541,7 +8518,7 @@ target_include_directories(resolve_address_posix_test
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(resolve_address_posix_test
+target_link_libraries(resolve_address_using_ares_resolver_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -8549,16 +8526,15 @@ target_link_libraries(resolve_address_posix_test
gpr
)
-endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
-add_executable(resolve_address_test
+add_executable(resolve_address_using_native_resolver_test
test/core/iomgr/resolve_address_test.cc
)
-target_include_directories(resolve_address_test
+target_include_directories(resolve_address_using_native_resolver_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
@@ -8571,7 +8547,7 @@ target_include_directories(resolve_address_test
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
)
-target_link_libraries(resolve_address_test
+target_link_libraries(resolve_address_using_native_resolver_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
@@ -11297,6 +11273,46 @@ target_link_libraries(cli_call_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
+add_executable(client_callback_end2end_test
+ test/cpp/end2end/client_callback_end2end_test.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(client_callback_end2end_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+ PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
+ PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
+ PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
+ PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
+ PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+ PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
+ PRIVATE third_party/googletest/googletest/include
+ PRIVATE third_party/googletest/googletest
+ PRIVATE third_party/googletest/googlemock/include
+ PRIVATE third_party/googletest/googlemock
+ PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(client_callback_end2end_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc++_test_util
+ grpc_test_util
+ grpc++
+ grpc
+ gpr_test_util
+ gpr
+ ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
add_executable(client_channel_stress_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc
diff --git a/Makefile b/Makefile
index 96ea890bcb..baaebd1803 100644
--- a/Makefile
+++ b/Makefile
@@ -352,6 +352,7 @@ CXXFLAGS += -std=c++11
ifeq ($(SYSTEM),Darwin)
CXXFLAGS += -stdlib=libc++
endif
+CXXFLAGS += -Wnon-virtual-dtor
CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 -Wno-deprecated-declarations -Ithird_party/nanopb -DPB_FIELD_32BIT
COREFLAGS += -fno-rtti -fno-exceptions
LDFLAGS += -g
@@ -997,7 +998,6 @@ dualstack_socket_test: $(BINDIR)/$(CONFIG)/dualstack_socket_test
endpoint_pair_test: $(BINDIR)/$(CONFIG)/endpoint_pair_test
error_test: $(BINDIR)/$(CONFIG)/error_test
ev_epollex_linux_test: $(BINDIR)/$(CONFIG)/ev_epollex_linux_test
-ev_epollsig_linux_test: $(BINDIR)/$(CONFIG)/ev_epollsig_linux_test
fake_resolver_test: $(BINDIR)/$(CONFIG)/fake_resolver_test
fake_transport_security_test: $(BINDIR)/$(CONFIG)/fake_transport_security_test
fd_conservation_posix_test: $(BINDIR)/$(CONFIG)/fd_conservation_posix_test
@@ -1079,9 +1079,9 @@ parse_address_test: $(BINDIR)/$(CONFIG)/parse_address_test
percent_decode_fuzzer: $(BINDIR)/$(CONFIG)/percent_decode_fuzzer
percent_encode_fuzzer: $(BINDIR)/$(CONFIG)/percent_encode_fuzzer
percent_encoding_test: $(BINDIR)/$(CONFIG)/percent_encoding_test
-pollset_set_test: $(BINDIR)/$(CONFIG)/pollset_set_test
resolve_address_posix_test: $(BINDIR)/$(CONFIG)/resolve_address_posix_test
-resolve_address_test: $(BINDIR)/$(CONFIG)/resolve_address_test
+resolve_address_using_ares_resolver_test: $(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test
+resolve_address_using_native_resolver_test: $(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test
resource_quota_test: $(BINDIR)/$(CONFIG)/resource_quota_test
secure_channel_create_test: $(BINDIR)/$(CONFIG)/secure_channel_create_test
secure_endpoint_test: $(BINDIR)/$(CONFIG)/secure_endpoint_test
@@ -1160,6 +1160,7 @@ check_gcp_environment_linux_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_linu
check_gcp_environment_windows_test: $(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test
chttp2_settings_timeout_test: $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test
cli_call_test: $(BINDIR)/$(CONFIG)/cli_call_test
+client_callback_end2end_test: $(BINDIR)/$(CONFIG)/client_callback_end2end_test
client_channel_stress_test: $(BINDIR)/$(CONFIG)/client_channel_stress_test
client_crash_test: $(BINDIR)/$(CONFIG)/client_crash_test
client_crash_test_server: $(BINDIR)/$(CONFIG)/client_crash_test_server
@@ -1452,7 +1453,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/endpoint_pair_test \
$(BINDIR)/$(CONFIG)/error_test \
$(BINDIR)/$(CONFIG)/ev_epollex_linux_test \
- $(BINDIR)/$(CONFIG)/ev_epollsig_linux_test \
$(BINDIR)/$(CONFIG)/fake_resolver_test \
$(BINDIR)/$(CONFIG)/fake_transport_security_test \
$(BINDIR)/$(CONFIG)/fd_conservation_posix_test \
@@ -1522,9 +1522,9 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test \
$(BINDIR)/$(CONFIG)/parse_address_test \
$(BINDIR)/$(CONFIG)/percent_encoding_test \
- $(BINDIR)/$(CONFIG)/pollset_set_test \
$(BINDIR)/$(CONFIG)/resolve_address_posix_test \
- $(BINDIR)/$(CONFIG)/resolve_address_test \
+ $(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test \
+ $(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test \
$(BINDIR)/$(CONFIG)/resource_quota_test \
$(BINDIR)/$(CONFIG)/secure_channel_create_test \
$(BINDIR)/$(CONFIG)/secure_endpoint_test \
@@ -1665,6 +1665,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
$(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
$(BINDIR)/$(CONFIG)/cli_call_test \
+ $(BINDIR)/$(CONFIG)/client_callback_end2end_test \
$(BINDIR)/$(CONFIG)/client_channel_stress_test \
$(BINDIR)/$(CONFIG)/client_crash_test \
$(BINDIR)/$(CONFIG)/client_crash_test_server \
@@ -1845,6 +1846,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/check_gcp_environment_windows_test \
$(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test \
$(BINDIR)/$(CONFIG)/cli_call_test \
+ $(BINDIR)/$(CONFIG)/client_callback_end2end_test \
$(BINDIR)/$(CONFIG)/client_channel_stress_test \
$(BINDIR)/$(CONFIG)/client_crash_test \
$(BINDIR)/$(CONFIG)/client_crash_test_server \
@@ -1986,8 +1988,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/error_test || ( echo test error_test failed ; exit 1 )
$(E) "[RUN] Testing ev_epollex_linux_test"
$(Q) $(BINDIR)/$(CONFIG)/ev_epollex_linux_test || ( echo test ev_epollex_linux_test failed ; exit 1 )
- $(E) "[RUN] Testing ev_epollsig_linux_test"
- $(Q) $(BINDIR)/$(CONFIG)/ev_epollsig_linux_test || ( echo test ev_epollsig_linux_test failed ; exit 1 )
$(E) "[RUN] Testing fake_resolver_test"
$(Q) $(BINDIR)/$(CONFIG)/fake_resolver_test || ( echo test fake_resolver_test failed ; exit 1 )
$(E) "[RUN] Testing fake_transport_security_test"
@@ -2114,12 +2114,12 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/parse_address_test || ( echo test parse_address_test failed ; exit 1 )
$(E) "[RUN] Testing percent_encoding_test"
$(Q) $(BINDIR)/$(CONFIG)/percent_encoding_test || ( echo test percent_encoding_test failed ; exit 1 )
- $(E) "[RUN] Testing pollset_set_test"
- $(Q) $(BINDIR)/$(CONFIG)/pollset_set_test || ( echo test pollset_set_test failed ; exit 1 )
$(E) "[RUN] Testing resolve_address_posix_test"
$(Q) $(BINDIR)/$(CONFIG)/resolve_address_posix_test || ( echo test resolve_address_posix_test failed ; exit 1 )
- $(E) "[RUN] Testing resolve_address_test"
- $(Q) $(BINDIR)/$(CONFIG)/resolve_address_test || ( echo test resolve_address_test failed ; exit 1 )
+ $(E) "[RUN] Testing resolve_address_using_ares_resolver_test"
+ $(Q) $(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test || ( echo test resolve_address_using_ares_resolver_test failed ; exit 1 )
+ $(E) "[RUN] Testing resolve_address_using_native_resolver_test"
+ $(Q) $(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test || ( echo test resolve_address_using_native_resolver_test failed ; exit 1 )
$(E) "[RUN] Testing resource_quota_test"
$(Q) $(BINDIR)/$(CONFIG)/resource_quota_test || ( echo test resource_quota_test failed ; exit 1 )
$(E) "[RUN] Testing secure_channel_create_test"
@@ -2302,6 +2302,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/chttp2_settings_timeout_test || ( echo test chttp2_settings_timeout_test failed ; exit 1 )
$(E) "[RUN] Testing cli_call_test"
$(Q) $(BINDIR)/$(CONFIG)/cli_call_test || ( echo test cli_call_test failed ; exit 1 )
+ $(E) "[RUN] Testing client_callback_end2end_test"
+ $(Q) $(BINDIR)/$(CONFIG)/client_callback_end2end_test || ( echo test client_callback_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing client_channel_stress_test"
$(Q) $(BINDIR)/$(CONFIG)/client_channel_stress_test || ( echo test client_channel_stress_test failed ; exit 1 )
$(E) "[RUN] Testing client_crash_test"
@@ -3474,7 +3476,6 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -3605,6 +3606,7 @@ LIBGRPC_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@@ -3881,7 +3883,6 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -4015,6 +4016,7 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@@ -4273,7 +4275,6 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -4426,6 +4427,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@@ -4574,7 +4576,6 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -4727,6 +4728,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@@ -4841,7 +4843,6 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -4973,6 +4974,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@@ -5329,6 +5331,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+ include/grpcpp/support/client_callback.h \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
@@ -5426,7 +5429,9 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@@ -5627,6 +5632,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
@@ -5671,7 +5677,6 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -5905,6 +5910,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+ include/grpcpp/support/client_callback.h \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
@@ -6002,7 +6008,9 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@@ -6392,7 +6400,9 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@@ -6546,7 +6556,9 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@@ -6771,6 +6783,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+ include/grpcpp/support/client_callback.h \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
@@ -6868,7 +6881,9 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+ include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+ include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@@ -11325,38 +11340,6 @@ endif
endif
-EV_EPOLLSIG_LINUX_TEST_SRC = \
- test/core/iomgr/ev_epollsig_linux_test.cc \
-
-EV_EPOLLSIG_LINUX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(EV_EPOLLSIG_LINUX_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/ev_epollsig_linux_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/ev_epollsig_linux_test: $(EV_EPOLLSIG_LINUX_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) $(EV_EPOLLSIG_LINUX_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)/ev_epollsig_linux_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/iomgr/ev_epollsig_linux_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_ev_epollsig_linux_test: $(EV_EPOLLSIG_LINUX_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(EV_EPOLLSIG_LINUX_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
FAKE_RESOLVER_TEST_SRC = \
test/core/client_channel/resolvers/fake_resolver_test.cc \
@@ -13967,98 +13950,98 @@ endif
endif
-POLLSET_SET_TEST_SRC = \
- test/core/iomgr/pollset_set_test.cc \
+RESOLVE_ADDRESS_POSIX_TEST_SRC = \
+ test/core/iomgr/resolve_address_posix_test.cc \
-POLLSET_SET_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(POLLSET_SET_TEST_SRC))))
+RESOLVE_ADDRESS_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_POSIX_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/pollset_set_test: openssl_dep_error
+$(BINDIR)/$(CONFIG)/resolve_address_posix_test: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/pollset_set_test: $(POLLSET_SET_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/resolve_address_posix_test: $(RESOLVE_ADDRESS_POSIX_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) $(POLLSET_SET_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)/pollset_set_test
+ $(Q) $(LD) $(LDFLAGS) $(RESOLVE_ADDRESS_POSIX_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)/resolve_address_posix_test
endif
-$(OBJDIR)/$(CONFIG)/test/core/iomgr/pollset_set_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/iomgr/resolve_address_posix_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_pollset_set_test: $(POLLSET_SET_TEST_OBJS:.o=.dep)
+deps_resolve_address_posix_test: $(RESOLVE_ADDRESS_POSIX_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(POLLSET_SET_TEST_OBJS:.o=.dep)
+-include $(RESOLVE_ADDRESS_POSIX_TEST_OBJS:.o=.dep)
endif
endif
-RESOLVE_ADDRESS_POSIX_TEST_SRC = \
- test/core/iomgr/resolve_address_posix_test.cc \
+RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_SRC = \
+ test/core/iomgr/resolve_address_test.cc \
-RESOLVE_ADDRESS_POSIX_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_POSIX_TEST_SRC))))
+RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/resolve_address_posix_test: openssl_dep_error
+$(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/resolve_address_posix_test: $(RESOLVE_ADDRESS_POSIX_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/resolve_address_using_ares_resolver_test: $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_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) $(RESOLVE_ADDRESS_POSIX_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)/resolve_address_posix_test
+ $(Q) $(LD) $(LDFLAGS) $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_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)/resolve_address_using_ares_resolver_test
endif
-$(OBJDIR)/$(CONFIG)/test/core/iomgr/resolve_address_posix_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/iomgr/resolve_address_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_resolve_address_posix_test: $(RESOLVE_ADDRESS_POSIX_TEST_OBJS:.o=.dep)
+deps_resolve_address_using_ares_resolver_test: $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(RESOLVE_ADDRESS_POSIX_TEST_OBJS:.o=.dep)
+-include $(RESOLVE_ADDRESS_USING_ARES_RESOLVER_TEST_OBJS:.o=.dep)
endif
endif
-RESOLVE_ADDRESS_TEST_SRC = \
+RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_SRC = \
test/core/iomgr/resolve_address_test.cc \
-RESOLVE_ADDRESS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_TEST_SRC))))
+RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
-$(BINDIR)/$(CONFIG)/resolve_address_test: openssl_dep_error
+$(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test: openssl_dep_error
else
-$(BINDIR)/$(CONFIG)/resolve_address_test: $(RESOLVE_ADDRESS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/resolve_address_using_native_resolver_test: $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_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) $(RESOLVE_ADDRESS_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)/resolve_address_test
+ $(Q) $(LD) $(LDFLAGS) $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_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)/resolve_address_using_native_resolver_test
endif
$(OBJDIR)/$(CONFIG)/test/core/iomgr/resolve_address_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-deps_resolve_address_test: $(RESOLVE_ADDRESS_TEST_OBJS:.o=.dep)
+deps_resolve_address_using_native_resolver_test: $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
--include $(RESOLVE_ADDRESS_TEST_OBJS:.o=.dep)
+-include $(RESOLVE_ADDRESS_USING_NATIVE_RESOLVER_TEST_OBJS:.o=.dep)
endif
endif
@@ -17076,6 +17059,49 @@ endif
endif
+CLIENT_CALLBACK_END2END_TEST_SRC = \
+ test/cpp/end2end/client_callback_end2end_test.cc \
+
+CLIENT_CALLBACK_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CLIENT_CALLBACK_END2END_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/client_callback_end2end_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
+
+$(BINDIR)/$(CONFIG)/client_callback_end2end_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/client_callback_end2end_test: $(PROTOBUF_DEP) $(CLIENT_CALLBACK_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LDXX) $(LDFLAGS) $(CLIENT_CALLBACK_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/client_callback_end2end_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/client_callback_end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_client_callback_end2end_test: $(CLIENT_CALLBACK_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CLIENT_CALLBACK_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
CLIENT_CHANNEL_STRESS_TEST_SRC = \
$(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc \
test/cpp/client/client_channel_stress_test.cc \
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index b3f97650e8..159ebd5d1f 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -24,7 +24,7 @@
#
# The set of pollers to test against if a test exercises polling
-POLLERS = ["epollex", "epollsig", "epoll1", "poll", "poll-cv"]
+POLLERS = ["epollex", "epoll1", "poll", "poll-cv"]
def if_not_windows(a):
return select({
diff --git a/build.yaml b/build.yaml
index a50a0a4ab6..f3895bb702 100644
--- a/build.yaml
+++ b/build.yaml
@@ -266,7 +266,6 @@ filegroups:
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/ev_epoll1_linux.cc
- src/core/lib/iomgr/ev_epollex_linux.cc
- - src/core/lib/iomgr/ev_epollsig_linux.cc
- src/core/lib/iomgr/ev_poll_posix.cc
- src/core/lib/iomgr/ev_posix.cc
- src/core/lib/iomgr/ev_windows.cc
@@ -446,7 +445,6 @@ filegroups:
- src/core/lib/iomgr/error_internal.h
- src/core/lib/iomgr/ev_epoll1_linux.h
- src/core/lib/iomgr/ev_epollex_linux.h
- - src/core/lib/iomgr/ev_epollsig_linux.h
- src/core/lib/iomgr/ev_poll_posix.h
- src/core/lib/iomgr/ev_posix.h
- src/core/lib/iomgr/exec_ctx.h
@@ -936,6 +934,7 @@ filegroups:
- src/core/ext/transport/chttp2/transport/frame_settings.h
- src/core/ext/transport/chttp2/transport/frame_window_update.h
- src/core/ext/transport/chttp2/transport/hpack_encoder.h
+ - src/core/ext/transport/chttp2/transport/hpack_mapping.h
- src/core/ext/transport/chttp2/transport/hpack_parser.h
- src/core/ext/transport/chttp2/transport/hpack_table.h
- src/core/ext/transport/chttp2/transport/http2_settings.h
@@ -957,6 +956,7 @@ filegroups:
- src/core/ext/transport/chttp2/transport/frame_settings.cc
- src/core/ext/transport/chttp2/transport/frame_window_update.cc
- src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+ - src/core/ext/transport/chttp2/transport/hpack_mapping.cc
- src/core/ext/transport/chttp2/transport/hpack_parser.cc
- src/core/ext/transport/chttp2/transport/hpack_table.cc
- src/core/ext/transport/chttp2/transport/http2_settings.cc
@@ -1169,7 +1169,9 @@ filegroups:
- include/grpcpp/impl/codegen/byte_buffer.h
- include/grpcpp/impl/codegen/call.h
- include/grpcpp/impl/codegen/call_hook.h
+ - include/grpcpp/impl/codegen/callback_common.h
- include/grpcpp/impl/codegen/channel_interface.h
+ - include/grpcpp/impl/codegen/client_callback.h
- include/grpcpp/impl/codegen/client_context.h
- include/grpcpp/impl/codegen/client_unary_call.h
- include/grpcpp/impl/codegen/completion_queue.h
@@ -1297,6 +1299,7 @@ filegroups:
- include/grpcpp/support/async_unary_call.h
- include/grpcpp/support/byte_buffer.h
- include/grpcpp/support/channel_arguments.h
+ - include/grpcpp/support/client_callback.h
- include/grpcpp/support/config.h
- include/grpcpp/support/proto_buffer_reader.h
- include/grpcpp/support/proto_buffer_writer.h
@@ -2367,21 +2370,6 @@ targets:
- uv
platforms:
- linux
-- name: ev_epollsig_linux_test
- cpu_cost: 3
- build: test
- language: c
- src:
- - test/core/iomgr/ev_epollsig_linux_test.cc
- deps:
- - grpc_test_util
- - grpc
- - gpr_test_util
- - gpr
- exclude_iomgrs:
- - uv
- platforms:
- - linux
- name: fake_resolver_test
build: test
language: c
@@ -3333,11 +3321,11 @@ targets:
- gpr_test_util
- gpr
uses_polling: false
-- name: pollset_set_test
+- name: resolve_address_posix_test
build: test
language: c
src:
- - test/core/iomgr/pollset_set_test.cc
+ - test/core/iomgr/resolve_address_posix_test.cc
deps:
- grpc_test_util
- grpc
@@ -3346,24 +3334,22 @@ targets:
exclude_iomgrs:
- uv
platforms:
+ - mac
- linux
-- name: resolve_address_posix_test
+ - posix
+- name: resolve_address_using_ares_resolver_test
build: test
language: c
src:
- - test/core/iomgr/resolve_address_posix_test.cc
+ - test/core/iomgr/resolve_address_test.cc
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- exclude_iomgrs:
- - uv
- platforms:
- - mac
- - linux
- - posix
-- name: resolve_address_test
+ args:
+ - --resolver=ares
+- name: resolve_address_using_native_resolver_test
build: test
language: c
src:
@@ -3373,6 +3359,8 @@ targets:
- grpc
- gpr_test_util
- gpr
+ args:
+ - --resolver=native
- name: resource_quota_test
cpu_cost: 30
build: test
@@ -4465,6 +4453,20 @@ targets:
- grpc
- gpr_test_util
- gpr
+- name: client_callback_end2end_test
+ gtest: true
+ cpu_cost: 0.5
+ build: test
+ language: c++
+ src:
+ - test/cpp/end2end/client_callback_end2end_test.cc
+ deps:
+ - grpc++_test_util
+ - grpc_test_util
+ - grpc++
+ - grpc
+ - gpr_test_util
+ - gpr
- name: client_channel_stress_test
gtest: false
build: test
@@ -5827,6 +5829,7 @@ defaults:
COREFLAGS: -fno-rtti -fno-exceptions
CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
-Wno-deprecated-declarations -Ithird_party/nanopb -DPB_FIELD_32BIT
+ CXXFLAGS: -Wnon-virtual-dtor
LDFLAGS: -g
zlib:
CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration
diff --git a/config.m4 b/config.m4
index af3624cdd1..1796c8c8e2 100644
--- a/config.m4
+++ b/config.m4
@@ -118,7 +118,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/error.cc \
src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.cc \
- src/core/lib/iomgr/ev_epollsig_linux.cc \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_posix.cc \
src/core/lib/iomgr/ev_windows.cc \
@@ -249,6 +248,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/transport/chttp2/transport/frame_settings.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
+ src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
diff --git a/config.w32 b/config.w32
index ad91ee40bd..6cdd2dac8b 100644
--- a/config.w32
+++ b/config.w32
@@ -93,7 +93,6 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\iomgr\\error.cc " +
"src\\core\\lib\\iomgr\\ev_epoll1_linux.cc " +
"src\\core\\lib\\iomgr\\ev_epollex_linux.cc " +
- "src\\core\\lib\\iomgr\\ev_epollsig_linux.cc " +
"src\\core\\lib\\iomgr\\ev_poll_posix.cc " +
"src\\core\\lib\\iomgr\\ev_posix.cc " +
"src\\core\\lib\\iomgr\\ev_windows.cc " +
@@ -224,6 +223,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\transport\\chttp2\\transport\\frame_settings.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\frame_window_update.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\hpack_encoder.cc " +
+ "src\\core\\ext\\transport\\chttp2\\transport\\hpack_mapping.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\hpack_parser.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\hpack_table.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\http2_settings.cc " +
diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md
index 3c33189196..1d6535d7ea 100644
--- a/doc/interop-test-descriptions.md
+++ b/doc/interop-test-descriptions.md
@@ -944,6 +944,11 @@ the experimental flag, `soak_iterations`.
This tests puts stress on several gRPC components; the resolver, the load
balancer, and the RPC hotpath.
+#### long_lived_channel
+
+The client performs a number of large_unary RPCs over a single long-lived
+channel with a fixed but configurable interval between each RPC.
+
### TODO Tests
#### High priority:
diff --git a/etc/roots.pem b/etc/roots.pem
index c22dfe69f8..3e6bbcd76e 100644
--- a/etc/roots.pem
+++ b/etc/roots.pem
@@ -4317,3 +4317,26 @@ JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R
8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4
5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
-----END CERTIFICATE-----
+
+# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed
+# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed
+# Label: "OISTE WISeKey Global Root GC CA"
+# Serial: 44084345621038548146064804565436152554
+# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23
+# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31
+# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d
+-----BEGIN CERTIFICATE-----
+MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw
+CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91
+bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg
+Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ
+BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu
+ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS
+b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni
+eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W
+p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T
+rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV
+57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg
+Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
+-----END CERTIFICATE-----
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 581b9246bc..3ca132f7c3 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -111,6 +111,7 @@ Pod::Spec.new do |s|
'include/grpcpp/support/async_unary_call.h',
'include/grpcpp/support/byte_buffer.h',
'include/grpcpp/support/channel_arguments.h',
+ 'include/grpcpp/support/client_callback.h',
'include/grpcpp/support/config.h',
'include/grpcpp/support/proto_buffer_reader.h',
'include/grpcpp/support/proto_buffer_writer.h',
@@ -127,7 +128,9 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/byte_buffer.h',
'include/grpcpp/impl/codegen/call.h',
'include/grpcpp/impl/codegen/call_hook.h',
+ 'include/grpcpp/impl/codegen/callback_common.h',
'include/grpcpp/impl/codegen/channel_interface.h',
+ 'include/grpcpp/impl/codegen/client_callback.h',
'include/grpcpp/impl/codegen/client_context.h',
'include/grpcpp/impl/codegen/client_unary_call.h',
'include/grpcpp/impl/codegen/completion_queue.h',
@@ -251,6 +254,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
+ 'src/core/ext/transport/chttp2/transport/hpack_mapping.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
@@ -392,7 +396,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error_internal.h',
'src/core/lib/iomgr/ev_epoll1_linux.h',
'src/core/lib/iomgr/ev_epollex_linux.h',
- 'src/core/lib/iomgr/ev_epollsig_linux.h',
'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h',
'src/core/lib/iomgr/exec_ctx.h',
@@ -582,7 +585,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error_internal.h',
'src/core/lib/iomgr/ev_epoll1_linux.h',
'src/core/lib/iomgr/ev_epollex_linux.h',
- 'src/core/lib/iomgr/ev_epollsig_linux.h',
'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h',
'src/core/lib/iomgr/exec_ctx.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 5a82a4200a..0c3fbe0a25 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -181,7 +181,7 @@ Pod::Spec.new do |s|
ss.header_mappings_dir = '.'
ss.libraries = 'z'
ss.dependency "#{s.name}/Interface", version
- ss.dependency 'BoringSSL-GRPC', '0.0.1'
+ ss.dependency 'BoringSSL-GRPC', '0.0.2'
ss.dependency 'nanopb', '~> 0.3'
ss.compiler_flags = '-DGRPC_SHADOW_BORINGSSL_SYMBOLS'
@@ -263,6 +263,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
+ 'src/core/ext/transport/chttp2/transport/hpack_mapping.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
@@ -404,7 +405,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error_internal.h',
'src/core/lib/iomgr/ev_epoll1_linux.h',
'src/core/lib/iomgr/ev_epollex_linux.h',
- 'src/core/lib/iomgr/ev_epollsig_linux.h',
'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h',
'src/core/lib/iomgr/exec_ctx.h',
@@ -550,7 +550,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -681,6 +680,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
+ 'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
@@ -866,6 +866,7 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/frame_settings.h',
'src/core/ext/transport/chttp2/transport/frame_window_update.h',
'src/core/ext/transport/chttp2/transport/hpack_encoder.h',
+ 'src/core/ext/transport/chttp2/transport/hpack_mapping.h',
'src/core/ext/transport/chttp2/transport/hpack_parser.h',
'src/core/ext/transport/chttp2/transport/hpack_table.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
@@ -1007,7 +1008,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/error_internal.h',
'src/core/lib/iomgr/ev_epoll1_linux.h',
'src/core/lib/iomgr/ev_epollex_linux.h',
- 'src/core/lib/iomgr/ev_epollsig_linux.h',
'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h',
'src/core/lib/iomgr/exec_ctx.h',
@@ -1307,5 +1307,6 @@ Pod::Spec.new do |s|
s.prepare_command = <<-END_OF_COMMAND
find src/core/ -type f ! -path '*.grpc_back' -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "(pb(_.*)?\\.h)";#include <nanopb/\\1>;g'
find src/core/ -type f -path '*.grpc_back' -print0 | xargs -0 rm
+ find src/core/ -type f \\( -path '*.h' -or -path '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/;#include <openssl_grpc/;g'
END_OF_COMMAND
end
diff --git a/grpc.gemspec b/grpc.gemspec
index c8e58faec9..5780dd7a07 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -195,6 +195,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_window_update.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.h )
+ s.files += %w( src/core/ext/transport/chttp2/transport/hpack_mapping.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.h )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.h )
s.files += %w( src/core/ext/transport/chttp2/transport/http2_settings.h )
@@ -340,7 +341,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/error_internal.h )
s.files += %w( src/core/lib/iomgr/ev_epoll1_linux.h )
s.files += %w( src/core/lib/iomgr/ev_epollex_linux.h )
- s.files += %w( src/core/lib/iomgr/ev_epollsig_linux.h )
s.files += %w( src/core/lib/iomgr/ev_poll_posix.h )
s.files += %w( src/core/lib/iomgr/ev_posix.h )
s.files += %w( src/core/lib/iomgr/exec_ctx.h )
@@ -486,7 +486,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/error.cc )
s.files += %w( src/core/lib/iomgr/ev_epoll1_linux.cc )
s.files += %w( src/core/lib/iomgr/ev_epollex_linux.cc )
- s.files += %w( src/core/lib/iomgr/ev_epollsig_linux.cc )
s.files += %w( src/core/lib/iomgr/ev_poll_posix.cc )
s.files += %w( src/core/lib/iomgr/ev_posix.cc )
s.files += %w( src/core/lib/iomgr/ev_windows.cc )
@@ -617,6 +616,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/frame_settings.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/frame_window_update.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_encoder.cc )
+ s.files += %w( src/core/ext/transport/chttp2/transport/hpack_mapping.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_parser.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/hpack_table.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/http2_settings.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 654a531092..1ef44eb4ad 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -310,7 +310,6 @@
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -441,6 +440,7 @@
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
+ 'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
@@ -672,7 +672,6 @@
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -825,6 +824,7 @@
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
+ 'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
@@ -907,7 +907,6 @@
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -1060,6 +1059,7 @@
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
+ 'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
@@ -1120,7 +1120,6 @@
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -1252,6 +1251,7 @@
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
+ 'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index fc0a0d3cce..a9beee1c9e 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -111,7 +111,8 @@ GRPCAPI grpc_completion_queue* grpc_completion_queue_create_for_pluck(
of GRPC_CQ_CALLBACK and grpc_cq_polling_type of GRPC_CQ_DEFAULT_POLLING.
This function is experimental. */
GRPCAPI grpc_completion_queue* grpc_completion_queue_create_for_callback(
- void* shutdown_callback, void* reserved);
+ grpc_experimental_completion_queue_functor* shutdown_callback,
+ void* reserved);
/** Create a completion queue */
GRPCAPI grpc_completion_queue* grpc_completion_queue_create(
@@ -500,7 +501,7 @@ GRPCAPI const grpc_arg_pointer_vtable* grpc_resource_quota_arg_vtable(void);
GRPCAPI char* grpc_channelz_get_top_channels(intptr_t start_channel_id);
/* Gets all servers that exist in the process. */
-GRPCAPI char* grpc_channelz_get_servers(intptr_t start_channel_id);
+GRPCAPI char* grpc_channelz_get_servers(intptr_t start_server_id);
/* Returns a single Channel, or else a NOT_FOUND code. The returned string
is allocated and must be freed by the application. */
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 02d87a493a..de90971cc5 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -532,14 +532,14 @@ typedef struct grpc_alts_credentials_options grpc_alts_credentials_options;
* It is used for experimental purpose for now and subject to change.
*/
GRPCAPI grpc_alts_credentials_options*
-grpc_alts_credentials_client_options_create();
+grpc_alts_credentials_client_options_create(void);
/**
* This method creates a grpc ALTS credentials server options instance.
* It is used for experimental purpose for now and subject to change.
*/
GRPCAPI grpc_alts_credentials_options*
-grpc_alts_credentials_server_options_create();
+grpc_alts_credentials_server_options_create(void);
/**
* This method adds a target service account to grpc client's ALTS credentials
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 5f3b96f40b..9ed5b3c1d4 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -660,6 +660,19 @@ typedef enum {
GRPC_CQ_CALLBACK
} grpc_cq_completion_type;
+/** EXPERIMENTAL: Specifies an interface class to be used as a tag
+ for callback-based completion queues. This can be used directly,
+ as the first element of a struct in C, or as a base class in C++.
+ Its "run" value should be assigned to some non-member function, such as
+ a static method. */
+typedef struct grpc_experimental_completion_queue_functor {
+ /** The run member specifies a function that will be called when this
+ tag is extracted from the completion queue. Its arguments will be a
+ pointer to this functor and a boolean that indicates whether the
+ operation succeeded (non-zero) or failed (zero) */
+ void (*functor_run)(struct grpc_experimental_completion_queue_functor*, int);
+} grpc_experimental_completion_queue_functor;
+
/* The upgrade to version 2 is currently experimental. */
#define GRPC_CQ_CURRENT_VERSION 2
@@ -678,7 +691,7 @@ typedef struct grpc_completion_queue_attributes {
/* EXPERIMENTAL: START OF VERSION 2 CQ ATTRIBUTES */
/** When creating a callbackable CQ, pass in a functor to get invoked when
* shutdown is complete */
- void* cq_shutdown_cb;
+ grpc_experimental_completion_queue_functor* cq_shutdown_cb;
/* END OF VERSION 2 CQ ATTRIBUTES */
} grpc_completion_queue_attributes;
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index 8d9bd83285..b2028a6305 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -174,6 +174,7 @@
#ifdef __GLIBC__
#define GPR_POSIX_CRASH_HANDLER 1
#define GPR_LINUX_PTHREAD_NAME 1
+#include <linux/version.h>
#else /* musl libc */
#define GPR_MUSL_LIBC_COMPAT 1
#endif
diff --git a/include/grpcpp/alarm.h b/include/grpcpp/alarm.h
index f484610a6e..365feb4eb9 100644
--- a/include/grpcpp/alarm.h
+++ b/include/grpcpp/alarm.h
@@ -21,6 +21,8 @@
#ifndef GRPCPP_ALARM_H
#define GRPCPP_ALARM_H
+#include <functional>
+
#include <grpc/grpc.h>
#include <grpcpp/impl/codegen/completion_queue.h>
#include <grpcpp/impl/codegen/completion_queue_tag.h>
@@ -76,8 +78,33 @@ class Alarm : private GrpcLibraryCodegen {
/// has already fired has no effect.
void Cancel();
+ /// NOTE: class experimental_type is not part of the public API of this class
+ /// TODO(vjpai): Move these contents to the public API of Alarm when
+ /// they are no longer experimental
+ class experimental_type {
+ public:
+ explicit experimental_type(Alarm* alarm) : alarm_(alarm) {}
+
+ /// Set an alarm to invoke callback \a f. The argument to the callback
+ /// states whether the alarm expired at \a deadline (true) or was cancelled
+ /// (false)
+ template <typename T>
+ void Set(const T& deadline, std::function<void(bool)> f) {
+ alarm_->SetInternal(TimePoint<T>(deadline).raw_time(), std::move(f));
+ }
+
+ private:
+ Alarm* alarm_;
+ };
+
+ /// NOTE: The function experimental() is not stable public API. It is a view
+ /// to the experimental components of this class. It may be changed or removed
+ /// at any time.
+ experimental_type experimental() { return experimental_type(this); }
+
private:
void SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag);
+ void SetInternal(gpr_timespec deadline, std::function<void(bool)> f);
internal::CompletionQueueTag* alarm_;
};
diff --git a/include/grpcpp/channel.h b/include/grpcpp/channel.h
index fed02bf7bc..f1dba5b8ad 100644
--- a/include/grpcpp/channel.h
+++ b/include/grpcpp/channel.h
@@ -78,8 +78,19 @@ class Channel final : public ChannelInterface,
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) override;
+ CompletionQueue* CallbackCQ() override;
+
const grpc::string host_;
grpc_channel* const c_channel_; // owned
+
+ // mu_ protects callback_cq_ (the per-channel callbackable completion queue)
+ std::mutex mu_;
+
+ // callback_cq_ references the callbackable completion queue associated
+ // with this channel (if any). It is set on the first call to CallbackCQ().
+ // It is _not owned_ by the channel; ownership belongs with its internal
+ // shutdown callback tag (invoked when the CQ is fully shutdown).
+ CompletionQueue* callback_cq_ = nullptr;
};
} // namespace grpc
diff --git a/include/grpcpp/generic/generic_stub.h b/include/grpcpp/generic/generic_stub.h
index 92405a43fa..d509d9a520 100644
--- a/include/grpcpp/generic/generic_stub.h
+++ b/include/grpcpp/generic/generic_stub.h
@@ -19,9 +19,12 @@
#ifndef GRPCPP_GENERIC_GENERIC_STUB_H
#define GRPCPP_GENERIC_GENERIC_STUB_H
+#include <functional>
+
#include <grpcpp/support/async_stream.h>
#include <grpcpp/support/async_unary_call.h>
#include <grpcpp/support/byte_buffer.h>
+#include <grpcpp/support/status.h>
namespace grpc {
@@ -62,6 +65,26 @@ class GenericStub final {
ClientContext* context, const grpc::string& method, CompletionQueue* cq,
void* tag);
+ /// NOTE: class experimental_type is not part of the public API of this class
+ /// TODO(vjpai): Move these contents to the public API of GenericStub when
+ /// they are no longer experimental
+ class experimental_type {
+ public:
+ explicit experimental_type(GenericStub* stub) : stub_(stub) {}
+
+ void UnaryCall(ClientContext* context, const grpc::string& method,
+ const ByteBuffer* request, ByteBuffer* response,
+ std::function<void(Status)> on_completion);
+
+ private:
+ GenericStub* stub_;
+ };
+
+ /// NOTE: The function experimental() is not stable public API. It is a view
+ /// to the experimental components of this class. It may be changed or removed
+ /// at any time.
+ experimental_type experimental() { return experimental_type(this); }
+
private:
std::shared_ptr<ChannelInterface> channel_;
};
diff --git a/include/grpcpp/impl/codegen/async_stream.h b/include/grpcpp/impl/codegen/async_stream.h
index b306cd3604..6e58fd0eef 100644
--- a/include/grpcpp/impl/codegen/async_stream.h
+++ b/include/grpcpp/impl/codegen/async_stream.h
@@ -64,7 +64,7 @@ class ClientAsyncStreamingInterface {
/// earlier call to \a AsyncReaderInterface::Read that yielded a failed
/// result, e.g. cq->Next(&read_tag, &ok) filled in 'ok' with 'false').
///
- /// This function will return when either:
+ /// The tag will be returned when either:
/// - all incoming messages have been read and the server has returned
/// a status.
/// - the server has returned a non-OK status.
@@ -114,6 +114,9 @@ class AsyncWriterInterface {
/// queue BEFORE calling Write again.
/// This is thread-safe with respect to \a AsyncReaderInterface::Read
///
+ /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to
+ /// to deallocate once Write returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] tag The tag identifying the operation.
virtual void Write(const W& msg, void* tag) = 0;
@@ -127,6 +130,9 @@ class AsyncWriterInterface {
/// WriteOptions \a options is used to set the write options of this message.
/// This is thread-safe with respect to \a AsyncReaderInterface::Read
///
+ /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to
+ /// to deallocate once Write returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] tag The tag identifying the operation.
@@ -144,6 +150,9 @@ class AsyncWriterInterface {
/// the flow control window size. If \a msg size is larger than the window
/// size, it will be sent on wire without buffering.
///
+ /// gRPC doesn't take ownership or a reference to \a msg, so it is safe to
+ /// to deallocate once Write returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] tag The tag identifying the operation.
@@ -651,6 +660,9 @@ class ServerAsyncReaderInterface
/// metadata (if not sent already), response message, and status, or if
/// some failure occurred when trying to do so.
///
+ /// gRPC doesn't take ownership or a reference to \a msg or \a status, so it
+ /// is safe to to deallocate once Finish returns.
+ ///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of this call.
/// \param[in] msg To be sent to the client as the response for this call.
@@ -671,6 +683,9 @@ class ServerAsyncReaderInterface
/// metadata (if not sent already), and status, or if some failure occurred
/// when trying to do so.
///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once FinishWithError returns.
+ ///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of this call.
/// - Note: \a status must have a non-OK code.
@@ -718,6 +733,9 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
/// initial and trailing metadata.
///
/// Note: \a msg is not sent if \a status has a non-OK code.
+ ///
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once Finish returns.
void Finish(const W& msg, const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
@@ -744,6 +762,9 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
/// - also sends initial metadata if not alreay sent.
/// - uses the \a ServerContext associated with this call to send possible
/// initial and trailing metadata.
+ ///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once FinishWithError returns.
void FinishWithError(const Status& status, void* tag) override {
GPR_CODEGEN_ASSERT(!status.ok());
finish_ops_.set_output_tag(tag);
@@ -794,6 +815,9 @@ class ServerAsyncWriterInterface
/// metadata (if not sent already), response message, and status, or if
/// some failure occurred when trying to do so.
///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once Finish returns.
+ ///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of this call.
virtual void Finish(const Status& status, void* tag) = 0;
@@ -805,6 +829,9 @@ class ServerAsyncWriterInterface
/// WriteAndFinish is equivalent of performing WriteLast and Finish
/// in a single step.
///
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once WriteAndFinish returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] status The Status that server returns to client.
@@ -868,6 +895,9 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
/// for sending trailing (and initial) metadata to the client.
///
/// Note: \a status must have an OK code.
+ ///
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once WriteAndFinish returns.
void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
void* tag) override {
write_ops_.set_output_tag(tag);
@@ -886,6 +916,9 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
///
/// Note: there are no restrictions are the code of
/// \a status,it may be non-OK
+ ///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once Finish returns.
void Finish(const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&finish_ops_);
@@ -945,6 +978,9 @@ class ServerAsyncReaderWriterInterface
/// metadata (if not sent already), response message, and status, or if some
/// failure occurred when trying to do so.
///
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once Finish returns.
+ ///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of this call.
virtual void Finish(const Status& status, void* tag) = 0;
@@ -956,6 +992,9 @@ class ServerAsyncReaderWriterInterface
/// WriteAndFinish is equivalent of performing WriteLast and Finish in a
/// single step.
///
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once WriteAndFinish returns.
+ ///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
/// \param[in] status The Status that server returns to client.
@@ -1027,6 +1066,9 @@ class ServerAsyncReaderWriter final
/// for sending trailing (and initial) metadata to the client.
///
/// Note: \a status must have an OK code.
+ //
+ /// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
+ /// is safe to to deallocate once WriteAndFinish returns.
void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
void* tag) override {
write_ops_.set_output_tag(tag);
@@ -1045,6 +1087,9 @@ class ServerAsyncReaderWriter final
///
/// Note: there are no restrictions are the code of \a status,
/// it may be non-OK
+ //
+ /// gRPC doesn't take ownership or a reference to \a status, so it is safe to
+ /// to deallocate once Finish returns.
void Finish(const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
EnsureInitialMetadataSent(&finish_ops_);
diff --git a/include/grpcpp/impl/codegen/call.h b/include/grpcpp/impl/codegen/call.h
index e94adada94..7cadea0055 100644
--- a/include/grpcpp/impl/codegen/call.h
+++ b/include/grpcpp/impl/codegen/call.h
@@ -599,6 +599,11 @@ class CallOpSetInterface : public CompletionQueueTag {
/// Fills in grpc_op, starting from ops[*nops] and moving
/// upwards.
virtual void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) = 0;
+
+ /// Get the tag to be used at the core completion queue. Generally, the
+ /// value of cq_tag will be "this". However, it can be overridden if we
+ /// want core to process the tag differently (e.g., as a core callback)
+ virtual void* cq_tag() = 0;
};
/// Primary implementation of CallOpSetInterface.
@@ -618,7 +623,7 @@ class CallOpSet : public CallOpSetInterface,
public Op5,
public Op6 {
public:
- CallOpSet() : return_tag_(this), call_(nullptr) {}
+ CallOpSet() : cq_tag_(this), return_tag_(this), call_(nullptr) {}
void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) override {
this->Op1::AddOp(ops, nops);
this->Op2::AddOp(ops, nops);
@@ -645,7 +650,16 @@ class CallOpSet : public CallOpSetInterface,
void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
+ void* cq_tag() override { return cq_tag_; }
+
+ /// set_cq_tag is used to provide a different core CQ tag than "this".
+ /// This is used for callback-based tags, where the core tag is the core
+ /// callback function. It does not change the use or behavior of any other
+ /// function (such as FinalizeResult)
+ void set_cq_tag(void* cq_tag) { cq_tag_ = cq_tag; }
+
private:
+ void* cq_tag_;
void* return_tag_;
grpc_call* call_;
};
diff --git a/include/grpcpp/impl/codegen/callback_common.h b/include/grpcpp/impl/codegen/callback_common.h
new file mode 100644
index 0000000000..ca2f867d04
--- /dev/null
+++ b/include/grpcpp/impl/codegen/callback_common.h
@@ -0,0 +1,164 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_IMPL_CODEGEN_CALLBACK_COMMON_H
+#define GRPCPP_IMPL_CODEGEN_CALLBACK_COMMON_H
+
+#include <functional>
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+namespace internal {
+
+/// An exception-safe way of invoking a user-specified callback function
+template <class Func, class Arg>
+void CatchingCallback(Func&& func, Arg&& arg) {
+#if GRPC_ALLOW_EXCEPTIONS
+ try {
+ func(arg);
+ } catch (...) {
+ // nothing to return or change here, just don't crash the library
+ }
+#else // GRPC_ALLOW_EXCEPTIONS
+ func(arg);
+#endif // GRPC_ALLOW_EXCEPTIONS
+}
+
+// The contract on these tags is that they are single-shot. They must be
+// constructed and then fired at exactly one point. There is no expectation
+// that they can be reused without reconstruction.
+
+class CallbackWithStatusTag
+ : public grpc_experimental_completion_queue_functor {
+ public:
+ // always allocated against a call arena, no memory free required
+ static void operator delete(void* ptr, std::size_t size) {
+ assert(size == sizeof(CallbackWithStatusTag));
+ }
+
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
+
+ CallbackWithStatusTag(grpc_call* call, std::function<void(Status)> f,
+ CompletionQueueTag* ops)
+ : call_(call), func_(std::move(f)), ops_(ops) {
+ g_core_codegen_interface->grpc_call_ref(call);
+ functor_run = &CallbackWithStatusTag::StaticRun;
+ }
+ ~CallbackWithStatusTag() {}
+ Status* status_ptr() { return &status_; }
+
+ // force_run can not be performed on a tag if operations using this tag
+ // have been sent to PerformOpsOnCall. It is intended for error conditions
+ // that are detected before the operations are internally processed.
+ void force_run(Status s) {
+ status_ = std::move(s);
+ Run(true);
+ }
+
+ private:
+ grpc_call* call_;
+ std::function<void(Status)> func_;
+ CompletionQueueTag* ops_;
+ Status status_;
+
+ static void StaticRun(grpc_experimental_completion_queue_functor* cb,
+ int ok) {
+ static_cast<CallbackWithStatusTag*>(cb)->Run(static_cast<bool>(ok));
+ }
+ void Run(bool ok) {
+ void* ignored = ops_;
+
+ GPR_CODEGEN_ASSERT(ops_->FinalizeResult(&ignored, &ok));
+ GPR_CODEGEN_ASSERT(ignored == ops_);
+
+ // Last use of func_ or status_, so ok to move them out
+ CatchingCallback(std::move(func_), std::move(status_));
+
+ func_ = nullptr; // reset to clear this out for sure
+ status_ = Status(); // reset to clear this out for sure
+ g_core_codegen_interface->grpc_call_unref(call_);
+ }
+};
+
+class CallbackWithSuccessTag
+ : public grpc_experimental_completion_queue_functor {
+ public:
+ // always allocated against a call arena, no memory free required
+ static void operator delete(void* ptr, std::size_t size) {
+ assert(size == sizeof(CallbackWithSuccessTag));
+ }
+
+ // This operator should never be called as the memory should be freed as part
+ // of the arena destruction. It only exists to provide a matching operator
+ // delete to the operator new so that some compilers will not complain (see
+ // https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
+ // there are no tests catching the compiler warning.
+ static void operator delete(void*, void*) { assert(0); }
+
+ CallbackWithSuccessTag(grpc_call* call, std::function<void(bool)> f,
+ CompletionQueueTag* ops)
+ : call_(call), func_(std::move(f)), ops_(ops) {
+ g_core_codegen_interface->grpc_call_ref(call);
+ functor_run = &CallbackWithSuccessTag::StaticRun;
+ }
+
+ CompletionQueueTag* ops() { return ops_; }
+
+ // force_run can not be performed on a tag if operations using this tag
+ // have been sent to PerformOpsOnCall. It is intended for error conditions
+ // that are detected before the operations are internally processed.
+ void force_run(bool ok) { Run(ok); }
+
+ private:
+ grpc_call* call_;
+ std::function<void(bool)> func_;
+ CompletionQueueTag* ops_;
+
+ static void StaticRun(grpc_experimental_completion_queue_functor* cb,
+ int ok) {
+ static_cast<CallbackWithSuccessTag*>(cb)->Run(static_cast<bool>(ok));
+ }
+ void Run(bool ok) {
+ void* ignored = ops_;
+ bool new_ok = ok;
+ GPR_CODEGEN_ASSERT(ops_->FinalizeResult(&ignored, &new_ok));
+ GPR_CODEGEN_ASSERT(ignored == ops_);
+
+ // Last use of func_, so ok to move it out for rvalue call above
+ CatchingCallback(std::move(func_), ok);
+
+ func_ = nullptr; // reset to clear this out for sure
+ g_core_codegen_interface->grpc_call_unref(call_);
+ }
+};
+
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_CALLBACK_COMMON_H
diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h
index ec1c6c25d8..b257acc1ab 100644
--- a/include/grpcpp/impl/codegen/channel_interface.h
+++ b/include/grpcpp/impl/codegen/channel_interface.h
@@ -41,6 +41,8 @@ class CallOpSetInterface;
class RpcMethod;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
+template <class InputMessage, class OutputMessage>
+class CallbackUnaryCallImpl;
template <class R>
class ClientAsyncReaderFactory;
template <class W>
@@ -103,6 +105,8 @@ class ChannelInterface {
friend class ::grpc::internal::ClientAsyncResponseReaderFactory;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
+ template <class InputMessage, class OutputMessage>
+ friend class ::grpc::internal::CallbackUnaryCallImpl;
friend class ::grpc::internal::RpcMethod;
virtual internal::Call CreateCall(const internal::RpcMethod& method,
ClientContext* context,
@@ -115,6 +119,16 @@ class ChannelInterface {
CompletionQueue* cq, void* tag) = 0;
virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) = 0;
+
+ // EXPERIMENTAL
+ // A method to get the callbackable completion queue associated with this
+ // channel. If the return value is nullptr, this channel doesn't support
+ // callback operations.
+ // TODO(vjpai): Consider a better default like using a global CQ
+ // Returns nullptr (rather than being pure) since this is a new method
+ // and adding a new pure method to an interface would be a breaking change
+ // (even though this is private and non-API)
+ virtual CompletionQueue* CallbackCQ() { return nullptr; }
};
} // namespace grpc
diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h
new file mode 100644
index 0000000000..4d4faea063
--- /dev/null
+++ b/include/grpcpp/impl/codegen/client_callback.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
+#define GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
+
+#include <functional>
+
+#include <grpcpp/impl/codegen/call.h>
+#include <grpcpp/impl/codegen/callback_common.h>
+#include <grpcpp/impl/codegen/channel_interface.h>
+#include <grpcpp/impl/codegen/config.h>
+#include <grpcpp/impl/codegen/core_codegen_interface.h>
+#include <grpcpp/impl/codegen/status.h>
+
+namespace grpc {
+
+class Channel;
+class ClientContext;
+class CompletionQueue;
+
+namespace internal {
+class RpcMethod;
+
+/// Perform a callback-based unary call
+/// TODO(vjpai): Combine as much as possible with the blocking unary call code
+template <class InputMessage, class OutputMessage>
+void CallbackUnaryCall(ChannelInterface* channel, const RpcMethod& method,
+ ClientContext* context, const InputMessage* request,
+ OutputMessage* result,
+ std::function<void(Status)> on_completion) {
+ CallbackUnaryCallImpl<InputMessage, OutputMessage> x(
+ channel, method, context, request, result, on_completion);
+}
+
+template <class InputMessage, class OutputMessage>
+class CallbackUnaryCallImpl {
+ public:
+ CallbackUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method,
+ ClientContext* context, const InputMessage* request,
+ OutputMessage* result,
+ std::function<void(Status)> on_completion) {
+ CompletionQueue* cq = channel->CallbackCQ();
+ GPR_CODEGEN_ASSERT(cq != nullptr);
+ Call call(channel->CreateCall(method, context, cq));
+
+ using FullCallOpSet =
+ CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+ CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
+ CallOpClientSendClose, CallOpClientRecvStatus>;
+
+ auto* ops = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call.call(), sizeof(FullCallOpSet))) FullCallOpSet;
+
+ auto* tag = new (g_core_codegen_interface->grpc_call_arena_alloc(
+ call.call(), sizeof(CallbackWithStatusTag)))
+ CallbackWithStatusTag(call.call(), on_completion, ops);
+
+ // TODO(vjpai): Unify code with sync API as much as possible
+ Status s = ops->SendMessage(*request);
+ if (!s.ok()) {
+ tag->force_run(s);
+ return;
+ }
+ ops->SendInitialMetadata(context->send_initial_metadata_,
+ context->initial_metadata_flags());
+ ops->RecvInitialMetadata(context);
+ ops->RecvMessage(result);
+ ops->AllowNoMessage();
+ ops->ClientSendClose();
+ ops->ClientRecvStatus(context, tag->status_ptr());
+ ops->set_cq_tag(tag);
+ call.PerformOps(ops);
+ }
+};
+
+} // namespace internal
+} // namespace grpc
+
+#endif // GRPCPP_IMPL_CODEGEN_CLIENT_CALLBACK_H
diff --git a/include/grpcpp/impl/codegen/client_context.h b/include/grpcpp/impl/codegen/client_context.h
index c6c9540950..46635a541a 100644
--- a/include/grpcpp/impl/codegen/client_context.h
+++ b/include/grpcpp/impl/codegen/client_context.h
@@ -68,6 +68,8 @@ class CallOpClientRecvStatus;
class CallOpRecvInitialMetadata;
template <class InputMessage, class OutputMessage>
class BlockingUnaryCallImpl;
+template <class InputMessage, class OutputMessage>
+class CallbackUnaryCallImpl;
} // namespace internal
template <class R>
@@ -389,6 +391,8 @@ class ClientContext {
friend class ::grpc::ClientAsyncResponseReader;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
+ template <class InputMessage, class OutputMessage>
+ friend class ::grpc::internal::CallbackUnaryCallImpl;
// Used by friend class CallOpClientRecvStatus
void set_debug_error_string(const grpc::string& debug_error_string) {
diff --git a/include/grpcpp/impl/codegen/completion_queue.h b/include/grpcpp/impl/codegen/completion_queue.h
index 3f7d4fb765..f52f9a53be 100644
--- a/include/grpcpp/impl/codegen/completion_queue.h
+++ b/include/grpcpp/impl/codegen/completion_queue.h
@@ -274,6 +274,9 @@ class CompletionQueue : private GrpcLibraryCodegen {
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
+ // Friends that need access to constructor for callback CQ
+ friend class ::grpc::Channel;
+
/// EXPERIMENTAL
/// Creates a Thread Local cache to store the first event
/// On this completion queue queued from this thread. Once
diff --git a/include/grpcpp/impl/codegen/completion_queue_tag.h b/include/grpcpp/impl/codegen/completion_queue_tag.h
index ffb642c56b..304386a9ec 100644
--- a/include/grpcpp/impl/codegen/completion_queue_tag.h
+++ b/include/grpcpp/impl/codegen/completion_queue_tag.h
@@ -26,10 +26,25 @@ namespace internal {
class CompletionQueueTag {
public:
virtual ~CompletionQueueTag() {}
- /// Called prior to returning from Next(), return value is the status of the
- /// operation (return status is the default thing to do). If this function
- /// returns false, the tag is dropped and not returned from the completion
- /// queue
+
+ /// FinalizeResult must be called before informing user code that the
+ /// operation bound to the underlying core completion queue tag has
+ /// completed. In practice, this means:
+ ///
+ /// 1. For the sync API - before returning from Pluck
+ /// 2. For the CQ-based async API - before returning from Next
+ /// 3. For the callback-based API - before invoking the user callback
+ ///
+ /// This is the method that translates from core-side tag/status to
+ /// C++ API-observable tag/status.
+ ///
+ /// The return value is the status of the operation (returning status is the
+ /// general behavior of this function). If this function returns false, the
+ /// tag is dropped and not returned from the completion queue: this concept is
+ /// for events that are observed at core but not requested by the user
+ /// application (e.g., server shutdown, for server unimplemented method
+ /// responses, or for cases where a server-side RPC doesn't have a completion
+ /// notification registered using AsyncNotifyWhenDone)
virtual bool FinalizeResult(void** tag, bool* status) = 0;
};
} // namespace internal
diff --git a/include/grpcpp/support/client_callback.h b/include/grpcpp/support/client_callback.h
new file mode 100644
index 0000000000..063fdc4f85
--- /dev/null
+++ b/include/grpcpp/support/client_callback.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPCPP_SUPPORT_CLIENT_CALLBACK_H
+#define GRPCPP_SUPPORT_CLIENT_CALLBACK_H
+
+#include <grpcpp/impl/codegen/client_callback.h>
+
+#endif // GRPCPP_SUPPORT_CLIENT_CALLBACK_H
diff --git a/package.xml b/package.xml
index 9c0e078e92..fddc676d51 100644
--- a/package.xml
+++ b/package.xml
@@ -200,6 +200,7 @@
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_settings.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_window_update.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_mapping.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_settings.h" role="src" />
@@ -345,7 +346,6 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/error_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_epoll1_linux.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_epollex_linux.h" role="src" />
- <file baseinstalldir="/" name="src/core/lib/iomgr/ev_epollsig_linux.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/exec_ctx.h" role="src" />
@@ -491,7 +491,6 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/error.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_epoll1_linux.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_epollex_linux.cc" role="src" />
- <file baseinstalldir="/" name="src/core/lib/iomgr/ev_epollsig_linux.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_windows.cc" role="src" />
@@ -622,6 +621,7 @@
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_settings.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame_window_update.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_encoder.cc" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_mapping.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_parser.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/hpack_table.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_settings.cc" role="src" />
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 1e0c36451b..56716493dc 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -128,6 +128,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
"");
}
static const char* headers_strs[] = {
+ "functional",
"grpcpp/impl/codegen/async_generic_service.h",
"grpcpp/impl/codegen/async_stream.h",
"grpcpp/impl/codegen/async_unary_call.h",
@@ -547,6 +548,116 @@ void PrintHeaderClientMethod(grpc_generator::Printer* printer,
}
}
+void PrintHeaderClientMethodCallbackInterfacesStart(
+ grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string>* vars) {
+ // This declares the interface for the callback-based API. The components
+ // are pure; even though this is new (post-1.0) API, it can be pure because
+ // it is an entirely new interface that happens to be scoped within
+ // StubInterface, not new additions to StubInterface itself
+ printer->Print("class experimental_async_interface {\n");
+ // All methods in this new interface are public. There is no need for private
+ // "Raw" methods since the callback-based API returns unowned raw pointers
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print("virtual ~experimental_async_interface() {}\n");
+}
+
+void PrintHeaderClientMethodCallbackInterfaces(
+ grpc_generator::Printer* printer, const grpc_generator::Method* method,
+ std::map<grpc::string, grpc::string>* vars, bool is_public) {
+ // Reserve is_public for future expansion
+ assert(is_public);
+
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "virtual void $Method$(::grpc::ClientContext* context, "
+ "const $Request$* request, $Response$* response, "
+ "std::function<void(::grpc::Status)>) = 0;\n");
+ } else if (ClientOnlyStreaming(method)) {
+ // TODO(vjpai): Add support for client-side streaming
+ } else if (ServerOnlyStreaming(method)) {
+ // TODO(vjpai): Add support for server-side streaming
+ } else if (method->BidiStreaming()) {
+ // TODO(vjpai): Add support for bidi streaming
+ }
+}
+
+void PrintHeaderClientMethodCallbackInterfacesEnd(
+ grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string>* vars) {
+ printer->Outdent();
+ printer->Print("};\n");
+
+ // Declare a function to give the async stub contents. It can't be pure
+ // since this is a new API in StubInterface, but it is meaningless by default
+ // (since any stub that wants to use it must have its own implementation of
+ // the callback functions therein), so make the default return value nullptr.
+ // Intentionally include the word "class" to avoid possible shadowing.
+ printer->Print(
+ "virtual class experimental_async_interface* experimental_async() { "
+ "return nullptr; }\n");
+}
+
+void PrintHeaderClientMethodCallbackStart(
+ grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string>* vars) {
+ // This declares the stub entry for the callback-based API.
+ printer->Print("class experimental_async final :\n");
+ printer->Print(" public StubInterface::experimental_async_interface {\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+}
+
+void PrintHeaderClientMethodCallback(grpc_generator::Printer* printer,
+ const grpc_generator::Method* method,
+ std::map<grpc::string, grpc::string>* vars,
+ bool is_public) {
+ // Reserve is_public for future expansion
+ assert(is_public);
+
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "void $Method$(::grpc::ClientContext* context, "
+ "const $Request$* request, $Response$* response, "
+ "std::function<void(::grpc::Status)>) override;\n");
+ } else if (ClientOnlyStreaming(method)) {
+ // TODO(vjpai): Add support for client-side streaming
+ } else if (ServerOnlyStreaming(method)) {
+ // TODO(vjpai): Add support for server-side streaming
+ } else if (method->BidiStreaming()) {
+ // TODO(vjpai): Add support for bidi streaming
+ }
+}
+
+void PrintHeaderClientMethodCallbackEnd(
+ grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string>* vars) {
+ printer->Outdent();
+ printer->Print(" private:\n");
+ printer->Indent();
+ printer->Print("friend class Stub;\n");
+ printer->Print("explicit experimental_async(Stub* stub): stub_(stub) { }\n");
+ // include a function with a dummy use of stub_ to avoid an unused
+ // private member warning for service with no methods
+ printer->Print("Stub* stub() { return stub_; }\n");
+ printer->Print("Stub* stub_;\n");
+ printer->Outdent();
+ printer->Print("};\n");
+
+ printer->Print(
+ "class experimental_async_interface* experimental_async() override { "
+ "return &async_stub_; }\n");
+}
+
void PrintHeaderClientMethodData(grpc_generator::Printer* printer,
const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) {
@@ -951,6 +1062,14 @@ void PrintHeaderService(grpc_generator::Printer* printer,
true);
printer->Print(service->method(i)->GetTrailingComments("//").c_str());
}
+ PrintHeaderClientMethodCallbackInterfacesStart(printer, vars);
+ for (int i = 0; i < service->method_count(); ++i) {
+ printer->Print(service->method(i)->GetLeadingComments("//").c_str());
+ PrintHeaderClientMethodCallbackInterfaces(printer, service->method(i).get(),
+ vars, true);
+ printer->Print(service->method(i)->GetTrailingComments("//").c_str());
+ }
+ PrintHeaderClientMethodCallbackInterfacesEnd(printer, vars);
printer->Outdent();
printer->Print("private:\n");
printer->Indent();
@@ -970,10 +1089,17 @@ void PrintHeaderService(grpc_generator::Printer* printer,
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
}
+ PrintHeaderClientMethodCallbackStart(printer, vars);
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethodCallback(printer, service->method(i).get(), vars,
+ true);
+ }
+ PrintHeaderClientMethodCallbackEnd(printer, vars);
printer->Outdent();
printer->Print("\n private:\n");
printer->Indent();
printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n");
+ printer->Print("class experimental_async async_stub_{this};\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethod(printer, service->method(i).get(), vars, false);
}
@@ -1199,10 +1325,12 @@ grpc::string GetSourceIncludes(grpc_generator::File* file,
std::map<grpc::string, grpc::string> vars;
static const char* headers_strs[] = {
+ "functional",
"grpcpp/impl/codegen/async_stream.h",
"grpcpp/impl/codegen/async_unary_call.h",
"grpcpp/impl/codegen/channel_interface.h",
"grpcpp/impl/codegen/client_unary_call.h",
+ "grpcpp/impl/codegen/client_callback.h",
"grpcpp/impl/codegen/method_handler_impl.h",
"grpcpp/impl/codegen/rpc_service_method.h",
"grpcpp/impl/codegen/service_type.h",
@@ -1247,6 +1375,17 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
" return ::grpc::internal::BlockingUnaryCall"
"(channel_.get(), rpcmethod_$Method$_, "
"context, request, response);\n}\n\n");
+
+ printer->Print(*vars,
+ "void $ns$$Service$::Stub::experimental_async::$Method$("
+ "::grpc::ClientContext* context, "
+ "const $Request$* request, $Response$* response, "
+ "std::function<void(::grpc::Status)> f) {\n");
+ printer->Print(*vars,
+ " return ::grpc::internal::CallbackUnaryCall"
+ "(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
+ "context, request, response, std::move(f));\n}\n\n");
+
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@@ -1277,6 +1416,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"rpcmethod_$Method$_, "
"context, response);\n"
"}\n\n");
+
+ // TODO(vjpai): Add callback version
+
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@@ -1308,6 +1450,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"rpcmethod_$Method$_, "
"context, request);\n"
"}\n\n");
+
+ // TODO(vjpai): Add callback version
+
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@@ -1339,6 +1484,9 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"rpcmethod_$Method$_, "
"context);\n"
"}\n\n");
+
+ // TODO(vjpai): Add callback version
+
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
diff --git a/src/compiler/ruby_generator.cc b/src/compiler/ruby_generator.cc
index c7af9c38fa..e39d8be5d4 100644
--- a/src/compiler/ruby_generator.cc
+++ b/src/compiler/ruby_generator.cc
@@ -160,12 +160,20 @@ grpc::string GetServices(const FileDescriptor* file) {
return output;
}
+ std::string package_name;
+
+ if (file->options().has_ruby_package()) {
+ package_name = file->options().ruby_package();
+ } else {
+ package_name = file->package();
+ }
+
// Write out a file header.
std::map<grpc::string, grpc::string> header_comment_vars = ListToDict({
"file.name",
file->name(),
"file.package",
- file->package(),
+ package_name,
});
out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print(header_comment_vars,
@@ -190,7 +198,7 @@ grpc::string GetServices(const FileDescriptor* file) {
// Write out services within the modules
out.Print("\n");
- std::vector<grpc::string> modules = Split(file->package(), '.');
+ std::vector<grpc::string> modules = Split(package_name, '.');
for (size_t i = 0; i < modules.size(); ++i) {
std::map<grpc::string, grpc::string> module_vars = ListToDict({
"module.name",
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index 1ee1925a25..0061190016 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -852,10 +852,12 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked(
}
} else {
// No valid initial response or serverlist found.
+ char* response_slice_str =
+ grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX);
gpr_log(GPR_ERROR,
"[grpclb %p] Invalid LB response received: '%s'. Ignoring.",
- grpclb_policy,
- grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX));
+ grpclb_policy, response_slice_str);
+ gpr_free(response_slice_str);
}
grpc_slice_unref_internal(response_slice);
if (!grpclb_policy->shutting_down_) {
diff --git a/src/core/ext/filters/client_channel/parse_address.cc b/src/core/ext/filters/client_channel/parse_address.cc
index 7e726dd562..707beb8876 100644
--- a/src/core/ext/filters/client_channel/parse_address.cc
+++ b/src/core/ext/filters/client_channel/parse_address.cc
@@ -129,30 +129,37 @@ bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
size_t host_without_scope_len = static_cast<size_t>(host_end - host);
uint32_t sin6_scope_id = 0;
if (host_without_scope_len > GRPC_INET6_ADDRSTRLEN) {
- gpr_log(GPR_ERROR,
- "invalid ipv6 address length %zu. Length cannot be greater than "
- "GRPC_INET6_ADDRSTRLEN i.e %d)",
- host_without_scope_len, GRPC_INET6_ADDRSTRLEN);
+ if (log_errors) {
+ gpr_log(
+ GPR_ERROR,
+ "invalid ipv6 address length %zu. Length cannot be greater than "
+ "GRPC_INET6_ADDRSTRLEN i.e %d)",
+ host_without_scope_len, GRPC_INET6_ADDRSTRLEN);
+ }
goto done;
}
strncpy(host_without_scope, host, host_without_scope_len);
host_without_scope[host_without_scope_len] = '\0';
if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) ==
0) {
- gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
+ if (log_errors) {
+ gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
+ }
goto done;
}
if (gpr_parse_bytes_to_uint32(host_end + 1,
strlen(host) - host_without_scope_len - 1,
&sin6_scope_id) == 0) {
- gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1);
+ if (log_errors) {
+ gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1);
+ }
goto done;
}
// Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
in6->sin6_scope_id = sin6_scope_id;
} else {
if (grpc_inet_pton(GRPC_AF_INET6, host, &in6->sin6_addr) == 0) {
- gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
+ if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
goto done;
}
}
@@ -197,3 +204,12 @@ bool grpc_parse_uri(const grpc_uri* uri, grpc_resolved_address* resolved_addr) {
gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme);
return false;
}
+
+uint16_t grpc_strhtons(const char* port) {
+ if (strcmp(port, "http") == 0) {
+ return htons(80);
+ } else if (strcmp(port, "https") == 0) {
+ return htons(443);
+ }
+ return htons(static_cast<unsigned short>(atoi(port)));
+}
diff --git a/src/core/ext/filters/client_channel/parse_address.h b/src/core/ext/filters/client_channel/parse_address.h
index 9a88b66edc..c2af0e6c49 100644
--- a/src/core/ext/filters/client_channel/parse_address.h
+++ b/src/core/ext/filters/client_channel/parse_address.h
@@ -47,4 +47,7 @@ bool grpc_parse_ipv4_hostport(const char* hostport, grpc_resolved_address* addr,
bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
bool log_errors);
+/* Converts named or numeric port to a uint16 suitable for use in a sockaddr. */
+uint16_t grpc_strhtons(const char* port);
+
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
index 485998f5e4..4c795c34c8 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
@@ -87,15 +87,6 @@ typedef struct grpc_ares_hostbyname_request {
static void do_basic_init(void) { gpr_mu_init(&g_init_mu); }
-static uint16_t strhtons(const char* port) {
- if (strcmp(port, "http") == 0) {
- return htons(80);
- } else if (strcmp(port, "https") == 0) {
- return htons(443);
- }
- return htons(static_cast<unsigned short>(atoi(port)));
-}
-
static void log_address_sorting_list(grpc_lb_addresses* lb_addrs,
const char* input_output_str) {
for (size_t i = 0; i < lb_addrs->num_addresses; i++) {
@@ -139,12 +130,6 @@ void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs) {
}
}
-/* Allow tests to access grpc_ares_wrapper_address_sorting_sort */
-void grpc_cares_wrapper_test_only_address_sorting_sort(
- grpc_lb_addresses* lb_addrs) {
- grpc_cares_wrapper_address_sorting_sort(lb_addrs);
-}
-
static void grpc_ares_request_ref_locked(grpc_ares_request* r) {
r->pending_queries++;
}
@@ -371,7 +356,8 @@ done:
grpc_ares_request_unref_locked(r);
}
-static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
+static grpc_ares_request*
+grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
@@ -454,12 +440,12 @@ static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
}
r->pending_queries = 1;
if (grpc_ares_query_ipv6()) {
- hr = create_hostbyname_request_locked(r, host, strhtons(port),
+ hr = create_hostbyname_request_locked(r, host, grpc_strhtons(port),
false /* is_balancer */);
ares_gethostbyname(*channel, hr->host, AF_INET6, on_hostbyname_done_locked,
hr);
}
- hr = create_hostbyname_request_locked(r, host, strhtons(port),
+ hr = create_hostbyname_request_locked(r, host, grpc_strhtons(port),
false /* is_balancer */);
ares_gethostbyname(*channel, hr->host, AF_INET, on_hostbyname_done_locked,
hr);
@@ -494,6 +480,79 @@ error_cleanup:
return nullptr;
}
+static bool inner_resolve_as_ip_literal_locked(const char* name,
+ const char* default_port,
+ grpc_lb_addresses** addrs,
+ char** host, char** port,
+ char** hostport) {
+ gpr_split_host_port(name, host, port);
+ if (*host == nullptr) {
+ gpr_log(GPR_ERROR,
+ "Failed to parse %s to host:port while attempting to resolve as ip "
+ "literal.",
+ name);
+ return false;
+ }
+ if (*port == nullptr) {
+ if (default_port == nullptr) {
+ gpr_log(GPR_ERROR,
+ "No port or default port for %s while attempting to resolve as "
+ "ip literal.",
+ name);
+ return false;
+ }
+ *port = gpr_strdup(default_port);
+ }
+ grpc_resolved_address addr;
+ GPR_ASSERT(gpr_join_host_port(hostport, *host, atoi(*port)));
+ if (grpc_parse_ipv4_hostport(*hostport, &addr, false /* log errors */) ||
+ grpc_parse_ipv6_hostport(*hostport, &addr, false /* log errors */)) {
+ GPR_ASSERT(*addrs == nullptr);
+ *addrs = grpc_lb_addresses_create(1, nullptr);
+ grpc_lb_addresses_set_address(
+ *addrs, 0, addr.addr, addr.len, false /* is_balancer */,
+ nullptr /* balancer_name */, nullptr /* user_data */);
+ return true;
+ }
+ return false;
+}
+
+static bool resolve_as_ip_literal_locked(const char* name,
+ const char* default_port,
+ grpc_lb_addresses** addrs) {
+ char* host = nullptr;
+ char* port = nullptr;
+ char* hostport = nullptr;
+ bool out = inner_resolve_as_ip_literal_locked(name, default_port, addrs,
+ &host, &port, &hostport);
+ gpr_free(host);
+ gpr_free(port);
+ gpr_free(hostport);
+ return out;
+}
+
+static grpc_ares_request* grpc_dns_lookup_ares_locked_impl(
+ const char* dns_server, const char* name, const char* default_port,
+ grpc_pollset_set* interested_parties, grpc_closure* on_done,
+ grpc_lb_addresses** addrs, bool check_grpclb, char** service_config_json,
+ grpc_combiner* combiner) {
+ // Early out if the target is an ipv4 or ipv6 literal.
+ if (resolve_as_ip_literal_locked(name, default_port, addrs)) {
+ GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
+ return nullptr;
+ }
+ // Early out if the target is localhost and we're on Windows.
+ if (grpc_ares_maybe_resolve_localhost_manually_locked(name, default_port,
+ addrs)) {
+ GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
+ return nullptr;
+ }
+ // Look up name using c-ares lib.
+ return grpc_dns_lookup_ares_continue_after_check_localhost_and_ip_literals_locked(
+ dns_server, name, default_port, interested_parties, on_done, addrs,
+ check_grpclb, service_config_json, combiner);
+}
+
grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
const char* dns_server, const char* name, const char* default_port,
grpc_pollset_set* interested_parties, grpc_closure* on_done,
@@ -502,7 +561,9 @@ grpc_ares_request* (*grpc_dns_lookup_ares_locked)(
void grpc_cancel_ares_request(grpc_ares_request* r) {
if (grpc_dns_lookup_ares_locked == grpc_dns_lookup_ares_locked_impl) {
- grpc_ares_ev_driver_shutdown_locked(r->ev_driver);
+ if (r != nullptr) {
+ grpc_ares_ev_driver_shutdown_locked(r->ev_driver);
+ }
}
}
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
index ca5779e1d7..1bc457d4cf 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
@@ -81,9 +81,15 @@ void grpc_ares_complete_request_locked(grpc_ares_request* request);
/* E.g., return false if ipv6 is known to not be available. */
bool grpc_ares_query_ipv6();
-/* Exposed only for testing */
-void grpc_cares_wrapper_test_only_address_sorting_sort(
- grpc_lb_addresses* lb_addrs);
+/* Maybe (depending on the current platform) checks if "name" matches
+ * "localhost" and if so fills in addrs with the correct sockaddr structures.
+ * Returns a bool indicating whether or not such an action was performed.
+ * See https://github.com/grpc/grpc/issues/15158. */
+bool grpc_ares_maybe_resolve_localhost_manually_locked(
+ const char* name, const char* default_port, grpc_lb_addresses** addrs);
+
+/* Sorts destinations in lb_addrs according to RFC 6724. */
+void grpc_cares_wrapper_address_sorting_sort(grpc_lb_addresses* lb_addrs);
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \
*/
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
index 23c0fec74f..639eec2323 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
@@ -26,4 +26,9 @@
bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); }
+bool grpc_ares_maybe_resolve_localhost_manually_locked(
+ const char* name, const char* default_port, grpc_lb_addresses** addrs) {
+ return false;
+}
+
#endif /* GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
index ee827e284e..7e34784691 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
@@ -21,9 +21,79 @@
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && defined(GPR_WINDOWS)
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
+#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/socket_windows.h"
bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); }
+static bool inner_maybe_resolve_localhost_manually_locked(
+ const char* name, const char* default_port, grpc_lb_addresses** addrs,
+ char** host, char** port) {
+ gpr_split_host_port(name, host, port);
+ if (*host == nullptr) {
+ gpr_log(GPR_ERROR,
+ "Failed to parse %s into host:port during Windows localhost "
+ "resolution check.",
+ name);
+ return false;
+ }
+ if (*port == nullptr) {
+ if (default_port == nullptr) {
+ gpr_log(GPR_ERROR,
+ "No port or default port for %s during Windows localhost "
+ "resolution check.",
+ name);
+ return false;
+ }
+ *port = gpr_strdup(default_port);
+ }
+ if (gpr_stricmp(*host, "localhost") == 0) {
+ GPR_ASSERT(*addrs == nullptr);
+ *addrs = grpc_lb_addresses_create(2, nullptr);
+ uint16_t numeric_port = grpc_strhtons(*port);
+ // Append the ipv6 loopback address.
+ struct sockaddr_in6 ipv6_loopback_addr;
+ memset(&ipv6_loopback_addr, 0, sizeof(ipv6_loopback_addr));
+ ((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1;
+ ipv6_loopback_addr.sin6_family = AF_INET6;
+ ipv6_loopback_addr.sin6_port = numeric_port;
+ grpc_lb_addresses_set_address(
+ *addrs, 0, &ipv6_loopback_addr, sizeof(ipv6_loopback_addr),
+ false /* is_balancer */, nullptr /* balancer_name */,
+ nullptr /* user_data */);
+ // Append the ipv4 loopback address.
+ struct sockaddr_in ipv4_loopback_addr;
+ memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr));
+ ((char*)&ipv4_loopback_addr.sin_addr)[0] = 0x7f;
+ ((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01;
+ ipv4_loopback_addr.sin_family = AF_INET;
+ ipv4_loopback_addr.sin_port = numeric_port;
+ grpc_lb_addresses_set_address(
+ *addrs, 1, &ipv4_loopback_addr, sizeof(ipv4_loopback_addr),
+ false /* is_balancer */, nullptr /* balancer_name */,
+ nullptr /* user_data */);
+ // Let the address sorter figure out which one should be tried first.
+ grpc_cares_wrapper_address_sorting_sort(*addrs);
+ return true;
+ }
+ return false;
+}
+
+bool grpc_ares_maybe_resolve_localhost_manually_locked(
+ const char* name, const char* default_port, grpc_lb_addresses** addrs) {
+ char* host = nullptr;
+ char* port = nullptr;
+ bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port,
+ addrs, &host, &port);
+ gpr_free(host);
+ gpr_free(port);
+ return out;
+}
+
#endif /* GRPC_ARES == 1 && defined(GPR_WINDOWS) */
diff --git a/src/core/ext/filters/client_channel/subchannel_index.cc b/src/core/ext/filters/client_channel/subchannel_index.cc
index f2b6c24e8e..1c23a6c4be 100644
--- a/src/core/ext/filters/client_channel/subchannel_index.cc
+++ b/src/core/ext/filters/client_channel/subchannel_index.cc
@@ -42,7 +42,7 @@ struct grpc_subchannel_key {
grpc_subchannel_args args;
};
-static gpr_atm g_force_creation = false;
+static bool g_force_creation = false;
static grpc_subchannel_key* create_key(
const grpc_subchannel_args* args,
@@ -74,7 +74,7 @@ static grpc_subchannel_key* subchannel_key_copy(grpc_subchannel_key* k) {
int grpc_subchannel_key_compare(const grpc_subchannel_key* a,
const grpc_subchannel_key* b) {
// To pretend the keys are different, return a non-zero value.
- if (GPR_UNLIKELY(gpr_atm_no_barrier_load(&g_force_creation))) return 1;
+ if (GPR_UNLIKELY(g_force_creation)) return 1;
int c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
if (c != 0) return c;
if (a->args.filter_count > 0) {
@@ -251,5 +251,5 @@ void grpc_subchannel_index_unregister(grpc_subchannel_key* key,
}
void grpc_subchannel_index_test_only_set_force_creation(bool force_creation) {
- gpr_atm_no_barrier_store(&g_force_creation, force_creation);
+ g_force_creation = force_creation;
}
diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc
index 91fa163fec..cd459e47cd 100644
--- a/src/core/ext/filters/http/client/http_client_filter.cc
+++ b/src/core/ext/filters/http/client/http_client_filter.cc
@@ -58,6 +58,8 @@ struct call_data {
grpc_metadata_batch* recv_trailing_metadata;
grpc_closure* original_recv_trailing_metadata_ready;
grpc_closure recv_trailing_metadata_ready;
+ grpc_error* recv_trailing_metadata_error;
+ bool seen_recv_trailing_metadata_ready;
// State for handling send_message ops.
grpc_transport_stream_op_batch* send_message_batch;
size_t send_message_bytes_read;
@@ -157,12 +159,27 @@ static void recv_initial_metadata_ready(void* user_data, grpc_error* error) {
} else {
GRPC_ERROR_REF(error);
}
- GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready, error);
+ grpc_closure* closure = calld->original_recv_initial_metadata_ready;
+ calld->original_recv_initial_metadata_ready = nullptr;
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(
+ calld->call_combiner, &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error, "continue recv_trailing_metadata");
+ }
+ GRPC_CLOSURE_RUN(closure, error);
}
static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
call_data* calld = static_cast<call_data*>(elem->call_data);
+ if (calld->original_recv_initial_metadata_ready != nullptr) {
+ calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error);
+ calld->seen_recv_trailing_metadata_ready = true;
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring recv_trailing_metadata_ready until "
+ "after recv_initial_metadata_ready");
+ return;
+ }
if (error == GRPC_ERROR_NONE) {
error =
client_filter_incoming_metadata(elem, calld->recv_trailing_metadata);
diff --git a/src/core/ext/filters/http/server/http_server_filter.cc b/src/core/ext/filters/http/server/http_server_filter.cc
index 1b3426b120..436ea09d94 100644
--- a/src/core/ext/filters/http/server/http_server_filter.cc
+++ b/src/core/ext/filters/http/server/http_server_filter.cc
@@ -63,8 +63,11 @@ struct call_data {
grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message;
bool seen_recv_message_ready;
+ // State for intercepting recv_trailing_metadata
grpc_closure recv_trailing_metadata_ready;
grpc_closure* original_recv_trailing_metadata_ready;
+ grpc_error* recv_trailing_metadata_ready_error;
+ bool seen_recv_trailing_metadata_ready;
};
struct channel_data {
@@ -301,6 +304,13 @@ static void hs_recv_initial_metadata_ready(void* user_data, grpc_error* err) {
} else {
GRPC_ERROR_REF(err);
}
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_ready_error,
+ "resuming hs_recv_trailing_metadata_ready from "
+ "hs_recv_initial_metadata_ready");
+ }
GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready, err);
}
@@ -331,6 +341,14 @@ static void hs_recv_message_ready(void* user_data, grpc_error* err) {
static void hs_recv_trailing_metadata_ready(void* user_data, grpc_error* err) {
grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
call_data* calld = static_cast<call_data*>(elem->call_data);
+ if (!calld->seen_recv_initial_metadata_ready) {
+ calld->recv_trailing_metadata_ready_error = GRPC_ERROR_REF(err);
+ calld->seen_recv_trailing_metadata_ready = true;
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring hs_recv_trailing_metadata_ready until "
+ "ater hs_recv_initial_metadata_ready");
+ return;
+ }
err = grpc_error_add_child(
GRPC_ERROR_REF(err),
GRPC_ERROR_REF(calld->recv_initial_metadata_ready_error));
diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc
index c17df86f3d..2d3b16d992 100644
--- a/src/core/ext/filters/message_size/message_size_filter.cc
+++ b/src/core/ext/filters/message_size/message_size_filter.cc
@@ -108,6 +108,8 @@ struct call_data {
grpc_closure* next_recv_message_ready;
// Original recv_trailing_metadata callback, invoked after our own.
grpc_closure* original_recv_trailing_metadata_ready;
+ bool seen_recv_trailing_metadata;
+ grpc_error* recv_trailing_metadata_error;
};
struct channel_data {
@@ -147,7 +149,21 @@ static void recv_message_ready(void* user_data, grpc_error* error) {
GRPC_ERROR_REF(error);
}
// Invoke the next callback.
- GRPC_CLOSURE_RUN(calld->next_recv_message_ready, error);
+ grpc_closure* closure = calld->next_recv_message_ready;
+ calld->next_recv_message_ready = nullptr;
+ if (calld->seen_recv_trailing_metadata) {
+ /* We might potentially see another RECV_MESSAGE op. In that case, we do not
+ * want to run the recv_trailing_metadata_ready closure again. The newer
+ * RECV_MESSAGE op cannot cause any errors since the transport has already
+ * invoked the recv_trailing_metadata_ready closure and all further
+ * RECV_MESSAGE ops will get null payloads. */
+ calld->seen_recv_trailing_metadata = false;
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error,
+ "continue recv_trailing_metadata_ready");
+ }
+ GRPC_CLOSURE_RUN(closure, error);
}
// Callback invoked on completion of recv_trailing_metadata
@@ -155,6 +171,14 @@ static void recv_message_ready(void* user_data, grpc_error* error) {
static void recv_trailing_metadata_ready(void* user_data, grpc_error* error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
call_data* calld = static_cast<call_data*>(elem->call_data);
+ if (calld->next_recv_message_ready != nullptr) {
+ calld->seen_recv_trailing_metadata = true;
+ calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error);
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring recv_trailing_metadata_ready until "
+ "after recv_message_ready");
+ return;
+ }
error =
grpc_error_add_child(GRPC_ERROR_REF(error), GRPC_ERROR_REF(calld->error));
// Invoke the next callback.
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
index 0eaf63f133..920d52770f 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
@@ -525,7 +525,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem,
/* should this elem be in the table? */
size_t decoder_space_usage =
- grpc_mdelem_get_size_in_hpack_table(elem, st->use_true_binary_metadata);
+ grpc_chttp2_get_size_in_hpack_table(elem, st->use_true_binary_metadata);
bool should_add_elem = elem_interned &&
decoder_space_usage < MAX_DECODER_SPACE_USAGE &&
c->filter_elems[HASH_FRAGMENT_1(elem_hash)] >=
@@ -688,11 +688,22 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor* c,
emit_advertise_table_size_change(c, &st);
}
for (size_t i = 0; i < extra_headers_size; ++i) {
- hpack_enc(c, *extra_headers[i], &st);
+ grpc_mdelem md = *extra_headers[i];
+ uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(md);
+ if (static_index) {
+ emit_indexed(c, static_index, &st);
+ } else {
+ hpack_enc(c, md, &st);
+ }
}
grpc_metadata_batch_assert_ok(metadata);
for (grpc_linked_mdelem* l = metadata->list.head; l; l = l->next) {
- hpack_enc(c, l->md, &st);
+ uint8_t static_index = grpc_chttp2_get_static_hpack_table_index(l->md);
+ if (static_index) {
+ emit_indexed(c, static_index, &st);
+ } else {
+ hpack_enc(c, l->md, &st);
+ }
}
grpc_millis deadline = metadata->deadline;
if (deadline != GRPC_MILLIS_INF_FUTURE) {
diff --git a/src/core/ext/transport/chttp2/transport/hpack_mapping.cc b/src/core/ext/transport/chttp2/transport/hpack_mapping.cc
new file mode 100644
index 0000000000..fd529f0fd4
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/hpack_mapping.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * WARNING: Auto-generated code.
+ *
+ * To make changes to this file, change
+ * tools/codegen/core/gen_static_metadata.py, and then re-run it.
+ *
+ * This file contains the mapping from the index of each metadata element in the
+ * grpc static metadata table to the index of that element in the hpack static
+ * metadata table. If the element is not contained in the static hpack table,
+ * then the returned index is 0.
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/ext/transport/chttp2/transport/hpack_mapping.h"
+
+const uint8_t grpc_hpack_static_mdelem_indices[GRPC_STATIC_MDELEM_COUNT] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 13, 6, 7, 0, 1, 2, 0, 4,
+ 5, 9, 10, 11, 12, 14, 15, 0, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 0, 0, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
diff --git a/src/core/ext/transport/chttp2/transport/hpack_mapping.h b/src/core/ext/transport/chttp2/transport/hpack_mapping.h
new file mode 100644
index 0000000000..ebcd65bd9f
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/hpack_mapping.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * WARNING: Auto-generated code.
+ *
+ * To make changes to this file, change
+ * tools/codegen/core/gen_static_metadata.py, and then re-run it.
+ *
+ * This file contains the mapping from the index of each metadata element in the
+ * grpc static metadata table to the index of that element in the hpack static
+ * metadata table. If the element is not contained in the static hpack table,
+ * then the returned index is 0.
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_MAPPING_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_MAPPING_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/transport/static_metadata.h"
+
+extern const uint8_t grpc_hpack_static_mdelem_indices[GRPC_STATIC_MDELEM_COUNT];
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_MAPPING_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.cc b/src/core/ext/transport/chttp2/transport/hpack_table.cc
index 7929258356..117679ab75 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.cc
@@ -27,8 +27,10 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include "src/core/ext/transport/chttp2/transport/hpack_mapping.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/murmur_hash.h"
+#include "src/core/lib/transport/static_metadata.h"
extern grpc_core::TraceFlag grpc_http_trace;
@@ -366,3 +368,30 @@ grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
return r;
}
+
+static size_t get_base64_encoded_size(size_t raw_length) {
+ static const uint8_t tail_xtra[3] = {0, 2, 3};
+ return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
+}
+
+size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
+ bool use_true_binary_metadata) {
+ size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
+ size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
+ if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
+ return overhead_and_key + (use_true_binary_metadata
+ ? value_len + 1
+ : get_base64_encoded_size(value_len));
+ } else {
+ return overhead_and_key + value_len;
+ }
+}
+
+uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md) {
+ if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
+ return grpc_hpack_static_mdelem_indices[GRPC_MDELEM_DATA(md) -
+ grpc_static_mdelem_table];
+ } else {
+ return 0;
+ }
+}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
index 98026a4ba4..a0ffc6fab7 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -83,6 +83,15 @@ grpc_mdelem grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl* tbl,
/* add a table entry to the index */
grpc_error* grpc_chttp2_hptbl_add(grpc_chttp2_hptbl* tbl,
grpc_mdelem md) GRPC_MUST_USE_RESULT;
+
+size_t grpc_chttp2_get_size_in_hpack_table(grpc_mdelem elem,
+ bool use_true_binary_metadata);
+
+/* Returns the static hpack table index that corresponds to /a elem. Returns 0
+ if /a elem is not statically stored or if it is not in the static hpack
+ table */
+uint8_t grpc_chttp2_get_static_hpack_table_index(grpc_mdelem md);
+
/* Find a key/value pair in the table... returns the index in the table of the
most similar entry, or 0 if the value was not found */
typedef struct {
diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index 0694ad743b..f532b084c9 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -409,67 +409,81 @@ static void on_initial_header(void* tp, grpc_mdelem md) {
gpr_free(value);
}
- if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
- !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
- /* TODO(ctiller): check for a status like " 0" */
- s->seen_error = true;
- }
+ if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
+ // We don't use grpc_mdelem_eq here to avoid executing additional
+ // instructions. The reasoning is if the payload is not equal, we already
+ // know that the metadata elements are not equal because the md is
+ // confirmed to be static. If we had used grpc_mdelem_eq here, then if the
+ // payloads are not equal, grpc_mdelem_eq executes more instructions to
+ // determine if they're equal or not.
+ if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload ||
+ md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) {
+ s->seen_error = true;
+ }
+ } else {
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+ /* TODO(ctiller): check for a status like " 0" */
+ s->seen_error = true;
+ }
- if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
- grpc_millis* cached_timeout =
- static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
- grpc_millis timeout;
- if (cached_timeout != nullptr) {
- timeout = *cached_timeout;
- } else {
- if (GPR_UNLIKELY(
- !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
- char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
- gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
- gpr_free(val);
- timeout = GRPC_MILLIS_INF_FUTURE;
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
+ grpc_millis* cached_timeout = static_cast<grpc_millis*>(
+ grpc_mdelem_get_user_data(md, free_timeout));
+ grpc_millis timeout;
+ if (cached_timeout != nullptr) {
+ timeout = *cached_timeout;
+ } else {
+ if (GPR_UNLIKELY(
+ !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
+ char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
+ gpr_free(val);
+ timeout = GRPC_MILLIS_INF_FUTURE;
+ }
+ if (GRPC_MDELEM_IS_INTERNED(md)) {
+ /* store the result */
+ cached_timeout =
+ static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
+ *cached_timeout = timeout;
+ grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+ }
}
- if (GRPC_MDELEM_IS_INTERNED(md)) {
- /* store the result */
- cached_timeout =
- static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
- *cached_timeout = timeout;
- grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+ if (timeout != GRPC_MILLIS_INF_FUTURE) {
+ grpc_chttp2_incoming_metadata_buffer_set_deadline(
+ &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout);
}
+ GRPC_MDELEM_UNREF(md);
+ return;
}
- if (timeout != GRPC_MILLIS_INF_FUTURE) {
- grpc_chttp2_incoming_metadata_buffer_set_deadline(
- &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout);
- }
+ }
+
+ const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
+ const size_t metadata_size_limit =
+ t->settings[GRPC_ACKED_SETTINGS]
+ [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
+ if (new_size > metadata_size_limit) {
+ gpr_log(GPR_DEBUG,
+ "received initial metadata size exceeds limit (%" PRIuPTR
+ " vs. %" PRIuPTR ")",
+ new_size, metadata_size_limit);
+ grpc_chttp2_cancel_stream(
+ t, s,
+ grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "received initial metadata size exceeds limit"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_RESOURCE_EXHAUSTED));
+ grpc_chttp2_parsing_become_skip_parser(t);
+ s->seen_error = true;
GRPC_MDELEM_UNREF(md);
} else {
- const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
- const size_t metadata_size_limit =
- t->settings[GRPC_ACKED_SETTINGS]
- [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
- if (new_size > metadata_size_limit) {
- gpr_log(GPR_DEBUG,
- "received initial metadata size exceeds limit (%" PRIuPTR
- " vs. %" PRIuPTR ")",
- new_size, metadata_size_limit);
- grpc_chttp2_cancel_stream(
- t, s,
- grpc_error_set_int(
- GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "received initial metadata size exceeds limit"),
- GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
+ grpc_error* error =
+ grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
+ if (error != GRPC_ERROR_NONE) {
+ grpc_chttp2_cancel_stream(t, s, error);
grpc_chttp2_parsing_become_skip_parser(t);
s->seen_error = true;
GRPC_MDELEM_UNREF(md);
- } else {
- grpc_error* error =
- grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
- if (error != GRPC_ERROR_NONE) {
- grpc_chttp2_cancel_stream(t, s, error);
- grpc_chttp2_parsing_become_skip_parser(t);
- s->seen_error = true;
- GRPC_MDELEM_UNREF(md);
- }
}
}
}
@@ -491,8 +505,19 @@ static void on_trailing_header(void* tp, grpc_mdelem md) {
gpr_free(value);
}
- if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
- !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+ if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) {
+ // We don't use grpc_mdelem_eq here to avoid executing additional
+ // instructions. The reasoning is if the payload is not equal, we already
+ // know that the metadata elements are not equal because the md is
+ // confirmed to be static. If we had used grpc_mdelem_eq here, then if the
+ // payloads are not equal, grpc_mdelem_eq executes more instructions to
+ // determine if they're equal or not.
+ if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload ||
+ md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) {
+ s->seen_error = true;
+ }
+ } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
/* TODO(ctiller): check for a status like " 0" */
s->seen_error = true;
}
diff --git a/src/core/lib/channel/channel_trace.h b/src/core/lib/channel/channel_trace.h
index 230faa483e..94fea20b45 100644
--- a/src/core/lib/channel/channel_trace.h
+++ b/src/core/lib/channel/channel_trace.h
@@ -63,7 +63,7 @@ class ChannelTrace {
// stack, determine if it makes more sense to accept a char* instead of a
// slice.
void AddTraceEventWithReference(Severity severity, grpc_slice data,
- RefCountedPtr<BaseNode> referenced_channel);
+ RefCountedPtr<BaseNode> referenced_entity);
// Creates and returns the raw grpc_json object, so a parent channelz
// object may incorporate the json before rendering.
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.cc b/src/core/lib/iomgr/ev_epollsig_linux.cc
deleted file mode 100644
index 5695ac795d..0000000000
--- a/src/core/lib/iomgr/ev_epollsig_linux.cc
+++ /dev/null
@@ -1,1743 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/iomgr/port.h"
-
-#include <grpc/grpc_posix.h>
-#include <grpc/support/log.h>
-
-/* This polling engine is only relevant on linux kernels supporting epoll() */
-#ifdef GRPC_LINUX_EPOLL_CREATE1
-
-#include "src/core/lib/iomgr/ev_epollsig_linux.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <poll.h>
-#include <pthread.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/lib/debug/stats.h"
-#include "src/core/lib/gpr/tls.h"
-#include "src/core/lib/gpr/useful.h"
-#include "src/core/lib/gprpp/manual_constructor.h"
-#include "src/core/lib/iomgr/block_annotate.h"
-#include "src/core/lib/iomgr/ev_posix.h"
-#include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/lockfree_event.h"
-#include "src/core/lib/iomgr/timer.h"
-#include "src/core/lib/iomgr/wakeup_fd_posix.h"
-#include "src/core/lib/profiling/timers.h"
-
-#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker*)1)
-
-#define GRPC_POLLING_TRACE(...) \
- if (grpc_polling_trace.enabled()) { \
- gpr_log(GPR_INFO, __VA_ARGS__); \
- }
-
-static int grpc_wakeup_signal = -1;
-static bool is_grpc_wakeup_signal_initialized = false;
-
-/* Implements the function defined in grpc_posix.h. This function might be
- * called before even calling grpc_init() to set either a different signal to
- * use. If signum == -1, then the use of signals is disabled */
-void grpc_use_signal(int signum) {
- grpc_wakeup_signal = signum;
- is_grpc_wakeup_signal_initialized = true;
-
- if (grpc_wakeup_signal < 0) {
- gpr_log(GPR_INFO,
- "Use of signals is disabled. Epoll engine will not be used");
- } else {
- gpr_log(GPR_INFO, "epoll engine will be using signal: %d",
- grpc_wakeup_signal);
- }
-}
-
-struct polling_island;
-
-typedef enum {
- POLL_OBJ_FD,
- POLL_OBJ_POLLSET,
- POLL_OBJ_POLLSET_SET
-} poll_obj_type;
-
-typedef struct poll_obj {
-#ifndef NDEBUG
- poll_obj_type obj_type;
-#endif
- gpr_mu mu;
- struct polling_island* pi;
-} poll_obj;
-
-const char* poll_obj_string(poll_obj_type po_type) {
- switch (po_type) {
- case POLL_OBJ_FD:
- return "fd";
- case POLL_OBJ_POLLSET:
- return "pollset";
- case POLL_OBJ_POLLSET_SET:
- return "pollset_set";
- }
-
- GPR_UNREACHABLE_CODE(return "UNKNOWN");
-}
-
- /*******************************************************************************
- * Fd Declarations
- */
-
-#define FD_FROM_PO(po) ((grpc_fd*)(po))
-
-struct grpc_fd {
- poll_obj po;
-
- int fd;
- /* refst format:
- bit 0 : 1=Active / 0=Orphaned
- bits 1-n : refcount
- Ref/Unref by two to avoid altering the orphaned bit */
- gpr_atm refst;
-
- /* The fd is either closed or we relinquished control of it. In either
- cases, this indicates that the 'fd' on this structure is no longer
- valid */
- bool orphaned;
-
- grpc_core::ManualConstructor<grpc_core::LockfreeEvent> read_closure;
- grpc_core::ManualConstructor<grpc_core::LockfreeEvent> write_closure;
- grpc_core::ManualConstructor<grpc_core::LockfreeEvent> error_closure;
-
- struct grpc_fd* freelist_next;
- grpc_closure* on_done_closure;
-
- grpc_iomgr_object iomgr_object;
-
- /* Do we need to track EPOLLERR events separately? */
- bool track_err;
-};
-
-/* Reference counting for fds */
-#ifndef NDEBUG
-static void fd_ref(grpc_fd* fd, const char* reason, const char* file, int line);
-static void fd_unref(grpc_fd* fd, const char* reason, const char* file,
- int line);
-#define GRPC_FD_REF(fd, reason) fd_ref(fd, reason, __FILE__, __LINE__)
-#define GRPC_FD_UNREF(fd, reason) fd_unref(fd, reason, __FILE__, __LINE__)
-#else
-static void fd_ref(grpc_fd* fd);
-static void fd_unref(grpc_fd* fd);
-#define GRPC_FD_REF(fd, reason) fd_ref(fd)
-#define GRPC_FD_UNREF(fd, reason) fd_unref(fd)
-#endif
-
-static void fd_global_init(void);
-static void fd_global_shutdown(void);
-
-/*******************************************************************************
- * Polling island Declarations
- */
-
-#ifndef NDEBUG
-
-#define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__)
-#define PI_UNREF(p, r) pi_unref_dbg((p), (r), __FILE__, __LINE__)
-
-#else
-
-#define PI_ADD_REF(p, r) pi_add_ref((p))
-#define PI_UNREF(p, r) pi_unref((p))
-
-#endif
-
-/* This is also used as grpc_workqueue (by directly casing it) */
-typedef struct polling_island {
- gpr_mu mu;
- /* Ref count. Use PI_ADD_REF() and PI_UNREF() macros to increment/decrement
- the refcount.
- Once the ref count becomes zero, this structure is destroyed which means
- we should ensure that there is never a scenario where a PI_ADD_REF() is
- racing with a PI_UNREF() that just made the ref_count zero. */
- gpr_atm ref_count;
-
- /* Pointer to the polling_island this merged into.
- * merged_to value is only set once in polling_island's lifetime (and that too
- * only if the island is merged with another island). Because of this, we can
- * use gpr_atm type here so that we can do atomic access on this and reduce
- * lock contention on 'mu' mutex.
- *
- * Note that if this field is not NULL (i.e not 0), all the remaining fields
- * (except mu and ref_count) are invalid and must be ignored. */
- gpr_atm merged_to;
-
- /* Number of threads currently polling on this island */
- gpr_atm poller_count;
-
- /* The fd of the underlying epoll set */
- int epoll_fd;
-
- /* The file descriptors in the epoll set */
- size_t fd_cnt;
- size_t fd_capacity;
- grpc_fd** fds;
-} polling_island;
-
-/*******************************************************************************
- * Pollset Declarations
- */
-struct grpc_pollset_worker {
- /* Thread id of this worker */
- pthread_t pt_id;
-
- /* Used to prevent a worker from getting kicked multiple times */
- gpr_atm is_kicked;
- struct grpc_pollset_worker* next;
- struct grpc_pollset_worker* prev;
-};
-
-struct grpc_pollset {
- poll_obj po;
-
- grpc_pollset_worker root_worker;
- bool kicked_without_pollers;
-
- bool shutting_down; /* Is the pollset shutting down ? */
- bool finish_shutdown_called; /* Is the 'finish_shutdown_locked()' called ? */
- grpc_closure* shutdown_done; /* Called after after shutdown is complete */
-};
-
-/*******************************************************************************
- * Pollset-set Declarations
- */
-struct grpc_pollset_set {
- poll_obj po;
-};
-
-/*******************************************************************************
- * Common helpers
- */
-
-static bool append_error(grpc_error** composite, grpc_error* error,
- const char* desc) {
- if (error == GRPC_ERROR_NONE) return true;
- if (*composite == GRPC_ERROR_NONE) {
- *composite = GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc);
- }
- *composite = grpc_error_add_child(*composite, error);
- return false;
-}
-
-/*******************************************************************************
- * Polling island Definitions
- */
-
-/* The wakeup fd that is used to wake up all threads in a Polling island. This
- is useful in the polling island merge operation where we need to wakeup all
- the threads currently polling the smaller polling island (so that they can
- start polling the new/merged polling island)
-
- NOTE: This fd is initialized to be readable and MUST NOT be consumed i.e the
- threads that woke up MUST NOT call grpc_wakeup_fd_consume_wakeup() */
-static grpc_wakeup_fd polling_island_wakeup_fd;
-
-/* The polling island being polled right now.
- See comments in workqueue_maybe_wakeup for why this is tracked. */
-static __thread polling_island* g_current_thread_polling_island;
-
-/* Forward declaration */
-static void polling_island_delete(polling_island* pi);
-
-#ifdef GRPC_TSAN
-/* Currently TSAN may incorrectly flag data races between epoll_ctl and
- epoll_wait for any grpc_fd structs that are added to the epoll set via
- epoll_ctl and are returned (within a very short window) via epoll_wait().
-
- To work-around this race, we establish a happens-before relation between
- the code just-before epoll_ctl() and the code after epoll_wait() by using
- this atomic */
-gpr_atm g_epoll_sync;
-#endif /* defined(GRPC_TSAN) */
-
-static void pi_add_ref(polling_island* pi);
-static void pi_unref(polling_island* pi);
-
-#ifndef NDEBUG
-static void pi_add_ref_dbg(polling_island* pi, const char* reason,
- const char* file, int line) {
- if (grpc_polling_trace.enabled()) {
- gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count);
- gpr_log(GPR_INFO,
- "Add ref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR
- " (%s) - (%s, %d)",
- pi, old_cnt, old_cnt + 1, reason, file, line);
- }
- pi_add_ref(pi);
-}
-
-static void pi_unref_dbg(polling_island* pi, const char* reason,
- const char* file, int line) {
- if (grpc_polling_trace.enabled()) {
- gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count);
- gpr_log(GPR_INFO,
- "Unref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR
- " (%s) - (%s, %d)",
- pi, old_cnt, (old_cnt - 1), reason, file, line);
- }
- pi_unref(pi);
-}
-#endif
-
-static void pi_add_ref(polling_island* pi) {
- gpr_atm_no_barrier_fetch_add(&pi->ref_count, 1);
-}
-
-static void pi_unref(polling_island* pi) {
- /* If ref count went to zero, delete the polling island.
- Note that this deletion not be done under a lock. Once the ref count goes
- to zero, we are guaranteed that no one else holds a reference to the
- polling island (and that there is no racing pi_add_ref() call either).
-
- Also, if we are deleting the polling island and the merged_to field is
- non-empty, we should remove a ref to the merged_to polling island
- */
- if (1 == gpr_atm_full_fetch_add(&pi->ref_count, -1)) {
- polling_island* next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- polling_island_delete(pi);
- if (next != nullptr) {
- PI_UNREF(next, "pi_delete"); /* Recursive call */
- }
- }
-}
-
-/* The caller is expected to hold pi->mu lock before calling this function */
-static void polling_island_add_fds_locked(polling_island* pi, grpc_fd** fds,
- size_t fd_count, bool add_fd_refs,
- grpc_error** error) {
- int err;
- size_t i;
- struct epoll_event ev;
- char* err_msg;
- const char* err_desc = "polling_island_add_fds";
-
-#ifdef GRPC_TSAN
- /* See the definition of g_epoll_sync for more context */
- gpr_atm_rel_store(&g_epoll_sync, (gpr_atm)0);
-#endif /* defined(GRPC_TSAN) */
-
- for (i = 0; i < fd_count; i++) {
- ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLOUT | EPOLLET);
- /* Use the least significant bit of ev.data.ptr to store track_err to avoid
- * synchronization issues when accessing it after receiving an event */
- ev.data.ptr = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(fds[i]) |
- (fds[i]->track_err ? 1 : 0));
- err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD, fds[i]->fd, &ev);
-
- if (err < 0) {
- if (errno != EEXIST) {
- gpr_asprintf(
- &err_msg,
- "epoll_ctl (epoll_fd: %d) add fd: %d failed with error: %d (%s)",
- pi->epoll_fd, fds[i]->fd, errno, strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- gpr_free(err_msg);
- }
-
- continue;
- }
-
- if (pi->fd_cnt == pi->fd_capacity) {
- pi->fd_capacity = GPR_MAX(pi->fd_capacity + 8, pi->fd_cnt * 3 / 2);
- pi->fds = static_cast<grpc_fd**>(
- gpr_realloc(pi->fds, sizeof(grpc_fd*) * pi->fd_capacity));
- }
-
- pi->fds[pi->fd_cnt++] = fds[i];
- if (add_fd_refs) {
- GRPC_FD_REF(fds[i], "polling_island");
- }
- }
-}
-
-/* The caller is expected to hold pi->mu before calling this */
-static void polling_island_add_wakeup_fd_locked(polling_island* pi,
- grpc_wakeup_fd* wakeup_fd,
- grpc_error** error) {
- struct epoll_event ev;
- int err;
- char* err_msg;
- const char* err_desc = "polling_island_add_wakeup_fd";
-
- ev.events = static_cast<uint32_t>(EPOLLIN | EPOLLET);
- ev.data.ptr = wakeup_fd;
- err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_ADD,
- GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), &ev);
- if (err < 0 && errno != EEXIST) {
- gpr_asprintf(&err_msg,
- "epoll_ctl (epoll_fd: %d) add wakeup fd: %d failed with "
- "error: %d (%s)",
- pi->epoll_fd, GRPC_WAKEUP_FD_GET_READ_FD(wakeup_fd), errno,
- strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- gpr_free(err_msg);
- }
-}
-
-/* The caller is expected to hold pi->mu lock before calling this function */
-static void polling_island_remove_all_fds_locked(polling_island* pi,
- bool remove_fd_refs,
- grpc_error** error) {
- int err;
- size_t i;
- char* err_msg;
- const char* err_desc = "polling_island_remove_fds";
-
- for (i = 0; i < pi->fd_cnt; i++) {
- err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, pi->fds[i]->fd, nullptr);
- if (err < 0 && errno != ENOENT) {
- gpr_asprintf(&err_msg,
- "epoll_ctl (epoll_fd: %d) delete fds[%zu]: %d failed with "
- "error: %d (%s)",
- pi->epoll_fd, i, pi->fds[i]->fd, errno, strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- gpr_free(err_msg);
- }
-
- if (remove_fd_refs) {
- GRPC_FD_UNREF(pi->fds[i], "polling_island");
- }
- }
-
- pi->fd_cnt = 0;
-}
-
-/* The caller is expected to hold pi->mu lock before calling this function */
-static void polling_island_remove_fd_locked(polling_island* pi, grpc_fd* fd,
- grpc_error** error) {
- int err;
- size_t i;
- char* err_msg;
- const char* err_desc = "polling_island_remove_fd";
-
- /* If fd is already closed, then it would have been automatically been removed
- from the epoll set */
- err = epoll_ctl(pi->epoll_fd, EPOLL_CTL_DEL, fd->fd, nullptr);
- if (err < 0 && errno != ENOENT) {
- gpr_asprintf(
- &err_msg,
- "epoll_ctl (epoll_fd: %d) del fd: %d failed with error: %d (%s)",
- pi->epoll_fd, fd->fd, errno, strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- gpr_free(err_msg);
- }
-
- for (i = 0; i < pi->fd_cnt; i++) {
- if (pi->fds[i] == fd) {
- pi->fds[i] = pi->fds[--pi->fd_cnt];
- GRPC_FD_UNREF(fd, "polling_island");
- break;
- }
- }
-}
-
-/* Might return NULL in case of an error */
-static polling_island* polling_island_create(grpc_fd* initial_fd,
- grpc_error** error) {
- polling_island* pi = nullptr;
- const char* err_desc = "polling_island_create";
-
- *error = GRPC_ERROR_NONE;
-
- pi = static_cast<polling_island*>(gpr_malloc(sizeof(*pi)));
- gpr_mu_init(&pi->mu);
- pi->fd_cnt = 0;
- pi->fd_capacity = 0;
- pi->fds = nullptr;
- pi->epoll_fd = -1;
-
- gpr_atm_rel_store(&pi->ref_count, 0);
- gpr_atm_rel_store(&pi->poller_count, 0);
- gpr_atm_rel_store(&pi->merged_to, (gpr_atm) nullptr);
-
- pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
-
- if (pi->epoll_fd < 0) {
- append_error(error, GRPC_OS_ERROR(errno, "epoll_create1"), err_desc);
- goto done;
- }
-
- if (initial_fd != nullptr) {
- polling_island_add_fds_locked(pi, &initial_fd, 1, true, error);
- }
-
-done:
- if (*error != GRPC_ERROR_NONE) {
- polling_island_delete(pi);
- pi = nullptr;
- }
- return pi;
-}
-
-static void polling_island_delete(polling_island* pi) {
- GPR_ASSERT(pi->fd_cnt == 0);
-
- if (pi->epoll_fd >= 0) {
- close(pi->epoll_fd);
- }
- gpr_mu_destroy(&pi->mu);
- gpr_free(pi->fds);
- gpr_free(pi);
-}
-
-/* Attempts to gets the last polling island in the linked list (liked by the
- * 'merged_to' field). Since this does not lock the polling island, there are no
- * guarantees that the island returned is the last island */
-static polling_island* polling_island_maybe_get_latest(polling_island* pi) {
- polling_island* next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- while (next != nullptr) {
- pi = next;
- next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- }
-
- return pi;
-}
-
-/* Gets the lock on the *latest* polling island i.e the last polling island in
- the linked list (linked by the 'merged_to' field). Call gpr_mu_unlock on the
- returned polling island's mu.
- Usage: To lock/unlock polling island "pi", do the following:
- polling_island *pi_latest = polling_island_lock(pi);
- ...
- ... critical section ..
- ...
- gpr_mu_unlock(&pi_latest->mu); // NOTE: use pi_latest->mu. NOT pi->mu */
-static polling_island* polling_island_lock(polling_island* pi) {
- polling_island* next = nullptr;
-
- while (true) {
- next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- if (next == nullptr) {
- /* Looks like 'pi' is the last node in the linked list but unless we check
- this by holding the pi->mu lock, we cannot be sure (i.e without the
- pi->mu lock, we don't prevent island merges).
- To be absolutely sure, check once more by holding the pi->mu lock */
- gpr_mu_lock(&pi->mu);
- next = (polling_island*)gpr_atm_acq_load(&pi->merged_to);
- if (next == nullptr) {
- /* pi is infact the last node and we have the pi->mu lock. we're done */
- break;
- }
-
- /* pi->merged_to is not NULL i.e pi isn't the last node anymore. pi->mu
- * isn't the lock we are interested in. Continue traversing the list */
- gpr_mu_unlock(&pi->mu);
- }
-
- pi = next;
- }
-
- return pi;
-}
-
-/* Gets the lock on the *latest* polling islands in the linked lists pointed by
- *p and *q (and also updates *p and *q to point to the latest polling islands)
-
- This function is needed because calling the following block of code to obtain
- locks on polling islands (*p and *q) is prone to deadlocks.
- {
- polling_island_lock(*p, true);
- polling_island_lock(*q, true);
- }
-
- Usage/example:
- polling_island *p1;
- polling_island *p2;
- ..
- polling_island_lock_pair(&p1, &p2);
- ..
- .. Critical section with both p1 and p2 locked
- ..
- // Release locks: Always call polling_island_unlock_pair() to release locks
- polling_island_unlock_pair(p1, p2);
-*/
-static void polling_island_lock_pair(polling_island** p, polling_island** q) {
- polling_island* pi_1 = *p;
- polling_island* pi_2 = *q;
- polling_island* next_1 = nullptr;
- polling_island* next_2 = nullptr;
-
- /* The algorithm is simple:
- - Go to the last polling islands in the linked lists *pi_1 and *pi_2 (and
- keep updating pi_1 and pi_2)
- - Then obtain locks on the islands by following a lock order rule of
- locking polling_island with lower address first
- Special case: Before obtaining the locks, check if pi_1 and pi_2 are
- pointing to the same island. If that is the case, we can just call
- polling_island_lock()
- - After obtaining both the locks, double check that the polling islands
- are still the last polling islands in their respective linked lists
- (this is because there might have been polling island merges before
- we got the lock)
- - If the polling islands are the last islands, we are done. If not,
- release the locks and continue the process from the first step */
- while (true) {
- next_1 = (polling_island*)gpr_atm_acq_load(&pi_1->merged_to);
- while (next_1 != nullptr) {
- pi_1 = next_1;
- next_1 = (polling_island*)gpr_atm_acq_load(&pi_1->merged_to);
- }
-
- next_2 = (polling_island*)gpr_atm_acq_load(&pi_2->merged_to);
- while (next_2 != nullptr) {
- pi_2 = next_2;
- next_2 = (polling_island*)gpr_atm_acq_load(&pi_2->merged_to);
- }
-
- if (pi_1 == pi_2) {
- pi_1 = pi_2 = polling_island_lock(pi_1);
- break;
- }
-
- if (pi_1 < pi_2) {
- gpr_mu_lock(&pi_1->mu);
- gpr_mu_lock(&pi_2->mu);
- } else {
- gpr_mu_lock(&pi_2->mu);
- gpr_mu_lock(&pi_1->mu);
- }
-
- next_1 = (polling_island*)gpr_atm_acq_load(&pi_1->merged_to);
- next_2 = (polling_island*)gpr_atm_acq_load(&pi_2->merged_to);
- if (next_1 == nullptr && next_2 == nullptr) {
- break;
- }
-
- gpr_mu_unlock(&pi_1->mu);
- gpr_mu_unlock(&pi_2->mu);
- }
-
- *p = pi_1;
- *q = pi_2;
-}
-
-static void polling_island_unlock_pair(polling_island* p, polling_island* q) {
- if (p == q) {
- gpr_mu_unlock(&p->mu);
- } else {
- gpr_mu_unlock(&p->mu);
- gpr_mu_unlock(&q->mu);
- }
-}
-
-static polling_island* polling_island_merge(polling_island* p,
- polling_island* q,
- grpc_error** error) {
- /* Get locks on both the polling islands */
- polling_island_lock_pair(&p, &q);
-
- if (p != q) {
- /* Make sure that p points to the polling island with fewer fds than q */
- if (p->fd_cnt > q->fd_cnt) {
- GPR_SWAP(polling_island*, p, q);
- }
-
- /* Merge p with q i.e move all the fds from p (The one with fewer fds) to q
- Note that the refcounts on the fds being moved will not change here.
- This is why the last param in the following two functions is 'false') */
- polling_island_add_fds_locked(q, p->fds, p->fd_cnt, false, error);
- polling_island_remove_all_fds_locked(p, false, error);
-
- /* Wakeup all the pollers (if any) on p so that they pickup this change */
- polling_island_add_wakeup_fd_locked(p, &polling_island_wakeup_fd, error);
-
- /* Add the 'merged_to' link from p --> q */
- gpr_atm_rel_store(&p->merged_to, (gpr_atm)q);
- PI_ADD_REF(q, "pi_merge"); /* To account for the new incoming ref from p */
- }
- /* else if p == q, nothing needs to be done */
-
- polling_island_unlock_pair(p, q);
-
- /* Return the merged polling island (Note that no merge would have happened
- if p == q which is ok) */
- return q;
-}
-
-static grpc_error* polling_island_global_init() {
- grpc_error* error = GRPC_ERROR_NONE;
-
- error = grpc_wakeup_fd_init(&polling_island_wakeup_fd);
- if (error == GRPC_ERROR_NONE) {
- error = grpc_wakeup_fd_wakeup(&polling_island_wakeup_fd);
- }
-
- return error;
-}
-
-static void polling_island_global_shutdown() {
- grpc_wakeup_fd_destroy(&polling_island_wakeup_fd);
-}
-
-/*******************************************************************************
- * Fd Definitions
- */
-
-/* We need to keep a freelist not because of any concerns of malloc performance
- * but instead so that implementations with multiple threads in (for example)
- * epoll_wait deal with the race between pollset removal and incoming poll
- * notifications.
- *
- * The problem is that the poller ultimately holds a reference to this
- * object, so it is very difficult to know when is safe to free it, at least
- * without some expensive synchronization.
- *
- * If we keep the object freelisted, in the worst case losing this race just
- * becomes a spurious read notification on a reused fd.
- */
-
-/* The alarm system needs to be able to wakeup 'some poller' sometimes
- * (specifically when a new alarm needs to be triggered earlier than the next
- * alarm 'epoch'). This wakeup_fd gives us something to alert on when such a
- * case occurs. */
-
-static grpc_fd* fd_freelist = nullptr;
-static gpr_mu fd_freelist_mu;
-
-#ifndef NDEBUG
-#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__)
-#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__)
-static void ref_by(grpc_fd* fd, int n, const char* reason, const char* file,
- int line) {
- if (grpc_trace_fd_refcount.enabled()) {
- gpr_log(GPR_DEBUG,
- "FD %d %p ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
- fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
- gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line);
- }
-#else
-#define REF_BY(fd, n, reason) ref_by(fd, n)
-#define UNREF_BY(fd, n, reason) unref_by(fd, n)
-static void ref_by(grpc_fd* fd, int n) {
-#endif
- GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0);
-}
-
-#ifndef NDEBUG
-static void unref_by(grpc_fd* fd, int n, const char* reason, const char* file,
- int line) {
- if (grpc_trace_fd_refcount.enabled()) {
- gpr_log(GPR_DEBUG,
- "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
- fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
- gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line);
- }
-#else
-static void unref_by(grpc_fd* fd, int n) {
-#endif
- gpr_atm old = gpr_atm_full_fetch_add(&fd->refst, -n);
- if (old == n) {
- /* Add the fd to the freelist */
- gpr_mu_lock(&fd_freelist_mu);
- fd->freelist_next = fd_freelist;
- fd_freelist = fd;
- grpc_iomgr_unregister_object(&fd->iomgr_object);
-
- fd->read_closure->DestroyEvent();
- fd->write_closure->DestroyEvent();
- fd->error_closure->DestroyEvent();
-
- gpr_mu_unlock(&fd_freelist_mu);
- } else {
- GPR_ASSERT(old > n);
- }
-}
-
-/* Increment refcount by two to avoid changing the orphan bit */
-#ifndef NDEBUG
-static void fd_ref(grpc_fd* fd, const char* reason, const char* file,
- int line) {
- ref_by(fd, 2, reason, file, line);
-}
-
-static void fd_unref(grpc_fd* fd, const char* reason, const char* file,
- int line) {
- unref_by(fd, 2, reason, file, line);
-}
-#else
-static void fd_ref(grpc_fd* fd) { ref_by(fd, 2); }
-static void fd_unref(grpc_fd* fd) { unref_by(fd, 2); }
-#endif
-
-static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
-
-static void fd_global_shutdown(void) {
- gpr_mu_lock(&fd_freelist_mu);
- gpr_mu_unlock(&fd_freelist_mu);
- while (fd_freelist != nullptr) {
- grpc_fd* fd = fd_freelist;
- fd_freelist = fd_freelist->freelist_next;
- gpr_mu_destroy(&fd->po.mu);
- gpr_free(fd);
- }
- gpr_mu_destroy(&fd_freelist_mu);
-}
-
-static grpc_fd* fd_create(int fd, const char* name, bool track_err) {
- grpc_fd* new_fd = nullptr;
-
- gpr_mu_lock(&fd_freelist_mu);
- if (fd_freelist != nullptr) {
- new_fd = fd_freelist;
- fd_freelist = fd_freelist->freelist_next;
- }
- gpr_mu_unlock(&fd_freelist_mu);
-
- if (new_fd == nullptr) {
- new_fd = static_cast<grpc_fd*>(gpr_malloc(sizeof(grpc_fd)));
- gpr_mu_init(&new_fd->po.mu);
- new_fd->read_closure.Init();
- new_fd->write_closure.Init();
- new_fd->error_closure.Init();
- }
-
- /* Note: It is not really needed to get the new_fd->po.mu lock here. If this
- * is a newly created fd (or an fd we got from the freelist), no one else
- * would be holding a lock to it anyway. */
- gpr_mu_lock(&new_fd->po.mu);
- new_fd->po.pi = nullptr;
-#ifndef NDEBUG
- new_fd->po.obj_type = POLL_OBJ_FD;
-#endif
-
- gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
- new_fd->fd = fd;
- new_fd->orphaned = false;
- new_fd->read_closure->InitEvent();
- new_fd->write_closure->InitEvent();
- new_fd->error_closure->InitEvent();
- new_fd->track_err = track_err;
-
- new_fd->freelist_next = nullptr;
- new_fd->on_done_closure = nullptr;
-
- gpr_mu_unlock(&new_fd->po.mu);
-
- char* fd_name;
- gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
- grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name);
- gpr_free(fd_name);
- return new_fd;
-}
-
-static int fd_wrapped_fd(grpc_fd* fd) {
- int ret_fd = -1;
- gpr_mu_lock(&fd->po.mu);
- if (!fd->orphaned) {
- ret_fd = fd->fd;
- }
- gpr_mu_unlock(&fd->po.mu);
-
- return ret_fd;
-}
-
-static void fd_orphan(grpc_fd* fd, grpc_closure* on_done, int* release_fd,
- const char* reason) {
- grpc_error* error = GRPC_ERROR_NONE;
- polling_island* unref_pi = nullptr;
-
- gpr_mu_lock(&fd->po.mu);
- fd->on_done_closure = on_done;
-
- /* Remove the active status but keep referenced. We want this grpc_fd struct
- to be alive (and not added to freelist) until the end of this function */
- REF_BY(fd, 1, reason);
-
- /* Remove the fd from the polling island:
- - Get a lock on the latest polling island (i.e the last island in the
- linked list pointed by fd->po.pi). This is the island that
- would actually contain the fd
- - Remove the fd from the latest polling island
- - Unlock the latest polling island
- - Set fd->po.pi to NULL (but remove the ref on the polling island
- before doing this.) */
- if (fd->po.pi != nullptr) {
- polling_island* pi_latest = polling_island_lock(fd->po.pi);
- polling_island_remove_fd_locked(pi_latest, fd, &error);
- gpr_mu_unlock(&pi_latest->mu);
-
- unref_pi = fd->po.pi;
- fd->po.pi = nullptr;
- }
-
- /* If release_fd is not NULL, we should be relinquishing control of the file
- descriptor fd->fd (but we still own the grpc_fd structure). */
- if (release_fd != nullptr) {
- *release_fd = fd->fd;
- } else {
- close(fd->fd);
- }
-
- fd->orphaned = true;
-
- GRPC_CLOSURE_SCHED(fd->on_done_closure, GRPC_ERROR_REF(error));
-
- gpr_mu_unlock(&fd->po.mu);
- UNREF_BY(fd, 2, reason); /* Drop the reference */
- if (unref_pi != nullptr) {
- /* Unref stale polling island here, outside the fd lock above.
- The polling island owns a workqueue which owns an fd, and unreffing
- inside the lock can cause an eventual lock loop that makes TSAN very
- unhappy. */
- PI_UNREF(unref_pi, "fd_orphan");
- }
- if (error != GRPC_ERROR_NONE) {
- const char* msg = grpc_error_string(error);
- gpr_log(GPR_DEBUG, "fd_orphan: %s", msg);
- }
- GRPC_ERROR_UNREF(error);
-}
-
-static bool fd_is_shutdown(grpc_fd* fd) {
- return fd->read_closure->IsShutdown();
-}
-
-/* Might be called multiple times */
-static void fd_shutdown(grpc_fd* fd, grpc_error* why) {
- if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) {
- shutdown(fd->fd, SHUT_RDWR);
- fd->write_closure->SetShutdown(GRPC_ERROR_REF(why));
- fd->error_closure->SetShutdown(GRPC_ERROR_REF(why));
- }
- GRPC_ERROR_UNREF(why);
-}
-
-static void fd_notify_on_read(grpc_fd* fd, grpc_closure* closure) {
- fd->read_closure->NotifyOn(closure);
-}
-
-static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
- fd->write_closure->NotifyOn(closure);
-}
-
-static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) {
- fd->error_closure->NotifyOn(closure);
-}
-
-static void fd_become_readable(grpc_fd* fd) { fd->read_closure->SetReady(); }
-
-static void fd_become_writable(grpc_fd* fd) { fd->write_closure->SetReady(); }
-
-static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
-
-/*******************************************************************************
- * Pollset Definitions
- */
-GPR_TLS_DECL(g_current_thread_pollset);
-GPR_TLS_DECL(g_current_thread_worker);
-static __thread bool g_initialized_sigmask;
-static __thread sigset_t g_orig_sigmask;
-
-static void sig_handler(int sig_num) {
-#ifdef GRPC_EPOLL_DEBUG
- gpr_log(GPR_INFO, "Received signal %d", sig_num);
-#endif
-}
-
-static void poller_kick_init() { signal(grpc_wakeup_signal, sig_handler); }
-
-/* Global state management */
-static grpc_error* pollset_global_init(void) {
- gpr_tls_init(&g_current_thread_pollset);
- gpr_tls_init(&g_current_thread_worker);
- poller_kick_init();
- return GRPC_ERROR_NONE;
-}
-
-static void pollset_global_shutdown(void) {
- gpr_tls_destroy(&g_current_thread_pollset);
- gpr_tls_destroy(&g_current_thread_worker);
-}
-
-static grpc_error* pollset_worker_kick(grpc_pollset_worker* worker) {
- grpc_error* err = GRPC_ERROR_NONE;
-
- /* Kick the worker only if it was not already kicked */
- if (gpr_atm_no_barrier_cas(&worker->is_kicked, static_cast<gpr_atm>(0),
- static_cast<gpr_atm>(1))) {
- GRPC_POLLING_TRACE(
- "pollset_worker_kick: Kicking worker: %p (thread id: %ld)",
- (void*)worker, (long int)worker->pt_id);
- int err_num = pthread_kill(worker->pt_id, grpc_wakeup_signal);
- if (err_num != 0) {
- err = GRPC_OS_ERROR(err_num, "pthread_kill");
- }
- }
- return err;
-}
-
-/* Return 1 if the pollset has active threads in pollset_work (pollset must
- * be locked) */
-static int pollset_has_workers(grpc_pollset* p) {
- return p->root_worker.next != &p->root_worker;
-}
-
-static void remove_worker(grpc_pollset* p, grpc_pollset_worker* worker) {
- worker->prev->next = worker->next;
- worker->next->prev = worker->prev;
-}
-
-static grpc_pollset_worker* pop_front_worker(grpc_pollset* p) {
- if (pollset_has_workers(p)) {
- grpc_pollset_worker* w = p->root_worker.next;
- remove_worker(p, w);
- return w;
- } else {
- return nullptr;
- }
-}
-
-static void push_back_worker(grpc_pollset* p, grpc_pollset_worker* worker) {
- worker->next = &p->root_worker;
- worker->prev = worker->next->prev;
- worker->prev->next = worker->next->prev = worker;
-}
-
-static void push_front_worker(grpc_pollset* p, grpc_pollset_worker* worker) {
- worker->prev = &p->root_worker;
- worker->next = worker->prev->next;
- worker->prev->next = worker->next->prev = worker;
-}
-
-/* p->mu must be held before calling this function */
-static grpc_error* pollset_kick(grpc_pollset* p,
- grpc_pollset_worker* specific_worker) {
- GPR_TIMER_SCOPE("pollset_kick", 0);
- grpc_error* error = GRPC_ERROR_NONE;
- GRPC_STATS_INC_POLLSET_KICK();
- const char* err_desc = "Kick Failure";
- grpc_pollset_worker* worker = specific_worker;
- if (worker != nullptr) {
- if (worker == GRPC_POLLSET_KICK_BROADCAST) {
- if (pollset_has_workers(p)) {
- GPR_TIMER_SCOPE("pollset_kick.broadcast", 0);
- for (worker = p->root_worker.next; worker != &p->root_worker;
- worker = worker->next) {
- if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) {
- append_error(&error, pollset_worker_kick(worker), err_desc);
- }
- }
- } else {
- p->kicked_without_pollers = true;
- }
- } else {
- GPR_TIMER_MARK("kicked_specifically", 0);
- if (gpr_tls_get(&g_current_thread_worker) != (intptr_t)worker) {
- append_error(&error, pollset_worker_kick(worker), err_desc);
- }
- }
- } else if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)p) {
- /* Since worker == NULL, it means that we can kick "any" worker on this
- pollset 'p'. If 'p' happens to be the same pollset this thread is
- currently polling (i.e in pollset_work() function), then there is no need
- to kick any other worker since the current thread can just absorb the
- kick. This is the reason why we enter this case only when
- g_current_thread_pollset is != p */
-
- GPR_TIMER_MARK("kick_anonymous", 0);
- worker = pop_front_worker(p);
- if (worker != nullptr) {
- GPR_TIMER_MARK("finally_kick", 0);
- push_back_worker(p, worker);
- append_error(&error, pollset_worker_kick(worker), err_desc);
- } else {
- GPR_TIMER_MARK("kicked_no_pollers", 0);
- p->kicked_without_pollers = true;
- }
- }
-
- GRPC_LOG_IF_ERROR("pollset_kick", GRPC_ERROR_REF(error));
- return error;
-}
-
-static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
- gpr_mu_init(&pollset->po.mu);
- *mu = &pollset->po.mu;
- pollset->po.pi = nullptr;
-#ifndef NDEBUG
- pollset->po.obj_type = POLL_OBJ_POLLSET;
-#endif
-
- pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker;
- pollset->kicked_without_pollers = false;
-
- pollset->shutting_down = false;
- pollset->finish_shutdown_called = false;
- pollset->shutdown_done = nullptr;
-}
-
-static int poll_deadline_to_millis_timeout(grpc_millis millis) {
- if (millis == GRPC_MILLIS_INF_FUTURE) return -1;
- grpc_millis delta = millis - grpc_core::ExecCtx::Get()->Now();
- if (delta > INT_MAX)
- return INT_MAX;
- else if (delta < 0)
- return 0;
- else
- return static_cast<int>(delta);
-}
-
-static void pollset_release_polling_island(grpc_pollset* ps,
- const char* reason) {
- if (ps->po.pi != nullptr) {
- PI_UNREF(ps->po.pi, reason);
- }
- ps->po.pi = nullptr;
-}
-
-static void finish_shutdown_locked(grpc_pollset* pollset) {
- /* The pollset cannot have any workers if we are at this stage */
- GPR_ASSERT(!pollset_has_workers(pollset));
-
- pollset->finish_shutdown_called = true;
-
- /* Release the ref and set pollset->po.pi to NULL */
- pollset_release_polling_island(pollset, "ps_shutdown");
- GRPC_CLOSURE_SCHED(pollset->shutdown_done, GRPC_ERROR_NONE);
-}
-
-/* pollset->po.mu lock must be held by the caller before calling this */
-static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
- GPR_TIMER_SCOPE("pollset_shutdown", 0);
- GPR_ASSERT(!pollset->shutting_down);
- pollset->shutting_down = true;
- pollset->shutdown_done = closure;
- pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
-
- /* If the pollset has any workers, we cannot call finish_shutdown_locked()
- because it would release the underlying polling island. In such a case, we
- let the last worker call finish_shutdown_locked() from pollset_work() */
- if (!pollset_has_workers(pollset)) {
- GPR_ASSERT(!pollset->finish_shutdown_called);
- GPR_TIMER_MARK("pollset_shutdown.finish_shutdown_locked", 0);
- finish_shutdown_locked(pollset);
- }
-}
-
-/* pollset_shutdown is guaranteed to be called before pollset_destroy. So other
- * than destroying the mutexes, there is nothing special that needs to be done
- * here */
-static void pollset_destroy(grpc_pollset* pollset) {
- GPR_ASSERT(!pollset_has_workers(pollset));
- gpr_mu_destroy(&pollset->po.mu);
-}
-
-#define GRPC_EPOLL_MAX_EVENTS 100
-/* Note: sig_mask contains the signal mask to use *during* epoll_wait() */
-static void pollset_work_and_unlock(grpc_pollset* pollset,
- grpc_pollset_worker* worker, int timeout_ms,
- sigset_t* sig_mask, grpc_error** error) {
- GPR_TIMER_SCOPE("pollset_work_and_unlock", 0);
- struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
- int epoll_fd = -1;
- int ep_rv;
- polling_island* pi = nullptr;
- char* err_msg;
- const char* err_desc = "pollset_work_and_unlock";
-
- /* We need to get the epoll_fd to wait on. The epoll_fd is in inside the
- latest polling island pointed by pollset->po.pi
-
- Since epoll_fd is immutable, we can read it without obtaining the polling
- island lock. There is however a possibility that the polling island (from
- which we got the epoll_fd) got merged with another island while we are
- in this function. This is still okay because in such a case, we will wakeup
- right-away from epoll_wait() and pick up the latest polling_island the next
- this function (i.e pollset_work_and_unlock()) is called */
-
- if (pollset->po.pi == nullptr) {
- pollset->po.pi = polling_island_create(nullptr, error);
- if (pollset->po.pi == nullptr) {
- return; /* Fatal error. We cannot continue */
- }
-
- PI_ADD_REF(pollset->po.pi, "ps");
- GRPC_POLLING_TRACE("pollset_work: pollset: %p created new pi: %p",
- (void*)pollset, (void*)pollset->po.pi);
- }
-
- pi = polling_island_maybe_get_latest(pollset->po.pi);
- epoll_fd = pi->epoll_fd;
-
- /* Update the pollset->po.pi since the island being pointed by
- pollset->po.pi maybe older than the one pointed by pi) */
- if (pollset->po.pi != pi) {
- /* Always do PI_ADD_REF before PI_UNREF because PI_UNREF may cause the
- polling island to be deleted */
- PI_ADD_REF(pi, "ps");
- PI_UNREF(pollset->po.pi, "ps");
- pollset->po.pi = pi;
- }
-
- /* Add an extra ref so that the island does not get destroyed (which means
- the epoll_fd won't be closed) while we are are doing an epoll_wait() on the
- epoll_fd */
- PI_ADD_REF(pi, "ps_work");
- gpr_mu_unlock(&pollset->po.mu);
-
- gpr_atm_no_barrier_fetch_add(&pi->poller_count, 1);
- g_current_thread_polling_island = pi;
-
- GRPC_SCHEDULING_START_BLOCKING_REGION;
- GRPC_STATS_INC_SYSCALL_POLL();
- ep_rv =
- epoll_pwait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms, sig_mask);
- GRPC_SCHEDULING_END_BLOCKING_REGION;
- if (ep_rv < 0) {
- if (errno != EINTR) {
- gpr_asprintf(&err_msg,
- "epoll_wait() epoll fd: %d failed with error: %d (%s)",
- epoll_fd, errno, strerror(errno));
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
- } else {
- /* We were interrupted. Save an interation by doing a zero timeout
- epoll_wait to see if there are any other events of interest */
- GRPC_POLLING_TRACE("pollset_work: pollset: %p, worker: %p received kick",
- (void*)pollset, (void*)worker);
- ep_rv = epoll_wait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0);
- }
- }
-
-#ifdef GRPC_TSAN
- /* See the definition of g_poll_sync for more details */
- gpr_atm_acq_load(&g_epoll_sync);
-#endif /* defined(GRPC_TSAN) */
-
- for (int i = 0; i < ep_rv; ++i) {
- void* data_ptr = ep_ev[i].data.ptr;
- if (data_ptr == &polling_island_wakeup_fd) {
- GRPC_POLLING_TRACE(
- "pollset_work: pollset: %p, worker: %p polling island (epoll_fd: "
- "%d) got merged",
- (void*)pollset, (void*)worker, epoll_fd);
- /* This means that our polling island is merged with a different
- island. We do not have to do anything here since the subsequent call
- to the function pollset_work_and_unlock() will pick up the correct
- epoll_fd */
- } else {
- grpc_fd* fd = reinterpret_cast<grpc_fd*>(
- reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1));
- bool track_err =
- reinterpret_cast<intptr_t>(data_ptr) & ~static_cast<intptr_t>(1);
- bool cancel = (ep_ev[i].events & EPOLLHUP) != 0;
- bool error = (ep_ev[i].events & EPOLLERR) != 0;
- bool read_ev = (ep_ev[i].events & (EPOLLIN | EPOLLPRI)) != 0;
- bool write_ev = (ep_ev[i].events & EPOLLOUT) != 0;
- bool err_fallback = error && !track_err;
-
- if (error && !err_fallback) {
- fd_has_errors(fd);
- }
- if (read_ev || cancel || err_fallback) {
- fd_become_readable(fd);
- }
- if (write_ev || cancel || err_fallback) {
- fd_become_writable(fd);
- }
- }
- }
-
- g_current_thread_polling_island = nullptr;
- gpr_atm_no_barrier_fetch_add(&pi->poller_count, -1);
-
- GPR_ASSERT(pi != nullptr);
-
- /* Before leaving, release the extra ref we added to the polling island. It
- is important to use "pi" here (i.e our old copy of pollset->po.pi
- that we got before releasing the polling island lock). This is because
- pollset->po.pi pointer might get udpated in other parts of the
- code when there is an island merge while we are doing epoll_wait() above */
- PI_UNREF(pi, "ps_work");
-}
-
-/* pollset->po.mu lock must be held by the caller before calling this.
- The function pollset_work() may temporarily release the lock (pollset->po.mu)
- during the course of its execution but it will always re-acquire the lock and
- ensure that it is held by the time the function returns */
-static grpc_error* pollset_work(grpc_pollset* pollset,
- grpc_pollset_worker** worker_hdl,
- grpc_millis deadline) {
- GPR_TIMER_SCOPE("pollset_work", 0);
- grpc_error* error = GRPC_ERROR_NONE;
- int timeout_ms = poll_deadline_to_millis_timeout(deadline);
-
- sigset_t new_mask;
-
- grpc_pollset_worker worker;
- worker.next = worker.prev = nullptr;
- worker.pt_id = pthread_self();
- gpr_atm_no_barrier_store(&worker.is_kicked, (gpr_atm)0);
-
- if (worker_hdl) *worker_hdl = &worker;
-
- gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
- gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
-
- if (pollset->kicked_without_pollers) {
- /* If the pollset was kicked without pollers, pretend that the current
- worker got the kick and skip polling. A kick indicates that there is some
- work that needs attention like an event on the completion queue or an
- alarm */
- GPR_TIMER_MARK("pollset_work.kicked_without_pollers", 0);
- pollset->kicked_without_pollers = 0;
- } else if (!pollset->shutting_down) {
- /* We use the posix-signal with number 'grpc_wakeup_signal' for waking up
- (i.e 'kicking') a worker in the pollset. A 'kick' is a way to inform the
- worker that there is some pending work that needs immediate attention
- (like an event on the completion queue, or a polling island merge that
- results in a new epoll-fd to wait on) and that the worker should not
- spend time waiting in epoll_pwait().
-
- A worker can be kicked anytime from the point it is added to the pollset
- via push_front_worker() (or push_back_worker()) to the point it is
- removed via remove_worker().
- If the worker is kicked before/during it calls epoll_pwait(), it should
- immediately exit from epoll_wait(). If the worker is kicked after it
- returns from epoll_wait(), then nothing really needs to be done.
-
- To accomplish this, we mask 'grpc_wakeup_signal' on this thread at all
- times *except* when it is in epoll_pwait(). This way, the worker never
- misses acting on a kick */
-
- if (!g_initialized_sigmask) {
- sigemptyset(&new_mask);
- sigaddset(&new_mask, grpc_wakeup_signal);
- pthread_sigmask(SIG_BLOCK, &new_mask, &g_orig_sigmask);
- sigdelset(&g_orig_sigmask, grpc_wakeup_signal);
- g_initialized_sigmask = true;
- /* new_mask: The new thread mask which blocks 'grpc_wakeup_signal'.
- This is the mask used at all times *except during
- epoll_wait()*"
- g_orig_sigmask: The thread mask which allows 'grpc_wakeup_signal' and
- this is the mask to use *during epoll_wait()*
-
- The new_mask is set on the worker before it is added to the pollset
- (i.e before it can be kicked) */
- }
-
- push_front_worker(pollset, &worker); /* Add worker to pollset */
-
- pollset_work_and_unlock(pollset, &worker, timeout_ms, &g_orig_sigmask,
- &error);
- grpc_core::ExecCtx::Get()->Flush();
-
- gpr_mu_lock(&pollset->po.mu);
-
- /* Note: There is no need to reset worker.is_kicked to 0 since we are no
- longer going to use this worker */
- remove_worker(pollset, &worker);
- }
-
- /* If we are the last worker on the pollset (i.e pollset_has_workers() is
- false at this point) and the pollset is shutting down, we may have to
- finish the shutdown process by calling finish_shutdown_locked().
- See pollset_shutdown() for more details.
-
- Note: Continuing to access pollset here is safe; it is the caller's
- responsibility to not destroy a pollset when it has outstanding calls to
- pollset_work() */
- if (pollset->shutting_down && !pollset_has_workers(pollset) &&
- !pollset->finish_shutdown_called) {
- GPR_TIMER_MARK("pollset_work.finish_shutdown_locked", 0);
- finish_shutdown_locked(pollset);
-
- gpr_mu_unlock(&pollset->po.mu);
- grpc_core::ExecCtx::Get()->Flush();
- gpr_mu_lock(&pollset->po.mu);
- }
-
- if (worker_hdl) *worker_hdl = nullptr;
-
- gpr_tls_set(&g_current_thread_pollset, (intptr_t)0);
- gpr_tls_set(&g_current_thread_worker, (intptr_t)0);
-
- GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
- return error;
-}
-
-static void add_poll_object(poll_obj* bag, poll_obj_type bag_type,
- poll_obj* item, poll_obj_type item_type) {
- GPR_TIMER_SCOPE("add_poll_object", 0);
-
-#ifndef NDEBUG
- GPR_ASSERT(item->obj_type == item_type);
- GPR_ASSERT(bag->obj_type == bag_type);
-#endif
-
- grpc_error* error = GRPC_ERROR_NONE;
- polling_island* pi_new = nullptr;
-
- gpr_mu_lock(&bag->mu);
- gpr_mu_lock(&item->mu);
-
-retry:
- /*
- * 1) If item->pi and bag->pi are both non-NULL and equal, do nothing
- * 2) If item->pi and bag->pi are both NULL, create a new polling island (with
- * a refcount of 2) and point item->pi and bag->pi to the new island
- * 3) If exactly one of item->pi or bag->pi is NULL, update it to point to
- * the other's non-NULL pi
- * 4) Finally if item->pi and bag-pi are non-NULL and not-equal, merge the
- * polling islands and update item->pi and bag->pi to point to the new
- * island
- */
-
- /* Early out if we are trying to add an 'fd' to a 'bag' but the fd is already
- * orphaned */
- if (item_type == POLL_OBJ_FD && (FD_FROM_PO(item))->orphaned) {
- gpr_mu_unlock(&item->mu);
- gpr_mu_unlock(&bag->mu);
- return;
- }
-
- if (item->pi == bag->pi) {
- pi_new = item->pi;
- if (pi_new == nullptr) {
- /* GPR_ASSERT(item->pi == bag->pi == NULL) */
-
- /* If we are adding an fd to a bag (i.e pollset or pollset_set), then
- * we need to do some extra work to make TSAN happy */
- if (item_type == POLL_OBJ_FD) {
- /* Unlock before creating a new polling island: the polling island will
- create a workqueue which creates a file descriptor, and holding an fd
- lock here can eventually cause a loop to appear to TSAN (making it
- unhappy). We don't think it's a real loop (there's an epoch point
- where that loop possibility disappears), but the advantages of
- keeping TSAN happy outweigh any performance advantage we might have
- by keeping the lock held. */
- gpr_mu_unlock(&item->mu);
- pi_new = polling_island_create(FD_FROM_PO(item), &error);
- gpr_mu_lock(&item->mu);
-
- /* Need to reverify any assumptions made between the initial lock and
- getting to this branch: if they've changed, we need to throw away our
- work and figure things out again. */
- if (item->pi != nullptr) {
- GRPC_POLLING_TRACE(
- "add_poll_object: Raced creating new polling island. pi_new: %p "
- "(fd: %d, %s: %p)",
- (void*)pi_new, FD_FROM_PO(item)->fd, poll_obj_string(bag_type),
- (void*)bag);
- /* No need to lock 'pi_new' here since this is a new polling island
- and no one has a reference to it yet */
- polling_island_remove_all_fds_locked(pi_new, true, &error);
-
- /* Ref and unref so that the polling island gets deleted during unref
- */
- PI_ADD_REF(pi_new, "dance_of_destruction");
- PI_UNREF(pi_new, "dance_of_destruction");
- goto retry;
- }
- } else {
- pi_new = polling_island_create(nullptr, &error);
- }
-
- GRPC_POLLING_TRACE(
- "add_poll_object: Created new polling island. pi_new: %p (%s: %p, "
- "%s: %p)",
- (void*)pi_new, poll_obj_string(item_type), (void*)item,
- poll_obj_string(bag_type), (void*)bag);
- } else {
- GRPC_POLLING_TRACE(
- "add_poll_object: Same polling island. pi: %p (%s, %s)",
- (void*)pi_new, poll_obj_string(item_type), poll_obj_string(bag_type));
- }
- } else if (item->pi == nullptr) {
- /* GPR_ASSERT(bag->pi != NULL) */
- /* Make pi_new point to latest pi*/
- pi_new = polling_island_lock(bag->pi);
-
- if (item_type == POLL_OBJ_FD) {
- grpc_fd* fd = FD_FROM_PO(item);
- polling_island_add_fds_locked(pi_new, &fd, 1, true, &error);
- }
-
- gpr_mu_unlock(&pi_new->mu);
- GRPC_POLLING_TRACE(
- "add_poll_obj: item->pi was NULL. pi_new: %p (item(%s): %p, "
- "bag(%s): %p)",
- (void*)pi_new, poll_obj_string(item_type), (void*)item,
- poll_obj_string(bag_type), (void*)bag);
- } else if (bag->pi == nullptr) {
- /* GPR_ASSERT(item->pi != NULL) */
- /* Make pi_new to point to latest pi */
- pi_new = polling_island_lock(item->pi);
- gpr_mu_unlock(&pi_new->mu);
- GRPC_POLLING_TRACE(
- "add_poll_obj: bag->pi was NULL. pi_new: %p (item(%s): %p, "
- "bag(%s): %p)",
- (void*)pi_new, poll_obj_string(item_type), (void*)item,
- poll_obj_string(bag_type), (void*)bag);
- } else {
- pi_new = polling_island_merge(item->pi, bag->pi, &error);
- GRPC_POLLING_TRACE(
- "add_poll_obj: polling islands merged. pi_new: %p (item(%s): %p, "
- "bag(%s): %p)",
- (void*)pi_new, poll_obj_string(item_type), (void*)item,
- poll_obj_string(bag_type), (void*)bag);
- }
-
- /* At this point, pi_new is the polling island that both item->pi and bag->pi
- MUST be pointing to */
-
- if (item->pi != pi_new) {
- PI_ADD_REF(pi_new, poll_obj_string(item_type));
- if (item->pi != nullptr) {
- PI_UNREF(item->pi, poll_obj_string(item_type));
- }
- item->pi = pi_new;
- }
-
- if (bag->pi != pi_new) {
- PI_ADD_REF(pi_new, poll_obj_string(bag_type));
- if (bag->pi != nullptr) {
- PI_UNREF(bag->pi, poll_obj_string(bag_type));
- }
- bag->pi = pi_new;
- }
-
- gpr_mu_unlock(&item->mu);
- gpr_mu_unlock(&bag->mu);
-
- GRPC_LOG_IF_ERROR("add_poll_object", error);
-}
-
-static void pollset_add_fd(grpc_pollset* pollset, grpc_fd* fd) {
- add_poll_object(&pollset->po, POLL_OBJ_POLLSET, &fd->po, POLL_OBJ_FD);
-}
-
-/*******************************************************************************
- * Pollset-set Definitions
- */
-
-static grpc_pollset_set* pollset_set_create(void) {
- grpc_pollset_set* pss =
- static_cast<grpc_pollset_set*>(gpr_malloc(sizeof(*pss)));
- gpr_mu_init(&pss->po.mu);
- pss->po.pi = nullptr;
-#ifndef NDEBUG
- pss->po.obj_type = POLL_OBJ_POLLSET_SET;
-#endif
- return pss;
-}
-
-static void pollset_set_destroy(grpc_pollset_set* pss) {
- gpr_mu_destroy(&pss->po.mu);
-
- if (pss->po.pi != nullptr) {
- PI_UNREF(pss->po.pi, "pss_destroy");
- }
-
- gpr_free(pss);
-}
-
-static void pollset_set_add_fd(grpc_pollset_set* pss, grpc_fd* fd) {
- add_poll_object(&pss->po, POLL_OBJ_POLLSET_SET, &fd->po, POLL_OBJ_FD);
-}
-
-static void pollset_set_del_fd(grpc_pollset_set* pss, grpc_fd* fd) {
- /* Nothing to do */
-}
-
-static void pollset_set_add_pollset(grpc_pollset_set* pss, grpc_pollset* ps) {
- add_poll_object(&pss->po, POLL_OBJ_POLLSET_SET, &ps->po, POLL_OBJ_POLLSET);
-}
-
-static void pollset_set_del_pollset(grpc_pollset_set* pss, grpc_pollset* ps) {
- /* Nothing to do */
-}
-
-static void pollset_set_add_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {
- add_poll_object(&bag->po, POLL_OBJ_POLLSET_SET, &item->po,
- POLL_OBJ_POLLSET_SET);
-}
-
-static void pollset_set_del_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {
- /* Nothing to do */
-}
-
-/* Test helper functions
- * */
-void* grpc_fd_get_polling_island(grpc_fd* fd) {
- polling_island* pi;
-
- gpr_mu_lock(&fd->po.mu);
- pi = fd->po.pi;
- gpr_mu_unlock(&fd->po.mu);
-
- return pi;
-}
-
-void* grpc_pollset_get_polling_island(grpc_pollset* ps) {
- polling_island* pi;
-
- gpr_mu_lock(&ps->po.mu);
- pi = ps->po.pi;
- gpr_mu_unlock(&ps->po.mu);
-
- return pi;
-}
-
-bool grpc_are_polling_islands_equal(void* p, void* q) {
- polling_island* p1 = static_cast<polling_island*>(p);
- polling_island* p2 = static_cast<polling_island*>(q);
-
- /* Note: polling_island_lock_pair() may change p1 and p2 to point to the
- latest polling islands in their respective linked lists */
- polling_island_lock_pair(&p1, &p2);
- polling_island_unlock_pair(p1, p2);
-
- return p1 == p2;
-}
-
-/*******************************************************************************
- * Event engine binding
- */
-
-static void shutdown_engine(void) {
- fd_global_shutdown();
- pollset_global_shutdown();
- polling_island_global_shutdown();
-}
-
-static const grpc_event_engine_vtable vtable = {
- sizeof(grpc_pollset),
- true,
-
- fd_create,
- fd_wrapped_fd,
- fd_orphan,
- fd_shutdown,
- fd_notify_on_read,
- fd_notify_on_write,
- fd_notify_on_error,
- fd_become_readable,
- fd_become_writable,
- fd_has_errors,
- fd_is_shutdown,
-
- pollset_init,
- pollset_shutdown,
- pollset_destroy,
- pollset_work,
- pollset_kick,
- pollset_add_fd,
-
- pollset_set_create,
- pollset_set_destroy,
- pollset_set_add_pollset,
- pollset_set_del_pollset,
- pollset_set_add_pollset_set,
- pollset_set_del_pollset_set,
- pollset_set_add_fd,
- pollset_set_del_fd,
-
- shutdown_engine,
-};
-
-/* It is possible that GLIBC has epoll but the underlying kernel doesn't.
- * Create a dummy epoll_fd to make sure epoll support is available */
-static bool is_epoll_available() {
- int fd = epoll_create1(EPOLL_CLOEXEC);
- if (fd < 0) {
- gpr_log(
- GPR_ERROR,
- "epoll_create1 failed with error: %d. Not using epoll polling engine",
- fd);
- return false;
- }
- close(fd);
- return true;
-}
-
-const grpc_event_engine_vtable* grpc_init_epollsig_linux(
- bool explicit_request) {
- /* If use of signals is disabled, we cannot use epoll engine*/
- if (is_grpc_wakeup_signal_initialized && grpc_wakeup_signal < 0) {
- gpr_log(GPR_ERROR, "Skipping epollsig because use of signals is disabled.");
- return nullptr;
- }
-
- if (!grpc_has_wakeup_fd()) {
- gpr_log(GPR_ERROR, "Skipping epollsig because of no wakeup fd.");
- return nullptr;
- }
-
- if (!is_epoll_available()) {
- gpr_log(GPR_ERROR, "Skipping epollsig because epoll is unavailable.");
- return nullptr;
- }
-
- if (!is_grpc_wakeup_signal_initialized) {
- if (explicit_request) {
- grpc_use_signal(SIGRTMIN + 6);
- } else {
- gpr_log(GPR_ERROR,
- "Skipping epollsig because uninitialized wakeup signal.");
- return nullptr;
- }
- }
-
- fd_global_init();
-
- if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) {
- return nullptr;
- }
-
- if (!GRPC_LOG_IF_ERROR("polling_island_global_init",
- polling_island_global_init())) {
- return nullptr;
- }
-
- return &vtable;
-}
-
-#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */
-#if defined(GRPC_POSIX_SOCKET_EV_EPOLLSIG)
-#include "src/core/lib/iomgr/ev_epollsig_linux.h"
-/* If GRPC_LINUX_EPOLL_CREATE1 is not defined, it means
- epoll_create1 is not available. Return NULL */
-const grpc_event_engine_vtable* grpc_init_epollsig_linux(
- bool explicit_request) {
- return nullptr;
-}
-#endif /* defined(GRPC_POSIX_SOCKET) */
-
-void grpc_use_signal(int signum) {}
-#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.h b/src/core/lib/iomgr/ev_epollsig_linux.h
deleted file mode 100644
index 2ba2f0a63b..0000000000
--- a/src/core/lib/iomgr/ev_epollsig_linux.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H
-#define GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/iomgr/ev_posix.h"
-#include "src/core/lib/iomgr/port.h"
-
-const grpc_event_engine_vtable* grpc_init_epollsig_linux(bool explicit_request);
-
-#ifdef GRPC_LINUX_EPOLL_CREATE1
-void* grpc_fd_get_polling_island(grpc_fd* fd);
-void* grpc_pollset_get_polling_island(grpc_pollset* ps);
-bool grpc_are_polling_islands_equal(void* p, void* q);
-#endif /* defined(GRPC_LINUX_EPOLL_CREATE1) */
-
-#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H */
diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc
index d4377e2d50..8a7dc7b004 100644
--- a/src/core/lib/iomgr/ev_posix.cc
+++ b/src/core/lib/iomgr/ev_posix.cc
@@ -35,7 +35,6 @@
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/ev_epoll1_linux.h"
#include "src/core/lib/iomgr/ev_epollex_linux.h"
-#include "src/core/lib/iomgr/ev_epollsig_linux.h"
#include "src/core/lib/iomgr/ev_poll_posix.h"
grpc_core::TraceFlag grpc_polling_trace(false,
@@ -123,13 +122,13 @@ const grpc_event_engine_vtable* init_non_polling(bool explicit_request) {
// environment variable if that variable is set (which should be a
// comma-separated list of one or more event engine names)
static event_engine_factory g_factories[] = {
- {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
- {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
- {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
- {"epollsig", grpc_init_epollsig_linux}, {"poll", grpc_init_poll_posix},
- {"poll-cv", grpc_init_poll_cv_posix}, {"none", init_non_polling},
- {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
- {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
+ {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
+ {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
+ {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
+ {"poll", grpc_init_poll_posix}, {"poll-cv", grpc_init_poll_cv_posix},
+ {"none", init_non_polling}, {ENGINE_TAIL_CUSTOM, nullptr},
+ {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
+ {ENGINE_TAIL_CUSTOM, nullptr},
};
static void add(const char* beg, const char* end, char*** ss, size_t* ns) {
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index abf96662f5..c8046b21dc 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -82,6 +82,11 @@
#define GRPC_LINUX_SOCKETUTILS 1
#endif
#endif
+#ifdef LINUX_VERSION_CODE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+#define GRPC_HAVE_TCP_USER_TIMEOUT
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) */
+#endif /* LINUX_VERSION_CODE */
#ifndef __GLIBC__
#define GRPC_LINUX_EPOLL 1
#define GRPC_LINUX_EPOLL_CREATE1 1
@@ -110,7 +115,6 @@
#define GRPC_POSIX_SOCKET_EV 1
#define GRPC_POSIX_SOCKET_EV_EPOLL1 1
#define GRPC_POSIX_SOCKET_EV_EPOLLEX 1
-#define GRPC_POSIX_SOCKET_EV_EPOLLSIG 1
#define GRPC_POSIX_SOCKET_EV_POLL 1
#define GRPC_POSIX_SOCKET_RESOLVE_ADDRESS 1
#define GRPC_POSIX_SOCKET_SOCKADDR 1
@@ -178,7 +182,6 @@
#define GRPC_POSIX_SOCKET_ARES_EV_DRIVER 1
#define GRPC_POSIX_SOCKET_EV 1
#define GRPC_POSIX_SOCKET_EV_EPOLLEX 1
-#define GRPC_POSIX_SOCKET_EV_EPOLLSIG 1
#define GRPC_POSIX_SOCKET_EV_POLL 1
#define GRPC_POSIX_SOCKET_EV_EPOLL1 1
#define GRPC_POSIX_SOCKET_IOMGR 1
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc
index c4b991c94d..50674b0845 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.cc
+++ b/src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -41,6 +41,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/sockaddr.h"
@@ -222,6 +223,95 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) {
return GRPC_ERROR_NONE;
}
+/* The default values for TCP_USER_TIMEOUT are currently configured to be in
+ * line with the default values of KEEPALIVE_TIMEOUT as proposed in
+ * https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md */
+#define DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
+#define DEFAULT_SERVER_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
+
+static int g_default_client_tcp_user_timeout_ms =
+ DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS;
+static int g_default_server_tcp_user_timeout_ms =
+ DEFAULT_SERVER_TCP_USER_TIMEOUT_MS;
+static bool g_default_client_tcp_user_timeout_enabled = false;
+static bool g_default_server_tcp_user_timeout_enabled = true;
+
+void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client) {
+ if (is_client) {
+ g_default_client_tcp_user_timeout_enabled = enable;
+ if (timeout > 0) {
+ g_default_client_tcp_user_timeout_ms = timeout;
+ }
+ } else {
+ g_default_server_tcp_user_timeout_enabled = enable;
+ if (timeout > 0) {
+ g_default_server_tcp_user_timeout_ms = timeout;
+ }
+ }
+}
+
+/* Set TCP_USER_TIMEOUT */
+grpc_error* grpc_set_socket_tcp_user_timeout(
+ int fd, const grpc_channel_args* channel_args, bool is_client) {
+#ifdef GRPC_HAVE_TCP_USER_TIMEOUT
+ bool enable;
+ int timeout;
+ if (is_client) {
+ enable = g_default_client_tcp_user_timeout_enabled;
+ timeout = g_default_client_tcp_user_timeout_ms;
+ } else {
+ enable = g_default_server_tcp_user_timeout_enabled;
+ timeout = g_default_server_tcp_user_timeout_ms;
+ }
+ if (channel_args) {
+ for (unsigned int i = 0; i < channel_args->num_args; i++) {
+ if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
+ const int value = grpc_channel_arg_get_integer(
+ &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
+ /* Continue using default if value is 0 */
+ if (value == 0) {
+ continue;
+ }
+ /* Disable if value is INT_MAX */
+ enable = value != INT_MAX;
+ } else if (0 == strcmp(channel_args->args[i].key,
+ GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
+ const int value = grpc_channel_arg_get_integer(
+ &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
+ /* Continue using default if value is 0 */
+ if (value == 0) {
+ continue;
+ }
+ timeout = value;
+ }
+ }
+ }
+ if (enable) {
+ extern grpc_core::TraceFlag grpc_tcp_trace;
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_INFO, "Enabling TCP_USER_TIMEOUT with a timeout of %d ms",
+ timeout);
+ }
+ int newval;
+ socklen_t len = sizeof(newval);
+ if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout,
+ sizeof(timeout))) {
+ return GRPC_OS_ERROR(errno, "setsockopt(TCP_USER_TIMEOUT)");
+ }
+ if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
+ return GRPC_OS_ERROR(errno, "getsockopt(TCP_USER_TIMEOUT)");
+ }
+ if (newval != timeout) {
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Failed to set TCP_USER_TIMEOUT");
+ }
+ }
+#else
+ gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform");
+#endif /* GRPC_HAVE_TCP_USER_TIMEOUT */
+ return GRPC_ERROR_NONE;
+}
+
/* set a socket using a grpc_socket_mutator */
grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) {
GPR_ASSERT(mutator);
diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h
index b3fd58a530..71a304dc4e 100644
--- a/src/core/lib/iomgr/socket_utils_posix.h
+++ b/src/core/lib/iomgr/socket_utils_posix.h
@@ -53,6 +53,13 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency);
/* set SO_REUSEPORT */
grpc_error* grpc_set_socket_reuse_port(int fd, int reuse);
+/* Configure the default values for TCP_USER_TIMEOUT */
+void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client);
+
+/* Set TCP_USER_TIMEOUT */
+grpc_error* grpc_set_socket_tcp_user_timeout(
+ int fd, const grpc_channel_args* channel_args, bool is_client);
+
/* Returns true if this system can create AF_INET6 sockets bound to ::1.
The value is probed once, and cached for the life of the process.
diff --git a/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc
index 9c989b7dfe..8553ed0db4 100644
--- a/src/core/lib/iomgr/tcp_client_posix.cc
+++ b/src/core/lib/iomgr/tcp_client_posix.cc
@@ -76,6 +76,9 @@ static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd,
if (!grpc_is_unix_socket(addr)) {
err = grpc_set_socket_low_latency(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_tcp_user_timeout(fd, channel_args,
+ true /* is_client */);
+ if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_no_sigpipe_if_possible(fd);
if (err != GRPC_ERROR_NONE) goto error;
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
index 9595c028ce..8d8d3f4273 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
@@ -166,6 +166,9 @@ grpc_error* grpc_tcp_server_prepare_socket(grpc_tcp_server* s, int fd,
if (err != GRPC_ERROR_NONE) goto error;
err = grpc_set_socket_reuse_addr(fd, 1);
if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_tcp_user_timeout(fd, s->channel_args,
+ false /* is_client */);
+ if (err != GRPC_ERROR_NONE) goto error;
}
err = grpc_set_socket_no_sigpipe_if_possible(fd);
if (err != GRPC_ERROR_NONE) goto error;
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
index 0a39c6c485..118d18d119 100644
--- a/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
@@ -72,7 +72,8 @@ static void target_service_account_destroy(
static const grpc_alts_credentials_options_vtable vtable = {
alts_client_options_copy, alts_client_options_destroy};
-grpc_alts_credentials_options* grpc_alts_credentials_client_options_create() {
+grpc_alts_credentials_options* grpc_alts_credentials_client_options_create(
+ void) {
auto client_options = static_cast<grpc_alts_credentials_client_options*>(
gpr_zalloc(sizeof(grpc_alts_credentials_client_options)));
client_options->base.vtable = &vtable;
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
index 62aa7a620a..1a59c45675 100644
--- a/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
@@ -36,7 +36,8 @@ static void alts_server_options_destroy(
static const grpc_alts_credentials_options_vtable vtable = {
alts_server_options_copy, alts_server_options_destroy};
-grpc_alts_credentials_options* grpc_alts_credentials_server_options_create() {
+grpc_alts_credentials_options* grpc_alts_credentials_server_options_create(
+ void) {
grpc_alts_credentials_server_options* server_options =
static_cast<grpc_alts_credentials_server_options*>(
gpr_zalloc(sizeof(*server_options)));
diff --git a/src/core/lib/security/transport/server_auth_filter.cc b/src/core/lib/security/transport/server_auth_filter.cc
index 552e70130a..b99fc5e178 100644
--- a/src/core/lib/security/transport/server_auth_filter.cc
+++ b/src/core/lib/security/transport/server_auth_filter.cc
@@ -41,9 +41,11 @@ struct call_data {
grpc_transport_stream_op_batch* recv_initial_metadata_batch;
grpc_closure* original_recv_initial_metadata_ready;
grpc_closure recv_initial_metadata_ready;
- grpc_error* error;
+ grpc_error* recv_initial_metadata_error;
grpc_closure recv_trailing_metadata_ready;
grpc_closure* original_recv_trailing_metadata_ready;
+ grpc_error* recv_trailing_metadata_error;
+ bool seen_recv_trailing_metadata_ready;
grpc_metadata_array md;
const grpc_metadata* consumed_md;
size_t num_consumed_md;
@@ -114,8 +116,16 @@ static void on_md_processing_done_inner(grpc_call_element* elem,
batch->payload->recv_initial_metadata.recv_initial_metadata,
remove_consumed_md, elem, "Response metadata filtering error");
}
- calld->error = GRPC_ERROR_REF(error);
- GRPC_CLOSURE_SCHED(calld->original_recv_initial_metadata_ready, error);
+ calld->recv_initial_metadata_error = GRPC_ERROR_REF(error);
+ grpc_closure* closure = calld->original_recv_initial_metadata_ready;
+ calld->original_recv_initial_metadata_ready = nullptr;
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error,
+ "continue recv_trailing_metadata_ready");
+ }
+ GRPC_CLOSURE_SCHED(closure, error);
}
// Called from application code.
@@ -184,14 +194,30 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
return;
}
}
- GRPC_CLOSURE_RUN(calld->original_recv_initial_metadata_ready,
- GRPC_ERROR_REF(error));
+ grpc_closure* closure = calld->original_recv_initial_metadata_ready;
+ calld->original_recv_initial_metadata_ready = nullptr;
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error,
+ "continue recv_trailing_metadata_ready");
+ }
+ GRPC_CLOSURE_RUN(closure, GRPC_ERROR_REF(error));
}
static void recv_trailing_metadata_ready(void* user_data, grpc_error* err) {
grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
call_data* calld = static_cast<call_data*>(elem->call_data);
- err = grpc_error_add_child(GRPC_ERROR_REF(err), GRPC_ERROR_REF(calld->error));
+ if (calld->original_recv_initial_metadata_ready != nullptr) {
+ calld->recv_trailing_metadata_error = GRPC_ERROR_REF(err);
+ calld->seen_recv_trailing_metadata_ready = true;
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring recv_trailing_metadata_ready until "
+ "after recv_initial_metadata_ready");
+ return;
+ }
+ err = grpc_error_add_child(
+ GRPC_ERROR_REF(err), GRPC_ERROR_REF(calld->recv_initial_metadata_error));
GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, err);
}
@@ -249,7 +275,7 @@ static void destroy_call_elem(grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
call_data* calld = static_cast<call_data*>(elem->call_data);
- GRPC_ERROR_UNREF(calld->error);
+ GRPC_ERROR_UNREF(calld->recv_initial_metadata_error);
}
/* Constructor for channel_data */
diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc
index 11b438f5dc..a9349afa68 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -207,7 +207,7 @@ struct grpc_call {
grpc_server* server;
} server;
} final_op;
- grpc_error* status_error;
+ gpr_atm status_error;
/* recv_state can contain one of the following values:
RECV_NONE : : no initial metadata and messages received
@@ -519,10 +519,12 @@ static void destroy_call(void* call, grpc_error* error) {
GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
}
- grpc_error_get_status(c->status_error, c->send_deadline,
+ grpc_error* status_error =
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&c->status_error));
+ grpc_error_get_status(status_error, c->send_deadline,
&c->final_info.final_status, nullptr, nullptr,
&(c->final_info.error_string));
- GRPC_ERROR_UNREF(c->status_error);
+ GRPC_ERROR_UNREF(status_error);
c->final_info.stats.latency =
gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
@@ -705,7 +707,7 @@ static void set_final_status(grpc_call* call, grpc_error* error) {
call->final_op.client.error_string);
// explicitly take a ref
grpc_slice_ref_internal(*call->final_op.client.status_details);
- call->status_error = error;
+ gpr_atm_rel_store(&call->status_error, reinterpret_cast<gpr_atm>(error));
grpc_core::channelz::ChannelNode* channelz_channel =
grpc_channel_get_channelz_node(call->channel);
if (channelz_channel != nullptr) {
@@ -717,7 +719,9 @@ static void set_final_status(grpc_call* call, grpc_error* error) {
}
} else {
*call->final_op.server.cancelled =
- error != GRPC_ERROR_NONE || call->status_error != GRPC_ERROR_NONE;
+ error != GRPC_ERROR_NONE ||
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&call->status_error)) !=
+ GRPC_ERROR_NONE;
grpc_core::channelz::ServerNode* channelz_server =
grpc_server_get_channelz_node(call->final_op.server.server);
if (channelz_server != nullptr) {
@@ -1686,7 +1690,8 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
}
}
- call->status_error = status_error;
+ gpr_atm_rel_store(&call->status_error,
+ reinterpret_cast<gpr_atm>(status_error));
if (!prepare_application_metadata(
call,
static_cast<int>(
diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc
index 0769d9e4f6..5dc9991f70 100644
--- a/src/core/lib/surface/completion_queue.cc
+++ b/src/core/lib/surface/completion_queue.cc
@@ -184,7 +184,8 @@ static const cq_poller_vtable g_poller_vtable_by_poller_type[] = {
typedef struct cq_vtable {
grpc_cq_completion_type cq_completion_type;
size_t data_size;
- void (*init)(void* data, grpc_core::CQCallbackInterface* shutdown_callback);
+ void (*init)(void* data,
+ grpc_experimental_completion_queue_functor* shutdown_callback);
void (*shutdown)(grpc_completion_queue* cq);
void (*destroy)(void* data);
bool (*begin_op)(grpc_completion_queue* cq, void* tag);
@@ -267,7 +268,7 @@ typedef struct cq_callback_data {
bool shutdown_called;
/** A callback that gets invoked when the CQ completes shutdown */
- grpc_core::CQCallbackInterface* shutdown_callback;
+ grpc_experimental_completion_queue_functor* shutdown_callback;
} cq_callback_data;
/* Completion queue structure */
@@ -333,12 +334,12 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag,
gpr_timespec deadline, void* reserved);
// Note that cq_init_next and cq_init_pluck do not use the shutdown_callback
-static void cq_init_next(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback);
-static void cq_init_pluck(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback);
-static void cq_init_callback(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback);
+static void cq_init_next(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback);
+static void cq_init_pluck(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback);
+static void cq_init_callback(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback);
static void cq_destroy_next(void* data);
static void cq_destroy_pluck(void* data);
static void cq_destroy_callback(void* data);
@@ -462,7 +463,7 @@ static long cq_event_queue_num_items(grpc_cq_event_queue* q) {
grpc_completion_queue* grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type,
- grpc_core::CQCallbackInterface* shutdown_callback) {
+ grpc_experimental_completion_queue_functor* shutdown_callback) {
GPR_TIMER_SCOPE("grpc_completion_queue_create_internal", 0);
grpc_completion_queue* cq;
@@ -497,8 +498,8 @@ grpc_completion_queue* grpc_completion_queue_create_internal(
return cq;
}
-static void cq_init_next(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback) {
+static void cq_init_next(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback) {
cq_next_data* cqd = static_cast<cq_next_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
@@ -513,8 +514,8 @@ static void cq_destroy_next(void* data) {
cq_event_queue_destroy(&cqd->queue);
}
-static void cq_init_pluck(void* data,
- grpc_core::CQCallbackInterface* shutdown_callback) {
+static void cq_init_pluck(
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback) {
cq_pluck_data* cqd = static_cast<cq_pluck_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
@@ -532,7 +533,7 @@ static void cq_destroy_pluck(void* data) {
}
static void cq_init_callback(
- void* data, grpc_core::CQCallbackInterface* shutdown_callback) {
+ void* data, grpc_experimental_completion_queue_functor* shutdown_callback) {
cq_callback_data* cqd = static_cast<cq_callback_data*>(data);
/* Initial count is dropped by grpc_completion_queue_shutdown */
gpr_atm_no_barrier_store(&cqd->pending_events, 1);
@@ -859,7 +860,8 @@ static void cq_end_op_for_callback(
GRPC_ERROR_UNREF(error);
- (static_cast<grpc_core::CQCallbackInterface*>(tag))->Run(is_success);
+ auto* functor = static_cast<grpc_experimental_completion_queue_functor*>(tag);
+ (*functor->functor_run)(functor, is_success);
}
void grpc_cq_end_op(grpc_completion_queue* cq, void* tag, grpc_error* error,
@@ -1343,7 +1345,7 @@ static void cq_finish_shutdown_callback(grpc_completion_queue* cq) {
GPR_ASSERT(cqd->shutdown_called);
cq->poller_vtable->shutdown(POLLSET_FROM_CQ(cq), &cq->pollset_shutdown_done);
- callback->Run(true);
+ (*callback->functor_run)(callback, true);
}
static void cq_shutdown_callback(grpc_completion_queue* cq) {
@@ -1364,9 +1366,11 @@ static void cq_shutdown_callback(grpc_completion_queue* cq) {
}
cqd->shutdown_called = true;
if (gpr_atm_full_fetch_add(&cqd->pending_events, -1) == 1) {
+ gpr_mu_unlock(cq->mu);
cq_finish_shutdown_callback(cq);
+ } else {
+ gpr_mu_unlock(cq->mu);
}
- gpr_mu_unlock(cq->mu);
GRPC_CQ_INTERNAL_UNREF(cq, "shutting_down (callback cq)");
}
diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h
index a7c524d8e8..d60fe6d6ef 100644
--- a/src/core/lib/surface/completion_queue.h
+++ b/src/core/lib/surface/completion_queue.h
@@ -48,23 +48,6 @@ typedef struct grpc_cq_completion {
uintptr_t next;
} grpc_cq_completion;
-/// For callback CQs, the tag that is passed in for an operation must
-/// actually be a pointer to an implementation of the following class.
-/// When the operation completes, the tag will be typecasted from void*
-/// to grpc_core::CQCallbackInterface* and then the Run method will be
-/// invoked on it. In practice, the language binding (e.g., C++ API
-/// implementation) is responsible for providing and using an implementation
-/// of this abstract base class.
-namespace grpc_core {
-class CQCallbackInterface {
- public:
- virtual ~CQCallbackInterface() {}
- virtual void Run(bool) GRPC_ABSTRACT;
-
- GRPC_ABSTRACT_BASE_CLASS
-};
-} // namespace grpc_core
-
#ifndef NDEBUG
void grpc_cq_internal_ref(grpc_completion_queue* cc, const char* reason,
const char* file, int line);
@@ -106,6 +89,6 @@ int grpc_get_cq_poll_num(grpc_completion_queue* cc);
grpc_completion_queue* grpc_completion_queue_create_internal(
grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type,
- grpc_core::CQCallbackInterface* shutdown_callback);
+ grpc_experimental_completion_queue_functor* shutdown_callback);
#endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/lib/surface/completion_queue_factory.cc b/src/core/lib/surface/completion_queue_factory.cc
index ed92dd7eba..2616c156e4 100644
--- a/src/core/lib/surface/completion_queue_factory.cc
+++ b/src/core/lib/surface/completion_queue_factory.cc
@@ -31,8 +31,7 @@ static grpc_completion_queue* default_create(
const grpc_completion_queue_factory* factory,
const grpc_completion_queue_attributes* attr) {
return grpc_completion_queue_create_internal(
- attr->cq_completion_type, attr->cq_polling_type,
- static_cast<grpc_core::CQCallbackInterface*>(attr->cq_shutdown_cb));
+ attr->cq_completion_type, attr->cq_polling_type, attr->cq_shutdown_cb);
}
static grpc_completion_queue_factory_vtable default_vtable = {default_create};
@@ -73,7 +72,8 @@ grpc_completion_queue* grpc_completion_queue_create_for_pluck(void* reserved) {
}
grpc_completion_queue* grpc_completion_queue_create_for_callback(
- void* shutdown_callback, void* reserved) {
+ grpc_experimental_completion_queue_functor* shutdown_callback,
+ void* reserved) {
GPR_ASSERT(!reserved);
grpc_completion_queue_attributes attr = {
2, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, shutdown_callback};
diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc
index 5fa58ffdec..72ddc2648d 100644
--- a/src/core/lib/surface/server.cc
+++ b/src/core/lib/surface/server.cc
@@ -150,12 +150,15 @@ struct call_data {
grpc_closure kill_zombie_closure;
grpc_closure* on_done_recv_initial_metadata;
grpc_closure recv_trailing_metadata_ready;
- grpc_error* error;
+ grpc_error* recv_initial_metadata_error;
grpc_closure* original_recv_trailing_metadata_ready;
+ grpc_error* recv_trailing_metadata_error;
+ bool seen_recv_trailing_metadata_ready;
grpc_closure publish;
call_data* pending_next;
+ grpc_call_combiner* call_combiner;
};
struct request_matcher {
@@ -727,21 +730,43 @@ static void server_on_recv_initial_metadata(void* ptr, grpc_error* error) {
if (calld->host_set && calld->path_set) {
/* do nothing */
} else {
+ /* Pass the error reference to calld->recv_initial_metadata_error */
grpc_error* src_error = error;
error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
- "Missing :authority or :path", &error, 1);
+ "Missing :authority or :path", &src_error, 1);
GRPC_ERROR_UNREF(src_error);
+ calld->recv_initial_metadata_error = GRPC_ERROR_REF(error);
}
-
- GRPC_CLOSURE_RUN(calld->on_done_recv_initial_metadata, error);
+ grpc_closure* closure = calld->on_done_recv_initial_metadata;
+ calld->on_done_recv_initial_metadata = nullptr;
+ if (calld->seen_recv_trailing_metadata_ready) {
+ GRPC_CALL_COMBINER_START(calld->call_combiner,
+ &calld->recv_trailing_metadata_ready,
+ calld->recv_trailing_metadata_error,
+ "continue server_recv_trailing_metadata_ready");
+ }
+ GRPC_CLOSURE_RUN(closure, error);
}
static void server_recv_trailing_metadata_ready(void* user_data,
- grpc_error* err) {
+ grpc_error* error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
call_data* calld = static_cast<call_data*>(elem->call_data);
- err = grpc_error_add_child(GRPC_ERROR_REF(err), GRPC_ERROR_REF(calld->error));
- GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, err);
+ if (calld->on_done_recv_initial_metadata != nullptr) {
+ calld->recv_trailing_metadata_error = GRPC_ERROR_REF(error);
+ calld->seen_recv_trailing_metadata_ready = true;
+ GRPC_CLOSURE_INIT(&calld->recv_trailing_metadata_ready,
+ server_recv_trailing_metadata_ready, elem,
+ grpc_schedule_on_exec_ctx);
+ GRPC_CALL_COMBINER_STOP(calld->call_combiner,
+ "deferring server_recv_trailing_metadata_ready "
+ "until after server_on_recv_initial_metadata");
+ return;
+ }
+ error =
+ grpc_error_add_child(GRPC_ERROR_REF(error),
+ GRPC_ERROR_REF(calld->recv_initial_metadata_error));
+ GRPC_CLOSURE_RUN(calld->original_recv_trailing_metadata_ready, error);
}
static void server_mutate_op(grpc_call_element* elem,
@@ -845,6 +870,7 @@ static grpc_error* init_call_elem(grpc_call_element* elem,
memset(calld, 0, sizeof(call_data));
calld->deadline = GRPC_MILLIS_INF_FUTURE;
calld->call = grpc_call_from_top_element(elem);
+ calld->call_combiner = args->call_combiner;
GRPC_CLOSURE_INIT(&calld->server_on_recv_initial_metadata,
server_on_recv_initial_metadata, elem,
@@ -863,7 +889,7 @@ static void destroy_call_elem(grpc_call_element* elem,
call_data* calld = static_cast<call_data*>(elem->call_data);
GPR_ASSERT(calld->state != PENDING);
- GRPC_ERROR_UNREF(calld->error);
+ GRPC_ERROR_UNREF(calld->recv_initial_metadata_error);
if (calld->host_set) {
grpc_slice_unref_internal(calld->host);
}
diff --git a/src/core/lib/transport/metadata.cc b/src/core/lib/transport/metadata.cc
index d10194a2fe..d164502280 100644
--- a/src/core/lib/transport/metadata.cc
+++ b/src/core/lib/transport/metadata.cc
@@ -342,24 +342,6 @@ grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_metadata* metadata) {
changed ? nullptr : reinterpret_cast<grpc_mdelem_data*>(metadata));
}
-static size_t get_base64_encoded_size(size_t raw_length) {
- static const uint8_t tail_xtra[3] = {0, 2, 3};
- return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
-}
-
-size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem,
- bool use_true_binary_metadata) {
- size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(GRPC_MDKEY(elem));
- size_t value_len = GRPC_SLICE_LENGTH(GRPC_MDVALUE(elem));
- if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
- return overhead_and_key + (use_true_binary_metadata
- ? value_len + 1
- : get_base64_encoded_size(value_len));
- } else {
- return overhead_and_key + value_len;
- }
-}
-
grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd DEBUG_ARGS) {
switch (GRPC_MDELEM_STORAGE(gmd)) {
case GRPC_MDELEM_STORAGE_EXTERNAL:
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index 78df4bc3a3..338082276c 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -125,9 +125,6 @@ grpc_mdelem grpc_mdelem_create(
bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b);
-size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem,
- bool use_true_binary_metadata);
-
/* Mutator and accessor for grpc_mdelem user data. The destructor function
is used as a type tag and is checked during user_data fetch. */
void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*if_destroy_func)(void*));
diff --git a/src/core/lib/transport/metadata_batch.cc b/src/core/lib/transport/metadata_batch.cc
index 49740fcd1e..761aad19c4 100644
--- a/src/core/lib/transport/metadata_batch.cc
+++ b/src/core/lib/transport/metadata_batch.cc
@@ -105,7 +105,7 @@ static grpc_error* maybe_link_callout(grpc_metadata_batch* batch,
return GRPC_ERROR_NONE;
}
if (batch->idx.array[idx] == nullptr) {
- if (grpc_static_callout_is_default[idx]) ++batch->list.default_count;
+ ++batch->list.default_count;
batch->idx.array[idx] = storage;
return GRPC_ERROR_NONE;
}
@@ -121,7 +121,7 @@ static void maybe_unlink_callout(grpc_metadata_batch* batch,
if (idx == GRPC_BATCH_CALLOUTS_COUNT) {
return;
}
- if (grpc_static_callout_is_default[idx]) --batch->list.default_count;
+ --batch->list.default_count;
GPR_ASSERT(batch->idx.array[idx] != nullptr);
batch->idx.array[idx] = nullptr;
}
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 7068750b6f..0bcbb32d1f 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -82,6 +82,7 @@ void grpc_metadata_batch_set_value(grpc_linked_mdelem* storage,
grpc_error* grpc_metadata_batch_link_head(grpc_metadata_batch* batch,
grpc_linked_mdelem* storage)
GRPC_MUST_USE_RESULT;
+
/** Add \a storage to the end of \a batch. storage->md is
assumed to be valid.
\a storage is owned by the caller and must survive for the
@@ -100,6 +101,7 @@ grpc_error* grpc_metadata_batch_link_tail(grpc_metadata_batch* batch,
grpc_error* grpc_metadata_batch_add_head(
grpc_metadata_batch* batch, grpc_linked_mdelem* storage,
grpc_mdelem elem_to_add) GRPC_MUST_USE_RESULT;
+
/** Add \a elem_to_add as the last element in \a batch, using
\a storage as backing storage for the linked list element.
\a storage is owned by the caller and must survive for the
diff --git a/src/core/lib/transport/static_metadata.cc b/src/core/lib/transport/static_metadata.cc
index 6a5144f21a..ed88aa3f28 100644
--- a/src/core/lib/transport/static_metadata.cc
+++ b/src/core/lib/transport/static_metadata.cc
@@ -568,33 +568,6 @@ grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
};
-bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {
- true, // :path
- true, // :method
- true, // :status
- true, // :authority
- true, // :scheme
- true, // te
- true, // grpc-message
- true, // grpc-status
- true, // grpc-payload-bin
- true, // grpc-encoding
- true, // grpc-accept-encoding
- true, // grpc-server-stats-bin
- true, // grpc-tags-bin
- true, // grpc-trace-bin
- true, // content-type
- true, // content-encoding
- true, // accept-encoding
- true, // grpc-internal-encoding-request
- true, // grpc-internal-stream-encoding-request
- true, // user-agent
- true, // host
- true, // lb-token
- true, // grpc-previous-rpc-attempts
- true, // grpc-retry-pushback-ms
-};
-
const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78,
79, 80, 81, 82};
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index b3a10f5873..1e95f4e5bb 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -587,8 +587,6 @@ typedef union {
GRPC_BATCH_CALLOUTS_COUNT) \
: GRPC_BATCH_CALLOUTS_COUNT)
-extern bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT];
-
extern const uint8_t grpc_static_accept_encoding_metadata[8];
#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \
(GRPC_MAKE_MDELEM( \
diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc
index 39b891c2e1..c59059f045 100644
--- a/src/cpp/client/channel_cc.cc
+++ b/src/cpp/client/channel_cc.cc
@@ -42,8 +42,10 @@
#include <grpcpp/support/time.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/surface/completion_queue.h"
namespace grpc {
@@ -53,7 +55,12 @@ Channel::Channel(const grpc::string& host, grpc_channel* channel)
g_gli_initializer.summon();
}
-Channel::~Channel() { grpc_channel_destroy(c_channel_); }
+Channel::~Channel() {
+ grpc_channel_destroy(c_channel_);
+ if (callback_cq_ != nullptr) {
+ callback_cq_->Shutdown();
+ }
+}
namespace {
@@ -135,8 +142,8 @@ void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops,
size_t nops = 0;
grpc_op cops[MAX_OPS];
ops->FillOps(call->call(), cops, &nops);
- GPR_ASSERT(GRPC_CALL_OK ==
- grpc_call_start_batch(call->call(), cops, nops, ops, nullptr));
+ GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(call->call(), cops, nops,
+ ops->cq_tag(), nullptr));
}
void* Channel::RegisterMethod(const char* method) {
@@ -185,4 +192,41 @@ bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed,
return ok;
}
+namespace {
+class ShutdownCallback : public grpc_experimental_completion_queue_functor {
+ public:
+ ShutdownCallback() { functor_run = &ShutdownCallback::Run; }
+ // TakeCQ takes ownership of the cq into the shutdown callback
+ // so that the shutdown callback will be responsible for destroying it
+ void TakeCQ(CompletionQueue* cq) { cq_ = cq; }
+
+ // The Run function will get invoked by the completion queue library
+ // when the shutdown is actually complete
+ static void Run(grpc_experimental_completion_queue_functor* cb, int) {
+ auto* callback = static_cast<ShutdownCallback*>(cb);
+ delete callback->cq_;
+ grpc_core::Delete(callback);
+ }
+
+ private:
+ CompletionQueue* cq_ = nullptr;
+};
+} // namespace
+
+CompletionQueue* Channel::CallbackCQ() {
+ // TODO(vjpai): Consider using a single global CQ for the default CQ
+ // if there is no explicit per-channel CQ registered
+ std::lock_guard<std::mutex> l(mu_);
+ if (callback_cq_ == nullptr) {
+ auto* shutdown_callback = grpc_core::New<ShutdownCallback>();
+ callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{
+ GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING,
+ shutdown_callback});
+
+ // Transfer ownership of the new cq to its own shutdown callback
+ shutdown_callback->TakeCQ(callback_cq_);
+ }
+ return callback_cq_;
+}
+
} // namespace grpc
diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc
index 67ef46bebe..87902b26f0 100644
--- a/src/cpp/client/generic_stub.cc
+++ b/src/cpp/client/generic_stub.cc
@@ -16,9 +16,11 @@
*
*/
-#include <grpcpp/generic/generic_stub.h>
+#include <functional>
+#include <grpcpp/generic/generic_stub.h>
#include <grpcpp/impl/rpc_method.h>
+#include <grpcpp/support/client_callback.h>
namespace grpc {
@@ -60,4 +62,14 @@ std::unique_ptr<GenericClientAsyncResponseReader> GenericStub::PrepareUnaryCall(
context, request, false));
}
+void GenericStub::experimental_type::UnaryCall(
+ ClientContext* context, const grpc::string& method,
+ const ByteBuffer* request, ByteBuffer* response,
+ std::function<void(Status)> on_completion) {
+ internal::CallbackUnaryCall(
+ stub_->channel_.get(),
+ internal::RpcMethod(method.c_str(), internal::RpcMethod::NORMAL_RPC),
+ context, request, response, std::move(on_completion));
+}
+
} // namespace grpc
diff --git a/src/cpp/common/alarm.cc b/src/cpp/common/alarm.cc
index 15a373d8a5..5819a4210b 100644
--- a/src/cpp/common/alarm.cc
+++ b/src/cpp/common/alarm.cc
@@ -39,17 +39,6 @@ class AlarmImpl : public CompletionQueueTag {
AlarmImpl() : cq_(nullptr), tag_(nullptr) {
gpr_ref_init(&refs_, 1);
grpc_timer_init_unset(&timer_);
- GRPC_CLOSURE_INIT(&on_alarm_,
- [](void* arg, grpc_error* error) {
- // queue the op on the completion queue
- AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
- alarm->Ref();
- grpc_cq_end_op(
- alarm->cq_, alarm, error,
- [](void* arg, grpc_cq_completion* completion) {},
- arg, &alarm->completion_);
- },
- this, grpc_schedule_on_exec_ctx);
}
~AlarmImpl() {
grpc_core::ExecCtx exec_ctx;
@@ -68,6 +57,32 @@ class AlarmImpl : public CompletionQueueTag {
cq_ = cq->cq();
tag_ = tag;
GPR_ASSERT(grpc_cq_begin_op(cq_, this));
+ GRPC_CLOSURE_INIT(&on_alarm_,
+ [](void* arg, grpc_error* error) {
+ // queue the op on the completion queue
+ AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
+ alarm->Ref();
+ grpc_cq_end_op(
+ alarm->cq_, alarm, error,
+ [](void* arg, grpc_cq_completion* completion) {},
+ arg, &alarm->completion_);
+ },
+ this, grpc_schedule_on_exec_ctx);
+ grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline),
+ &on_alarm_);
+ }
+ void Set(gpr_timespec deadline, std::function<void(bool)> f) {
+ grpc_core::ExecCtx exec_ctx;
+ // Don't use any CQ at all. Instead just use the timer to fire the function
+ callback_ = std::move(f);
+ Ref();
+ GRPC_CLOSURE_INIT(&on_alarm_,
+ [](void* arg, grpc_error* error) {
+ AlarmImpl* alarm = static_cast<AlarmImpl*>(arg);
+ alarm->callback_(error == GRPC_ERROR_NONE);
+ alarm->Unref();
+ },
+ this, grpc_schedule_on_exec_ctx);
grpc_timer_init(&timer_, grpc_timespec_to_millis_round_up(deadline),
&on_alarm_);
}
@@ -95,6 +110,7 @@ class AlarmImpl : public CompletionQueueTag {
// completion queue where events about this alarm will be posted
grpc_completion_queue* cq_;
void* tag_;
+ std::function<void(bool)> callback_;
};
} // namespace internal
@@ -113,6 +129,15 @@ void Alarm::SetInternal(CompletionQueue* cq, gpr_timespec deadline, void* tag) {
static_cast<internal::AlarmImpl*>(alarm_)->Set(cq, deadline, tag);
}
+void Alarm::SetInternal(gpr_timespec deadline, std::function<void(bool)> f) {
+ // Note that we know that alarm_ is actually an internal::AlarmImpl
+ // but we declared it as the base pointer to avoid a forward declaration
+ // or exposing core data structures in the C++ public headers.
+ // Thus it is safe to use a static_cast to the subclass here, and the
+ // C++ style guide allows us to do so in this case
+ static_cast<internal::AlarmImpl*>(alarm_)->Set(deadline, std::move(f));
+}
+
Alarm::~Alarm() {
if (alarm_ != nullptr) {
static_cast<internal::AlarmImpl*>(alarm_)->Destroy();
diff --git a/src/cpp/ext/filters/census/server_filter.cc b/src/cpp/ext/filters/census/server_filter.cc
index c7c62eefe5..b5f3d5a13a 100644
--- a/src/cpp/ext/filters/census/server_filter.cc
+++ b/src/cpp/ext/filters/census/server_filter.cc
@@ -93,7 +93,7 @@ void CensusServerCallData::OnDoneRecvInitialMetadataCb(void* user_data,
FilterInitialMetadata(initial_metadata, &sml);
calld->path_ = grpc_slice_ref_internal(sml.path);
calld->method_ = GetMethod(&calld->path_);
- calld->qualified_method_ = StrCat("Recv.", calld->method_);
+ calld->qualified_method_ = absl::StrCat("Recv.", calld->method_);
const char* tracing_str =
GRPC_SLICE_IS_EMPTY(sml.tracing_slice)
? ""
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index b8ba7042d9..36f7eb81f9 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -657,6 +657,7 @@ void Server::PerformOpsOnCall(internal::CallOpSetInterface* ops,
size_t nops = 0;
grpc_op cops[MAX_OPS];
ops->FillOps(call->call(), cops, &nops);
+ // TODO(vjpai): Use ops->cq_tag once this case supports callbacks
auto result = grpc_call_start_batch(call->call(), cops, nops, ops, nullptr);
if (result != GRPC_CALL_OK) {
gpr_log(GPR_ERROR, "Fatal: grpc_call_start_batch returned %d", result);
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index bf0c027cda..b7254b6bb9 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -61,6 +61,9 @@ class ServerContext::CompletionOp final : public internal::CallOpSetInterface {
tag_ = tag;
}
+ /// TODO(vjpai): Allow override of cq_tag if appropriate for callback API
+ void* cq_tag() override { return this; }
+
void Unref();
private:
diff --git a/src/objective-c/BoringSSL-GRPC.podspec b/src/objective-c/BoringSSL-GRPC.podspec
index 704b35a29e..04e4d5768f 100644
--- a/src/objective-c/BoringSSL-GRPC.podspec
+++ b/src/objective-c/BoringSSL-GRPC.podspec
@@ -38,7 +38,7 @@
Pod::Spec.new do |s|
s.name = 'BoringSSL-GRPC'
- version = '0.0.1'
+ version = '0.0.2'
s.version = version
s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google\'s needs.'
# Adapted from the homepage:
@@ -81,7 +81,7 @@ Pod::Spec.new do |s|
s.ios.deployment_target = '5.0'
s.osx.deployment_target = '10.7'
- name = 'openssl'
+ name = 'openssl_grpc'
# When creating a dynamic framework, name it openssl.framework instead of BoringSSL.framework.
# This lets users write their includes like `#include <openssl/ssl.h>` as opposed to `#include
@@ -1546,6 +1546,7 @@ Pod::Spec.new do |s|
sed -i'.back' '/^#define \\([A-Za-z0-9_]*\\) \\1/d' include/openssl/ssl.h
sed -i'.back' 'N;/^#define \\([A-Za-z0-9_]*\\) *\\\\\\n *\\1/d' include/openssl/ssl.h
sed -i'.back' 's/#ifndef md5_block_data_order/#ifndef GRPC_SHADOW_md5_block_data_order/g' crypto/fipsmodule/md5/md5.c
+ find . -type f \\( -path '*.h' -or -path '*.cc' -or -path '*.c' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/;#include <openssl_grpc/;g'
END_OF_COMMAND
# Redefine symbols to avoid conflict when the same app also depends on OpenSSL. The list of
diff --git a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
index 75a669da4d..84893b92c1 100644
--- a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
+++ b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
@@ -39,7 +39,7 @@
#import "src/core/tsi/grpc_shadow_boringssl.h"
-#import <openssl/ssl.h>
+#import <openssl_grpc/ssl.h>
static void drain_cq(grpc_completion_queue *cq) {
grpc_event ev;
diff --git a/src/php/tests/unit_tests/ChannelTest.php b/src/php/tests/unit_tests/ChannelTest.php
index 49b0e350f7..583c618d32 100644
--- a/src/php/tests/unit_tests/ChannelTest.php
+++ b/src/php/tests/unit_tests/ChannelTest.php
@@ -599,10 +599,10 @@ class ChannelTest extends PHPUnit_Framework_TestCase
public function testPersistentChannelForceNewOldChannelIdle2()
{
- $this->channel1 = new Grpc\Channel('localhost:50029', [
+ $this->channel1 = new Grpc\Channel('localhost:50032', [
"grpc_target_persist_bound" => 2,
]);
- $this->channel2 = new Grpc\Channel('localhost:50029', []);
+ $this->channel2 = new Grpc\Channel('localhost:50032', []);
// try to connect on channel2
$state = $this->channel1->getConnectivityState(true);
diff --git a/src/proto/grpc/testing/package_options.proto b/src/proto/grpc/testing/package_options.proto
new file mode 100644
index 0000000000..e7ecf8c196
--- /dev/null
+++ b/src/proto/grpc/testing/package_options.proto
@@ -0,0 +1,28 @@
+// Copyright 2018 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package grpc.testing;
+
+// For sanity checking package definitions
+option ruby_package = "Grpc.Testing.Package.Options";
+
+message TestRequest { }
+
+message TestResponse { }
+
+service TestService {
+ rpc GetTest(TestRequest) returns (TestResponse) { }
+}
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
index 38fd9e78b2..63048e8da0 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
@@ -144,8 +144,14 @@ cdef class SSLChannelCredentials(ChannelCredentials):
return grpc_ssl_credentials_create(
c_pem_root_certificates, NULL, NULL, NULL)
else:
- c_pem_key_certificate_pair.private_key = self._private_key
- c_pem_key_certificate_pair.certificate_chain = self._certificate_chain
+ if self._private_key:
+ c_pem_key_certificate_pair.private_key = self._private_key
+ else:
+ c_pem_key_certificate_pair.private_key = NULL
+ if self._certificate_chain:
+ c_pem_key_certificate_pair.certificate_chain = self._certificate_chain
+ else:
+ c_pem_key_certificate_pair.certificate_chain = NULL
return grpc_ssl_credentials_create(
c_pem_root_certificates, &c_pem_key_certificate_pair, NULL, NULL)
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 0f68e823d7..3ad82e9cad 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -92,7 +92,6 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/error.cc',
'src/core/lib/iomgr/ev_epoll1_linux.cc',
'src/core/lib/iomgr/ev_epollex_linux.cc',
- 'src/core/lib/iomgr/ev_epollsig_linux.cc',
'src/core/lib/iomgr/ev_poll_posix.cc',
'src/core/lib/iomgr/ev_posix.cc',
'src/core/lib/iomgr/ev_windows.cc',
@@ -223,6 +222,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/transport/chttp2/transport/frame_settings.cc',
'src/core/ext/transport/chttp2/transport/frame_window_update.cc',
'src/core/ext/transport/chttp2/transport/hpack_encoder.cc',
+ 'src/core/ext/transport/chttp2/transport/hpack_mapping.cc',
'src/core/ext/transport/chttp2/transport/hpack_parser.cc',
'src/core/ext/transport/chttp2/transport/hpack_table.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index b6c0791469..fc641dae80 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -819,6 +819,7 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
unsigned write_flag = 0;
void* tag = (void*)&st;
+ grpc_ruby_fork_guard();
if (RTYPEDDATA_DATA(self) == NULL) {
rb_raise(grpc_rb_eCallError, "Cannot run batch on closed call");
return Qnil;
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 3f0dc530cf..6d4b2293a2 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -217,6 +217,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE* argv, VALUE self) {
MEMZERO(&args, grpc_channel_args, 1);
grpc_ruby_once_init();
+ grpc_ruby_fork_guard();
rb_thread_call_without_gvl(
wait_until_channel_polling_thread_started_no_gil,
&stop_waiting_for_thread_start,
@@ -374,6 +375,7 @@ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self,
watch_state_stack stack;
void* op_success = 0;
+ grpc_ruby_fork_guard();
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
if (wrapper->bg_wrapped == NULL) {
@@ -415,6 +417,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask,
grpc_slice* host_slice_ptr = NULL;
char* tmp_str = NULL;
+ grpc_ruby_fork_guard();
if (host != Qnil) {
host_slice =
grpc_slice_from_copied_buffer(RSTRING_PTR(host), RSTRING_LEN(host));
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index f065a857db..872aed0cfc 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -23,9 +23,13 @@
#include <math.h>
#include <ruby/vm.h>
+#include <stdbool.h>
#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <grpc/grpc.h>
+#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "rb_call.h"
#include "rb_call_credentials.h"
@@ -255,7 +259,26 @@ static void Init_grpc_time_consts() {
id_tv_nsec = rb_intern("tv_nsec");
}
-static void grpc_rb_shutdown(void) { grpc_shutdown(); }
+#if GPR_WINDOWS
+static void grpc_ruby_set_init_pid(void) {}
+static bool grpc_ruby_forked_after_init(void) { return false; }
+#else
+static pid_t grpc_init_pid;
+
+static void grpc_ruby_set_init_pid(void) {
+ GPR_ASSERT(grpc_init_pid == 0);
+ grpc_init_pid = getpid();
+}
+
+static bool grpc_ruby_forked_after_init(void) {
+ GPR_ASSERT(grpc_init_pid != 0);
+ return grpc_init_pid != getpid();
+}
+#endif
+
+static void grpc_rb_shutdown(void) {
+ if (!grpc_ruby_forked_after_init()) grpc_shutdown();
+}
/* Initialize the GRPC module structs */
@@ -276,10 +299,17 @@ VALUE sym_metadata = Qundef;
static gpr_once g_once_init = GPR_ONCE_INIT;
static void grpc_ruby_once_init_internal() {
+ grpc_ruby_set_init_pid();
grpc_init();
atexit(grpc_rb_shutdown);
}
+void grpc_ruby_fork_guard() {
+ if (grpc_ruby_forked_after_init()) {
+ rb_raise(rb_eRuntimeError, "grpc cannot be used before and after forking");
+ }
+}
+
static VALUE bg_thread_init_rb_mu = Qundef;
static int bg_thread_init_done = 0;
diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h
index 577902319e..4118435ecf 100644
--- a/src/ruby/ext/grpc/rb_grpc.h
+++ b/src/ruby/ext/grpc/rb_grpc.h
@@ -69,4 +69,6 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval);
void grpc_ruby_once_init();
+void grpc_ruby_fork_guard();
+
#endif /* GRPC_RB_H_ */
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 1375f68bbf..ed4b6264b0 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -107,7 +107,7 @@ extern grpc_completion_queue_create_for_next_type grpc_completion_queue_create_f
typedef grpc_completion_queue*(*grpc_completion_queue_create_for_pluck_type)(void* reserved);
extern grpc_completion_queue_create_for_pluck_type grpc_completion_queue_create_for_pluck_import;
#define grpc_completion_queue_create_for_pluck grpc_completion_queue_create_for_pluck_import
-typedef grpc_completion_queue*(*grpc_completion_queue_create_for_callback_type)(void* shutdown_callback, void* reserved);
+typedef grpc_completion_queue*(*grpc_completion_queue_create_for_callback_type)(grpc_experimental_completion_queue_functor* shutdown_callback, void* reserved);
extern grpc_completion_queue_create_for_callback_type grpc_completion_queue_create_for_callback_import;
#define grpc_completion_queue_create_for_callback grpc_completion_queue_create_for_callback_import
typedef grpc_completion_queue*(*grpc_completion_queue_create_type)(const grpc_completion_queue_factory* factory, const grpc_completion_queue_attributes* attributes, void* reserved);
@@ -266,7 +266,7 @@ extern grpc_resource_quota_arg_vtable_type grpc_resource_quota_arg_vtable_import
typedef char*(*grpc_channelz_get_top_channels_type)(intptr_t start_channel_id);
extern grpc_channelz_get_top_channels_type grpc_channelz_get_top_channels_import;
#define grpc_channelz_get_top_channels grpc_channelz_get_top_channels_import
-typedef char*(*grpc_channelz_get_servers_type)(intptr_t start_channel_id);
+typedef char*(*grpc_channelz_get_servers_type)(intptr_t start_server_id);
extern grpc_channelz_get_servers_type grpc_channelz_get_servers_import;
#define grpc_channelz_get_servers grpc_channelz_get_servers_import
typedef char*(*grpc_channelz_get_channel_type)(intptr_t channel_id);
@@ -410,10 +410,10 @@ extern grpc_call_set_credentials_type grpc_call_set_credentials_import;
typedef void(*grpc_server_credentials_set_auth_metadata_processor_type)(grpc_server_credentials* creds, grpc_auth_metadata_processor processor);
extern grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
#define grpc_server_credentials_set_auth_metadata_processor grpc_server_credentials_set_auth_metadata_processor_import
-typedef grpc_alts_credentials_options*(*grpc_alts_credentials_client_options_create_type)();
+typedef grpc_alts_credentials_options*(*grpc_alts_credentials_client_options_create_type)(void);
extern grpc_alts_credentials_client_options_create_type grpc_alts_credentials_client_options_create_import;
#define grpc_alts_credentials_client_options_create grpc_alts_credentials_client_options_create_import
-typedef grpc_alts_credentials_options*(*grpc_alts_credentials_server_options_create_type)();
+typedef grpc_alts_credentials_options*(*grpc_alts_credentials_server_options_create_type)(void);
extern grpc_alts_credentials_server_options_create_type grpc_alts_credentials_server_options_create_import;
#define grpc_alts_credentials_server_options_create grpc_alts_credentials_server_options_create_import
typedef void(*grpc_alts_credentials_client_options_add_target_service_account_type)(grpc_alts_credentials_options* options, const char* service_account);
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 88e6a0cfd5..2931f34409 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -243,6 +243,8 @@ static VALUE grpc_rb_server_request_call(VALUE self) {
static VALUE grpc_rb_server_start(VALUE self) {
grpc_rb_server* s = NULL;
TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
+
+ grpc_ruby_fork_guard();
if (s->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "destroyed!");
} else {
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index 5fd1805aab..efb0e4233d 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -32,7 +32,7 @@ module GRPC
# @return [Proc] { |instance| marshalled(instance) }
def marshal_proc
- proc { |o| o.class.method(marshal_method).call(o).to_s }
+ proc { |o| o.class.send(marshal_method, o).to_s }
end
# @param [:input, :output] target determines whether to produce the an
@@ -42,9 +42,9 @@ module GRPC
# @return [Proc] An unmarshal proc { |marshalled(instance)| instance }
def unmarshal_proc(target)
fail ArgumentError unless [:input, :output].include?(target)
- unmarshal_class = method(target).call
+ unmarshal_class = send(target)
unmarshal_class = unmarshal_class.type if unmarshal_class.is_a? Stream
- proc { |o| unmarshal_class.method(unmarshal_method).call(o) }
+ proc { |o| unmarshal_class.send(unmarshal_method, o) }
end
def handle_request_response(active_call, mth, inter_ctx)
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 838ac45927..3b5a0ce27f 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -136,7 +136,7 @@ module GRPC
begin
blk, args = worker_queue.pop
blk.call(*args)
- rescue StandardError => e
+ rescue StandardError, GRPC::Core::CallError => e
GRPC.logger.warn('Error in worker thread')
GRPC.logger.warn(e)
end
diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb
index 3c9eca47ec..adba6db99c 100644
--- a/src/ruby/spec/channel_spec.rb
+++ b/src/ruby/spec/channel_spec.rb
@@ -13,6 +13,7 @@
# limitations under the License.
require 'spec_helper'
+require 'English'
def load_test_certs
test_root = File.join(File.dirname(__FILE__), 'testdata')
@@ -27,6 +28,28 @@ describe GRPC::Core::Channel do
GRPC::Core::ChannelCredentials.new(load_test_certs[0])
end
+ def fork_with_propagated_error_message
+ pipe_read, pipe_write = IO.pipe
+ pid = fork do
+ pipe_read.close
+ begin
+ yield
+ rescue => exc
+ pipe_write.syswrite(exc.message)
+ end
+ pipe_write.close
+ end
+ pipe_write.close
+
+ exc_message = pipe_read.read
+ Process.wait(pid)
+
+ unless $CHILD_STATUS.success?
+ raise "forked process failed with #{$CHILD_STATUS}"
+ end
+ raise exc_message unless exc_message.empty?
+ end
+
shared_examples '#new' do
it 'take a host name without channel args' do
blk = proc do
@@ -79,6 +102,14 @@ describe GRPC::Core::Channel do
blk = construct_with_args(args)
expect(&blk).to_not raise_error
end
+
+ it 'raises if grpc was initialized in another process' do
+ blk = construct_with_args({})
+ expect(&blk).not_to raise_error
+ expect do
+ fork_with_propagated_error_message(&blk)
+ end.to raise_error(RuntimeError, 'grpc cannot be used before and after forking')
+ end
end
describe '#new for secure channels' do
@@ -121,6 +152,19 @@ describe GRPC::Core::Channel do
end
expect(&blk).to raise_error(RuntimeError)
end
+
+ it 'raises if grpc was initialized in another process' do
+ ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure)
+
+ deadline = Time.now + 5
+
+ blk = proc do
+ fork_with_propagated_error_message do
+ ch.create_call(nil, nil, 'dummy_method', nil, deadline)
+ end
+ end
+ expect(&blk).to raise_error(RuntimeError, 'grpc cannot be used before and after forking')
+ end
end
describe '#destroy' do
diff --git a/src/ruby/spec/client_auth_spec.rb b/src/ruby/spec/client_auth_spec.rb
index c563ed3227..5d2e6d24ec 100644
--- a/src/ruby/spec/client_auth_spec.rb
+++ b/src/ruby/spec/client_auth_spec.rb
@@ -30,7 +30,7 @@ end
def create_server_creds
test_root = File.join(File.dirname(__FILE__), 'testdata')
- p "test root: #{test_root}"
+ GRPC.logger.info("test root: #{test_root}")
files = ['ca.pem', 'server1.key', 'server1.pem']
creds = files.map { |f| File.open(File.join(test_root, f)).read }
GRPC::Core::ServerCredentials.new(
@@ -59,7 +59,7 @@ class SslTestService
def a_client_streaming_rpc(call)
check_peer_cert(call)
- call.each_remote_read.each { |r| p r }
+ call.each_remote_read.each { |r| GRPC.logger.info(r) }
EchoMsg.new
end
@@ -70,7 +70,7 @@ class SslTestService
def a_bidi_rpc(requests, call)
check_peer_cert(call)
- requests.each { |r| p r }
+ requests.each { |r| GRPC.logger.info(r) }
[EchoMsg.new, EchoMsg.new]
end
end
@@ -116,11 +116,11 @@ describe 'client-server auth' do
it 'client-server auth with server streaming RPCs' do
responses = @stub.a_server_streaming_rpc(EchoMsg.new)
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
it 'client-server auth with bidi RPCs' do
responses = @stub.a_bidi_rpc([EchoMsg.new, EchoMsg.new])
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index fc50362ca5..200139d849 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -293,7 +293,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
describe 'without a call operation' do
def get_response(stub, credentials: nil)
- puts credentials.inspect
+ GRPC.logger.info(credentials.inspect)
stub.request_response(@method, @sent_msg, noop, noop,
metadata: @metadata,
credentials: credentials)
@@ -342,13 +342,15 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
it 'sends metadata to the server ok when running start_call first' do
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
- @op, @server_initial_md, @server_trailing_md) { |r| p r }
+ @op, @server_initial_md, @server_trailing_md
+ ) { |r| GRPC.logger.info(r) }
end
it 'does not crash when used after the call has been finished' do
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
- @op, @server_initial_md, @server_trailing_md) { |r| p r }
+ @op, @server_initial_md, @server_trailing_md
+ ) { |r| GRPC.logger.info(r) }
end
end
end
@@ -435,13 +437,15 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
it 'sends metadata to the server ok when running start_call first' do
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
- @op, @server_initial_md, @server_trailing_md) { |r| p r }
+ @op, @server_initial_md, @server_trailing_md
+ ) { |r| GRPC.logger.info(r) }
end
it 'does not crash when used after the call has been finished' do
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
- @op, @server_initial_md, @server_trailing_md) { |r| p r }
+ @op, @server_initial_md, @server_trailing_md
+ ) { |r| GRPC.logger.info(r) }
end
end
end
@@ -578,7 +582,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
@@ -586,7 +590,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
@@ -895,7 +899,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(true)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
@@ -903,7 +907,7 @@ describe 'ClientStub' do # rubocop:disable Metrics/BlockLength
run_op_view_metadata_test(false)
check_op_view_of_finished_client_call(
@op, @server_initial_md, @server_trailing_md) do |responses|
- responses.each { |r| p r }
+ responses.each { |r| GRPC.logger.info(r) }
end
end
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index e072d0c45f..44a6134086 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -125,7 +125,7 @@ class CheckCallAfterFinishedService
fail 'shouldnt reuse service' unless @server_side_call.nil?
@server_side_call = call
# iterate through requests so call can complete
- call.each_remote_read.each { |r| p r }
+ call.each_remote_read.each { |r| GRPC.logger.info(r) }
EchoMsg.new
end
@@ -138,7 +138,7 @@ class CheckCallAfterFinishedService
def a_bidi_rpc(requests, call)
fail 'shouldnt reuse service' unless @server_side_call.nil?
@server_side_call = call
- requests.each { |r| p r }
+ requests.each { |r| GRPC.logger.info(r) }
[EchoMsg.new, EchoMsg.new]
end
end
@@ -560,7 +560,7 @@ describe GRPC::RpcServer do
'connect_k1' => 'connect_v1'
}
wanted_md.each do |key, value|
- puts "key: #{key}"
+ GRPC.logger.info("key: #{key}")
expect(op.metadata[key]).to eq(value)
end
@srv.stop
diff --git a/src/ruby/spec/pb/codegen/package_option_spec.rb b/src/ruby/spec/pb/codegen/package_option_spec.rb
new file mode 100644
index 0000000000..46d23cd651
--- /dev/null
+++ b/src/ruby/spec/pb/codegen/package_option_spec.rb
@@ -0,0 +1,53 @@
+# Copyright 2018 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'spec_helper'
+require 'open3'
+require 'tmpdir'
+
+describe 'Code Generation Options' do
+ it 'should generate and respect package options' do
+ fail 'CONFIG env variable unexpectedly unset' unless ENV['CONFIG']
+ bins_sub_dir = ENV['CONFIG']
+
+ src_dir = File.join(File.dirname(__FILE__), '..', '..', '..', '..')
+ pb_dir = File.join(src_dir, 'proto')
+ bins_dir = File.join(src_dir, '..', 'bins', bins_sub_dir)
+
+ plugin = File.join(bins_dir, 'grpc_ruby_plugin')
+ protoc = File.join(bins_dir, 'protobuf', 'protoc')
+
+ # Generate the service from the proto
+ Dir.mktmpdir(nil, File.dirname(__FILE__)) do |tmp_dir|
+ gen_file = system(protoc,
+ '-I.',
+ 'grpc/testing/package_options.proto',
+ "--grpc_out=#{tmp_dir}", # generate the service
+ "--ruby_out=#{tmp_dir}", # generate the definitions
+ "--plugin=protoc-gen-grpc=#{plugin}",
+ chdir: pb_dir,
+ out: File::NULL)
+
+ expect(gen_file).to be_truthy
+ begin
+ $LOAD_PATH.push(tmp_dir)
+ expect { Grpc::Testing::Package::Options::TestService::Service }.to raise_error(NameError)
+ expect(require('grpc/testing/package_options_services_pb')).to be_truthy
+ expect { Grpc::Testing::Package::Options::TestService::Service }.to_not raise_error
+ ensure
+ $LOAD_PATH.delete(tmp_dir)
+ end
+ end
+ end
+end
diff --git a/src/ruby/spec/support/services.rb b/src/ruby/spec/support/services.rb
index 27239cd66c..6e693f1cde 100644
--- a/src/ruby/spec/support/services.rb
+++ b/src/ruby/spec/support/services.rb
@@ -50,7 +50,9 @@ class EchoService
def a_client_streaming_rpc(call)
# iterate through requests so call can complete
call.output_metadata.update(@trailing_metadata)
- call.each_remote_read.each { |r| p r }
+ call.each_remote_read.each do |r|
+ GRPC.logger.info(r)
+ end
EchoMsg.new
end
@@ -61,7 +63,9 @@ class EchoService
def a_bidi_rpc(requests, call)
call.output_metadata.update(@trailing_metadata)
- requests.each { |r| p r }
+ requests.each do |r|
+ GRPC.logger.info(r)
+ end
[EchoMsg.new, EchoMsg.new]
end
end
@@ -71,35 +75,37 @@ EchoStub = EchoService.rpc_stub_class
# For testing server interceptors
class TestServerInterceptor < GRPC::ServerInterceptor
def request_response(request:, call:, method:)
- p "Received request/response call at method #{method}" \
- " with request #{request} for call #{call}"
+ GRPC.logger.info("Received request/response call at method #{method}" \
+ " with request #{request} for call #{call}")
call.output_metadata[:interc] = 'from_request_response'
- p "[GRPC::Ok] (#{method.owner.name}.#{method.name})"
+ GRPC.logger.info("[GRPC::Ok] (#{method.owner.name}.#{method.name})")
yield
end
def client_streamer(call:, method:)
call.output_metadata[:interc] = 'from_client_streamer'
call.each_remote_read.each do |r|
- p "In interceptor: #{r}"
+ GRPC.logger.info("In interceptor: #{r}")
end
- p "Received client streamer call at method #{method} for call #{call}"
+ GRPC.logger.info(
+ "Received client streamer call at method #{method} for call #{call}"
+ )
yield
end
def server_streamer(request:, call:, method:)
- p "Received server streamer call at method #{method} with request" \
- " #{request} for call #{call}"
+ GRPC.logger.info("Received server streamer call at method #{method} with request" \
+ " #{request} for call #{call}")
call.output_metadata[:interc] = 'from_server_streamer'
yield
end
def bidi_streamer(requests:, call:, method:)
requests.each do |r|
- p "Bidi request: #{r}"
+ GRPC.logger.info("Bidi request: #{r}")
end
- p "Received bidi streamer call at method #{method} with requests" \
- " #{requests} for call #{call}"
+ GRPC.logger.info("Received bidi streamer call at method #{method} with requests" \
+ " #{requests} for call #{call}")
call.output_metadata[:interc] = 'from_bidi_streamer'
yield
end
@@ -108,38 +114,38 @@ end
# For testing client interceptors
class TestClientInterceptor < GRPC::ClientInterceptor
def request_response(request:, call:, method:, metadata: {})
- p "Intercepted request/response call at method #{method}" \
+ GRPC.logger.info("Intercepted request/response call at method #{method}" \
" with request #{request} for call #{call}" \
- " and metadata: #{metadata}"
+ " and metadata: #{metadata}")
metadata['foo'] = 'bar_from_request_response'
yield
end
def client_streamer(requests:, call:, method:, metadata: {})
- p "Received client streamer call at method #{method}" \
+ GRPC.logger.info("Received client streamer call at method #{method}" \
" with requests #{requests} for call #{call}" \
- " and metadata: #{metadata}"
+ " and metadata: #{metadata}")
requests.each do |r|
- p "In client interceptor: #{r}"
+ GRPC.logger.info("In client interceptor: #{r}")
end
metadata['foo'] = 'bar_from_client_streamer'
yield
end
def server_streamer(request:, call:, method:, metadata: {})
- p "Received server streamer call at method #{method}" \
+ GRPC.logger.info("Received server streamer call at method #{method}" \
" with request #{request} for call #{call}" \
- " and metadata: #{metadata}"
+ " and metadata: #{metadata}")
metadata['foo'] = 'bar_from_server_streamer'
yield
end
def bidi_streamer(requests:, call:, method:, metadata: {})
- p "Received bidi streamer call at method #{method}" \
+ GRPC.logger.info("Received bidi streamer call at method #{method}" \
"with requests #{requests} for call #{call}" \
- " and metadata: #{metadata}"
+ " and metadata: #{metadata}")
requests.each do |r|
- p "In client interceptor: #{r}"
+ GRPC.logger.info("In client interceptor: #{r}")
end
metadata['foo'] = 'bar_from_bidi_streamer'
yield
diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template
index f912154301..98b6344a4b 100644
--- a/templates/gRPC-Core.podspec.template
+++ b/templates/gRPC-Core.podspec.template
@@ -174,7 +174,7 @@
ss.header_mappings_dir = '.'
ss.libraries = 'z'
ss.dependency "#{s.name}/Interface", version
- ss.dependency 'BoringSSL-GRPC', '0.0.1'
+ ss.dependency 'BoringSSL-GRPC', '0.0.2'
ss.dependency 'nanopb', '~> 0.3'
ss.compiler_flags = '-DGRPC_SHADOW_BORINGSSL_SYMBOLS'
@@ -223,5 +223,6 @@
s.prepare_command = <<-END_OF_COMMAND
find src/core/ -type f ! -path '*.grpc_back' -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include "(pb(_.*)?\\.h)";#include <nanopb/\\1>;g'
find src/core/ -type f -path '*.grpc_back' -print0 | xargs -0 rm
+ find src/core/ -type f \\( -path '*.h' -or -path '*.cc' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/;#include <openssl_grpc/;g'
END_OF_COMMAND
end
diff --git a/templates/src/objective-c/BoringSSL-GRPC.podspec.template b/templates/src/objective-c/BoringSSL-GRPC.podspec.template
index 986216fdbf..2b3bb8d97a 100644
--- a/templates/src/objective-c/BoringSSL-GRPC.podspec.template
+++ b/templates/src/objective-c/BoringSSL-GRPC.podspec.template
@@ -43,7 +43,7 @@
Pod::Spec.new do |s|
s.name = 'BoringSSL-GRPC'
- version = '0.0.1'
+ version = '0.0.2'
s.version = version
s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google\'s needs.'
# Adapted from the homepage:
@@ -86,7 +86,7 @@
s.ios.deployment_target = '5.0'
s.osx.deployment_target = '10.7'
- name = 'openssl'
+ name = 'openssl_grpc'
# When creating a dynamic framework, name it openssl.framework instead of BoringSSL.framework.
# This lets users write their includes like `#include <openssl/ssl.h>` as opposed to `#include
@@ -1551,6 +1551,7 @@
sed -i'.back' '/^#define \\([A-Za-z0-9_]*\\) \\1/d' include/openssl/ssl.h
sed -i'.back' 'N;/^#define \\([A-Za-z0-9_]*\\) *\\\\\\n *\\1/d' include/openssl/ssl.h
sed -i'.back' 's/#ifndef md5_block_data_order/#ifndef GRPC_SHADOW_md5_block_data_order/g' crypto/fipsmodule/md5/md5.c
+ find . -type f \\( -path '*.h' -or -path '*.cc' -or -path '*.c' \\) -print0 | xargs -0 -L1 sed -E -i'.grpc_back' 's;#include <openssl/;#include <openssl_grpc/;g'
END_OF_COMMAND
# Redefine symbols to avoid conflict when the same app also depends on OpenSSL. The list of
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index db2886d8e3..6d9ffcfb91 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -13,277 +13,347 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-POLLERS = ['epollex', 'epollsig', 'epoll1', 'poll', 'poll-cv']
-
-load("//bazel:grpc_build_system.bzl", "grpc_sh_test", "grpc_cc_binary", "grpc_cc_library")
-
"""Generates the appropriate build.json data for all the end2end tests."""
+load("//bazel:grpc_build_system.bzl", "grpc_cc_binary", "grpc_cc_library")
-def fixture_options(fullstack=True, includes_proxy=False, dns_resolver=True,
- name_resolution=True, secure=True, tracing=False,
- platforms=['windows', 'linux', 'mac', 'posix'],
- is_inproc=False, is_http2=True, supports_proxy_auth=False,
- supports_write_buffering=True, client_channel=True):
- return struct(
- fullstack=fullstack,
- includes_proxy=includes_proxy,
- dns_resolver=dns_resolver,
- name_resolution=name_resolution,
- secure=secure,
- tracing=tracing,
- is_inproc=is_inproc,
- is_http2=is_http2,
- supports_proxy_auth=supports_proxy_auth,
- supports_write_buffering=supports_write_buffering,
- client_channel=client_channel,
- #platforms=platforms,
- )
+POLLERS = ["epollex", "epoll1", "poll", "poll-cv"]
+def _fixture_options(
+ fullstack = True,
+ includes_proxy = False,
+ dns_resolver = True,
+ name_resolution = True,
+ secure = True,
+ tracing = False,
+ _platforms = ["windows", "linux", "mac", "posix"],
+ is_inproc = False,
+ is_http2 = True,
+ supports_proxy_auth = False,
+ supports_write_buffering = True,
+ client_channel = True):
+ return struct(
+ fullstack = fullstack,
+ includes_proxy = includes_proxy,
+ dns_resolver = dns_resolver,
+ name_resolution = name_resolution,
+ secure = secure,
+ tracing = tracing,
+ is_inproc = is_inproc,
+ is_http2 = is_http2,
+ supports_proxy_auth = supports_proxy_auth,
+ supports_write_buffering = supports_write_buffering,
+ client_channel = client_channel,
+ #_platforms=_platforms,
+ )
# maps fixture name to whether it requires the security library
END2END_FIXTURES = {
- 'h2_compress': fixture_options(),
- 'h2_census': fixture_options(),
+ "h2_compress": _fixture_options(),
+ "h2_census": _fixture_options(),
# TODO(juanlishen): This is disabled for now, but should be considered to re-enable once we have
# decided how the load reporting service should be enabled.
- #'h2_load_reporting': fixture_options(),
- 'h2_fakesec': fixture_options(),
- 'h2_fd': fixture_options(dns_resolver=False, fullstack=False,
- client_channel=False,
- platforms=['linux', 'mac', 'posix']),
- 'h2_full': fixture_options(),
- 'h2_full+pipe': fixture_options(platforms=['linux']),
- 'h2_full+trace': fixture_options(tracing=True),
- 'h2_full+workarounds': fixture_options(),
- 'h2_http_proxy': fixture_options(supports_proxy_auth=True),
- 'h2_oauth2': fixture_options(),
- 'h2_proxy': fixture_options(includes_proxy=True),
- 'h2_sockpair_1byte': fixture_options(fullstack=False, dns_resolver=False,
- client_channel=False),
- 'h2_sockpair': fixture_options(fullstack=False, dns_resolver=False,
- client_channel=False),
- 'h2_sockpair+trace': fixture_options(fullstack=False, dns_resolver=False,
- tracing=True, client_channel=False),
- 'h2_ssl': fixture_options(secure=True),
- 'h2_local': fixture_options(secure=True, dns_resolver=False, platforms=['linux', 'mac', 'posix']),
- 'h2_ssl_proxy': fixture_options(includes_proxy=True, secure=True),
- 'h2_uds': fixture_options(dns_resolver=False,
- platforms=['linux', 'mac', 'posix']),
- 'inproc': fixture_options(fullstack=False, dns_resolver=False,
- name_resolution=False, is_inproc=True,
- is_http2=False, supports_write_buffering=False,
- client_channel=False),
+ #'h2_load_reporting': _fixture_options(),
+ "h2_fakesec": _fixture_options(),
+ "h2_fd": _fixture_options(
+ dns_resolver = False,
+ fullstack = False,
+ client_channel = False,
+ _platforms = ["linux", "mac", "posix"],
+ ),
+ "h2_full": _fixture_options(),
+ "h2_full+pipe": _fixture_options(_platforms = ["linux"]),
+ "h2_full+trace": _fixture_options(tracing = True),
+ "h2_full+workarounds": _fixture_options(),
+ "h2_http_proxy": _fixture_options(supports_proxy_auth = True),
+ "h2_oauth2": _fixture_options(),
+ "h2_proxy": _fixture_options(includes_proxy = True),
+ "h2_sockpair_1byte": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ client_channel = False,
+ ),
+ "h2_sockpair": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ client_channel = False,
+ ),
+ "h2_sockpair+trace": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ tracing = True,
+ client_channel = False,
+ ),
+ "h2_ssl": _fixture_options(secure = True),
+ "h2_local": _fixture_options(secure = True, dns_resolver = False, _platforms = ["linux", "mac", "posix"]),
+ "h2_ssl_proxy": _fixture_options(includes_proxy = True, secure = True),
+ "h2_uds": _fixture_options(
+ dns_resolver = False,
+ _platforms = ["linux", "mac", "posix"],
+ ),
+ "inproc": _fixture_options(
+ fullstack = False,
+ dns_resolver = False,
+ name_resolution = False,
+ is_inproc = True,
+ is_http2 = False,
+ supports_write_buffering = False,
+ client_channel = False,
+ ),
}
-
-def test_options(needs_fullstack=False, needs_dns=False, needs_names=False,
- proxyable=True, secure=False, traceable=False,
- exclude_inproc=False, needs_http2=False,
- needs_proxy_auth=False, needs_write_buffering=False,
- needs_client_channel=False):
- return struct(
- needs_fullstack=needs_fullstack,
- needs_dns=needs_dns,
- needs_names=needs_names,
- proxyable=proxyable,
- secure=secure,
- traceable=traceable,
- exclude_inproc=exclude_inproc,
- needs_http2=needs_http2,
- needs_proxy_auth=needs_proxy_auth,
- needs_write_buffering=needs_write_buffering,
- needs_client_channel=needs_client_channel,
- )
-
+def _test_options(
+ needs_fullstack = False,
+ needs_dns = False,
+ needs_names = False,
+ proxyable = True,
+ secure = False,
+ traceable = False,
+ exclude_inproc = False,
+ needs_http2 = False,
+ needs_proxy_auth = False,
+ needs_write_buffering = False,
+ needs_client_channel = False):
+ return struct(
+ needs_fullstack = needs_fullstack,
+ needs_dns = needs_dns,
+ needs_names = needs_names,
+ proxyable = proxyable,
+ secure = secure,
+ traceable = traceable,
+ exclude_inproc = exclude_inproc,
+ needs_http2 = needs_http2,
+ needs_proxy_auth = needs_proxy_auth,
+ needs_write_buffering = needs_write_buffering,
+ needs_client_channel = needs_client_channel,
+ )
# maps test names to options
END2END_TESTS = {
- 'bad_hostname': test_options(needs_names=True),
- 'bad_ping': test_options(needs_fullstack=True,proxyable=False),
- 'binary_metadata': test_options(),
- 'resource_quota_server': test_options(proxyable=False),
- 'call_creds': test_options(secure=True),
- 'call_host_override': test_options(needs_fullstack=True, needs_dns=True,
- needs_names=True),
- 'cancel_after_accept': test_options(),
- 'cancel_after_client_done': test_options(),
- 'cancel_after_invoke': test_options(),
- 'cancel_after_round_trip': test_options(),
- 'cancel_before_invoke': test_options(),
- 'cancel_in_a_vacuum': test_options(),
- 'cancel_with_status': test_options(),
- 'compressed_payload': test_options(proxyable=False, exclude_inproc=True),
- 'connectivity': test_options(needs_fullstack=True, needs_names=True,
- proxyable=False),
- 'channelz': test_options(),
- 'default_host': test_options(needs_fullstack=True, needs_dns=True,
- needs_names=True),
- 'disappearing_server': test_options(needs_fullstack=True,needs_names=True),
- 'empty_batch': test_options(),
- 'filter_causes_close': test_options(),
- 'filter_call_init_fails': test_options(),
- 'graceful_server_shutdown': test_options(exclude_inproc=True),
- 'hpack_size': test_options(proxyable=False, traceable=False,
- exclude_inproc=True),
- 'high_initial_seqno': test_options(),
- 'idempotent_request': test_options(),
- 'invoke_large_request': test_options(),
- 'keepalive_timeout': test_options(proxyable=False, needs_http2=True),
- 'large_metadata': test_options(),
- 'max_concurrent_streams': test_options(proxyable=False,
- exclude_inproc=True),
- 'max_connection_age': test_options(exclude_inproc=True),
- 'max_connection_idle': test_options(needs_fullstack=True, proxyable=False),
- 'max_message_length': test_options(),
- 'negative_deadline': test_options(),
- 'network_status_change': test_options(),
- 'no_error_on_hotpath': test_options(proxyable=False),
- 'no_logging': test_options(traceable=False),
- 'no_op': test_options(),
- 'payload': test_options(),
+ "bad_hostname": _test_options(needs_names = True),
+ "bad_ping": _test_options(needs_fullstack = True, proxyable = False),
+ "binary_metadata": _test_options(),
+ "resource_quota_server": _test_options(proxyable = False),
+ "call_creds": _test_options(secure = True),
+ "call_host_override": _test_options(
+ needs_fullstack = True,
+ needs_dns = True,
+ needs_names = True,
+ ),
+ "cancel_after_accept": _test_options(),
+ "cancel_after_client_done": _test_options(),
+ "cancel_after_invoke": _test_options(),
+ "cancel_after_round_trip": _test_options(),
+ "cancel_before_invoke": _test_options(),
+ "cancel_in_a_vacuum": _test_options(),
+ "cancel_with_status": _test_options(),
+ "compressed_payload": _test_options(proxyable = False, exclude_inproc = True),
+ "connectivity": _test_options(
+ needs_fullstack = True,
+ needs_names = True,
+ proxyable = False,
+ ),
+ "channelz": _test_options(),
+ "default_host": _test_options(
+ needs_fullstack = True,
+ needs_dns = True,
+ needs_names = True,
+ ),
+ "disappearing_server": _test_options(needs_fullstack = True, needs_names = True),
+ "empty_batch": _test_options(),
+ "filter_causes_close": _test_options(),
+ "filter_call_init_fails": _test_options(),
+ "graceful_server_shutdown": _test_options(exclude_inproc = True),
+ "hpack_size": _test_options(
+ proxyable = False,
+ traceable = False,
+ exclude_inproc = True,
+ ),
+ "high_initial_seqno": _test_options(),
+ "idempotent_request": _test_options(),
+ "invoke_large_request": _test_options(),
+ "keepalive_timeout": _test_options(proxyable = False, needs_http2 = True),
+ "large_metadata": _test_options(),
+ "max_concurrent_streams": _test_options(
+ proxyable = False,
+ exclude_inproc = True,
+ ),
+ "max_connection_age": _test_options(exclude_inproc = True),
+ "max_connection_idle": _test_options(needs_fullstack = True, proxyable = False),
+ "max_message_length": _test_options(),
+ "negative_deadline": _test_options(),
+ "network_status_change": _test_options(),
+ "no_error_on_hotpath": _test_options(proxyable = False),
+ "no_logging": _test_options(traceable = False),
+ "no_op": _test_options(),
+ "payload": _test_options(),
# TODO(juanlishen): This is disabled for now because it depends on some generated functions in
# end2end_tests.cc, which are not generated because they would depend on OpenCensus while
# OpenCensus can only be built via Bazel so far.
- # 'load_reporting_hook': test_options(),
- 'ping_pong_streaming': test_options(),
- 'ping': test_options(needs_fullstack=True, proxyable=False),
- 'proxy_auth': test_options(needs_proxy_auth=True),
- 'registered_call': test_options(),
- 'request_with_flags': test_options(proxyable=False),
- 'request_with_payload': test_options(),
+ # 'load_reporting_hook': _test_options(),
+ "ping_pong_streaming": _test_options(),
+ "ping": _test_options(needs_fullstack = True, proxyable = False),
+ "proxy_auth": _test_options(needs_proxy_auth = True),
+ "registered_call": _test_options(),
+ "request_with_flags": _test_options(proxyable = False),
+ "request_with_payload": _test_options(),
# TODO(roth): Remove proxyable=False for all retry tests once we
# have a way for the proxy to propagate the fact that trailing
# metadata is available when initial metadata is returned.
# See https://github.com/grpc/grpc/issues/14467 for context.
- 'retry': test_options(needs_client_channel=True, proxyable=False),
- 'retry_cancellation': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_disabled': test_options(needs_client_channel=True, proxyable=False),
- 'retry_exceeds_buffer_size_in_initial_batch': test_options(
- needs_client_channel=True, proxyable=False),
- 'retry_exceeds_buffer_size_in_subsequent_batch': test_options(
- needs_client_channel=True, proxyable=False),
- 'retry_non_retriable_status': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_non_retriable_status_before_recv_trailing_metadata_started':
- test_options(needs_client_channel=True, proxyable=False),
- 'retry_recv_initial_metadata': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_recv_message': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_server_pushback_delay': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_server_pushback_disabled': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_streaming': test_options(needs_client_channel=True, proxyable=False),
- 'retry_streaming_after_commit': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_streaming_succeeds_before_replay_finished': test_options(
- needs_client_channel=True, proxyable=False),
- 'retry_throttled': test_options(needs_client_channel=True,
- proxyable=False),
- 'retry_too_many_attempts': test_options(needs_client_channel=True,
- proxyable=False),
- 'server_finishes_request': test_options(),
- 'shutdown_finishes_calls': test_options(),
- 'shutdown_finishes_tags': test_options(),
- 'simple_cacheable_request': test_options(),
- 'simple_delayed_request': test_options(needs_fullstack=True),
- 'simple_metadata': test_options(),
- 'simple_request': test_options(),
- 'streaming_error_response': test_options(),
- 'stream_compression_compressed_payload': test_options(proxyable=False,
- exclude_inproc=True),
- 'stream_compression_payload': test_options(exclude_inproc=True),
- 'stream_compression_ping_pong_streaming': test_options(exclude_inproc=True),
- 'trailing_metadata': test_options(),
- 'authority_not_supported': test_options(),
- 'filter_latency': test_options(),
- 'filter_status_code': test_options(),
- 'workaround_cronet_compression': test_options(),
- 'write_buffering': test_options(needs_write_buffering=True),
- 'write_buffering_at_end': test_options(needs_write_buffering=True),
+ "retry": _test_options(needs_client_channel = True, proxyable = False),
+ "retry_cancellation": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_disabled": _test_options(needs_client_channel = True, proxyable = False),
+ "retry_exceeds_buffer_size_in_initial_batch": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_exceeds_buffer_size_in_subsequent_batch": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_non_retriable_status": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_non_retriable_status_before_recv_trailing_metadata_started": _test_options(needs_client_channel = True, proxyable = False),
+ "retry_recv_initial_metadata": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_recv_message": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_server_pushback_delay": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_server_pushback_disabled": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_streaming": _test_options(needs_client_channel = True, proxyable = False),
+ "retry_streaming_after_commit": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_streaming_succeeds_before_replay_finished": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_throttled": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "retry_too_many_attempts": _test_options(
+ needs_client_channel = True,
+ proxyable = False,
+ ),
+ "server_finishes_request": _test_options(),
+ "shutdown_finishes_calls": _test_options(),
+ "shutdown_finishes_tags": _test_options(),
+ "simple_cacheable_request": _test_options(),
+ "simple_delayed_request": _test_options(needs_fullstack = True),
+ "simple_metadata": _test_options(),
+ "simple_request": _test_options(),
+ "streaming_error_response": _test_options(),
+ "stream_compression_compressed_payload": _test_options(
+ proxyable = False,
+ exclude_inproc = True,
+ ),
+ "stream_compression_payload": _test_options(exclude_inproc = True),
+ "stream_compression_ping_pong_streaming": _test_options(exclude_inproc = True),
+ "trailing_metadata": _test_options(),
+ "authority_not_supported": _test_options(),
+ "filter_latency": _test_options(),
+ "filter_status_code": _test_options(),
+ "workaround_cronet_compression": _test_options(),
+ "write_buffering": _test_options(needs_write_buffering = True),
+ "write_buffering_at_end": _test_options(needs_write_buffering = True),
}
-
-def compatible(fopt, topt):
- if topt.needs_fullstack:
- if not fopt.fullstack:
- return False
- if topt.needs_dns:
- if not fopt.dns_resolver:
- return False
- if topt.needs_names:
- if not fopt.name_resolution:
- return False
- if not topt.proxyable:
- if fopt.includes_proxy:
- return False
- if not topt.traceable:
- if fopt.tracing:
- return False
- if topt.exclude_inproc:
- if fopt.is_inproc:
- return False
- if topt.needs_http2:
- if not fopt.is_http2:
- return False
- if topt.needs_proxy_auth:
- if not fopt.supports_proxy_auth:
- return False
- if topt.needs_write_buffering:
- if not fopt.supports_write_buffering:
- return False
- if topt.needs_client_channel:
- if not fopt.client_channel:
- return False
- return True
-
+def _compatible(fopt, topt):
+ if topt.needs_fullstack:
+ if not fopt.fullstack:
+ return False
+ if topt.needs_dns:
+ if not fopt.dns_resolver:
+ return False
+ if topt.needs_names:
+ if not fopt.name_resolution:
+ return False
+ if not topt.proxyable:
+ if fopt.includes_proxy:
+ return False
+ if not topt.traceable:
+ if fopt.tracing:
+ return False
+ if topt.exclude_inproc:
+ if fopt.is_inproc:
+ return False
+ if topt.needs_http2:
+ if not fopt.is_http2:
+ return False
+ if topt.needs_proxy_auth:
+ if not fopt.supports_proxy_auth:
+ return False
+ if topt.needs_write_buffering:
+ if not fopt.supports_write_buffering:
+ return False
+ if topt.needs_client_channel:
+ if not fopt.client_channel:
+ return False
+ return True
def grpc_end2end_tests():
- grpc_cc_library(
- name = 'end2end_tests',
- srcs = ['end2end_tests.cc', 'end2end_test_utils.cc'] + [
- 'tests/%s.cc' % t
- for t in sorted(END2END_TESTS.keys())],
- hdrs = [
- 'tests/cancel_test_helpers.h',
- 'end2end_tests.h'
- ],
- language = "C++",
- deps = [
- ':cq_verifier',
- ':ssl_test_data',
- ':http_proxy',
- ':proxy',
- ]
- )
-
- for f, fopt in END2END_FIXTURES.items():
- grpc_cc_binary(
- name = '%s_test' % f,
- srcs = ['fixtures/%s.cc' % f],
- language = "C++",
- deps = [
- ':end2end_tests',
- '//test/core/util:grpc_test_util',
- '//:grpc',
- '//test/core/util:gpr_test_util',
- '//:gpr',
- ],
+ grpc_cc_library(
+ name = "end2end_tests",
+ srcs = ["end2end_tests.cc", "end2end_test_utils.cc"] + [
+ "tests/%s.cc" % t
+ for t in sorted(END2END_TESTS.keys())
+ ],
+ hdrs = [
+ "tests/cancel_test_helpers.h",
+ "end2end_tests.h",
+ ],
+ language = "C++",
+ deps = [
+ ":cq_verifier",
+ ":ssl_test_data",
+ ":http_proxy",
+ ":proxy",
+ ],
)
- for t, topt in END2END_TESTS.items():
- #print(compatible(fopt, topt), f, t, fopt, topt)
- if not compatible(fopt, topt): continue
- for poller in POLLERS:
- native.sh_test(
- name = '%s_test@%s@poller=%s' % (f, t, poller),
- data = [':%s_test' % f],
- srcs = ['end2end_test.sh'],
- args = [
- '$(location %s_test)' % f,
- t,
- poller,
- ],
+
+ for f, fopt in END2END_FIXTURES.items():
+ grpc_cc_binary(
+ name = "%s_test" % f,
+ srcs = ["fixtures/%s.cc" % f],
+ language = "C++",
+ deps = [
+ ":end2end_tests",
+ "//test/core/util:grpc_test_util",
+ "//:grpc",
+ "//test/core/util:gpr_test_util",
+ "//:gpr",
+ ],
)
+ for t, topt in END2END_TESTS.items():
+ #print(_compatible(fopt, topt), f, t, fopt, topt)
+ if not _compatible(fopt, topt):
+ continue
+ for poller in POLLERS:
+ native.sh_test(
+ name = "%s_test@%s@poller=%s" % (f, t, poller),
+ data = [":%s_test" % f],
+ srcs = ["end2end_test.sh"],
+ args = [
+ "$(location %s_test)" % f,
+ t,
+ poller,
+ ],
+ )
diff --git a/test/core/end2end/inproc_callback_test.cc b/test/core/end2end/inproc_callback_test.cc
index 0d6c7c75a8..310030046a 100644
--- a/test/core/end2end/inproc_callback_test.cc
+++ b/test/core/end2end/inproc_callback_test.cc
@@ -37,13 +37,16 @@ typedef struct inproc_fixture_data {
namespace {
template <typename F>
-class CQDeletingCallback : public grpc_core::CQCallbackInterface {
+class CQDeletingCallback : public grpc_experimental_completion_queue_functor {
public:
- explicit CQDeletingCallback(F f) : func_(f) {}
- ~CQDeletingCallback() override {}
- void Run(bool ok) override {
- func_(ok);
- grpc_core::Delete(this);
+ explicit CQDeletingCallback(F f) : func_(f) {
+ functor_run = &CQDeletingCallback::Run;
+ }
+ ~CQDeletingCallback() {}
+ static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
+ auto* callback = static_cast<CQDeletingCallback*>(cb);
+ callback->func_(static_cast<bool>(ok));
+ grpc_core::Delete(callback);
}
private:
@@ -51,18 +54,24 @@ class CQDeletingCallback : public grpc_core::CQCallbackInterface {
};
template <typename F>
-grpc_core::CQCallbackInterface* NewDeletingCallback(F f) {
+grpc_experimental_completion_queue_functor* NewDeletingCallback(F f) {
return grpc_core::New<CQDeletingCallback<F>>(f);
}
-class ShutdownCallback : public grpc_core::CQCallbackInterface {
+class ShutdownCallback : public grpc_experimental_completion_queue_functor {
public:
ShutdownCallback() : done_(false) {
+ functor_run = &ShutdownCallback::StaticRun;
gpr_mu_init(&mu_);
gpr_cv_init(&cv_);
}
- ~ShutdownCallback() override {}
- void Run(bool ok) override {
+ ~ShutdownCallback() {}
+ static void StaticRun(grpc_experimental_completion_queue_functor* cb,
+ int ok) {
+ auto* callback = static_cast<ShutdownCallback*>(cb);
+ callback->Run(static_cast<bool>(ok));
+ }
+ void Run(bool ok) {
gpr_log(GPR_DEBUG, "CQ shutdown notification invoked");
gpr_mu_lock(&mu_);
done_ = true;
@@ -170,7 +179,7 @@ static void verify_tags(gpr_timespec deadline) {
// This function creates a callback functor that emits the
// desired tag into the global tag set
-static grpc_core::CQCallbackInterface* tag(intptr_t t) {
+static grpc_experimental_completion_queue_functor* tag(intptr_t t) {
auto func = [t](bool ok) {
gpr_mu_lock(&tags_mu);
gpr_log(GPR_DEBUG, "Completing operation %" PRIdPTR, t);
diff --git a/test/core/iomgr/BUILD b/test/core/iomgr/BUILD
index 675d9e6278..70ee83acd2 100644
--- a/test/core/iomgr/BUILD
+++ b/test/core/iomgr/BUILD
@@ -40,6 +40,7 @@ grpc_cc_library(
grpc_cc_test(
name = "combiner_test",
srcs = ["combiner_test.cc"],
+ data = ["//third_party/toolchains:RBE_USE_MACHINE_TYPE_LARGE"],
language = "C++",
deps = [
"//:gpr",
@@ -47,7 +48,6 @@ grpc_cc_test(
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
- data = ["//third_party/toolchains:RBE_USE_MACHINE_TYPE_LARGE"],
)
grpc_cc_test(
@@ -89,18 +89,6 @@ grpc_cc_test(
)
grpc_cc_test(
- name = "ev_epollsig_linux_test",
- srcs = ["ev_epollsig_linux_test.cc"],
- language = "C++",
- deps = [
- "//:gpr",
- "//:grpc",
- "//test/core/util:gpr_test_util",
- "//test/core/util:grpc_test_util",
- ],
-)
-
-grpc_cc_test(
name = "fd_conservation_posix_test",
srcs = ["fd_conservation_posix_test.cc"],
language = "C++",
@@ -136,7 +124,6 @@ grpc_cc_test(
],
)
-
grpc_cc_test(
name = "load_file_test",
srcs = ["load_file_test.cc"],
@@ -150,8 +137,8 @@ grpc_cc_test(
)
grpc_cc_test(
- name = "pollset_set_test",
- srcs = ["pollset_set_test.cc"],
+ name = "resolve_address_posix_test",
+ srcs = ["resolve_address_posix_test.cc"],
language = "C++",
deps = [
"//:gpr",
@@ -162,8 +149,11 @@ grpc_cc_test(
)
grpc_cc_test(
- name = "resolve_address_posix_test",
- srcs = ["resolve_address_posix_test.cc"],
+ name = "resolve_address_using_ares_resolver_test",
+ srcs = ["resolve_address_test.cc"],
+ args = [
+ "--resolver=ares",
+ ],
language = "C++",
deps = [
"//:gpr",
@@ -174,8 +164,11 @@ grpc_cc_test(
)
grpc_cc_test(
- name = "resolve_address_test",
+ name = "resolve_address_using_native_resolver_test",
srcs = ["resolve_address_test.cc"],
+ args = [
+ "--resolver=native",
+ ],
language = "C++",
deps = [
"//:gpr",
@@ -258,7 +251,6 @@ grpc_cc_test(
],
)
-
grpc_cc_test(
name = "tcp_server_posix_test",
srcs = ["tcp_server_posix_test.cc"],
diff --git a/test/core/iomgr/ev_epollsig_linux_test.cc b/test/core/iomgr/ev_epollsig_linux_test.cc
deleted file mode 100644
index 28c9dd408c..0000000000
--- a/test/core/iomgr/ev_epollsig_linux_test.cc
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-#include "src/core/lib/iomgr/port.h"
-
-/* This test only relevant on linux systems where epoll() is available */
-#ifdef GRPC_LINUX_EPOLL_CREATE1
-#include "src/core/lib/iomgr/ev_epollsig_linux.h"
-#include "src/core/lib/iomgr/ev_posix.h"
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/gpr/useful.h"
-#include "src/core/lib/gprpp/thd.h"
-#include "src/core/lib/iomgr/iomgr.h"
-#include "test/core/util/test_config.h"
-
-typedef struct test_pollset {
- grpc_pollset* pollset;
- gpr_mu* mu;
-} test_pollset;
-
-typedef struct test_fd {
- int inner_fd;
- grpc_fd* fd;
-} test_fd;
-
-/* num_fds should be an even number */
-static void test_fd_init(test_fd* tfds, int* fds, int num_fds) {
- int i;
- int r;
-
- /* Create some dummy file descriptors. Currently using pipe file descriptors
- * for this test but we could use any other type of file descriptors. Also,
- * since pipe() used in this test creates two fds in each call, num_fds should
- * be an even number */
- GPR_ASSERT((num_fds % 2) == 0);
- for (i = 0; i < num_fds; i = i + 2) {
- r = pipe(fds + i);
- if (r != 0) {
- gpr_log(GPR_ERROR, "Error in creating pipe. %d (%s)", errno,
- strerror(errno));
- return;
- }
- }
-
- for (i = 0; i < num_fds; i++) {
- tfds[i].inner_fd = fds[i];
- tfds[i].fd = grpc_fd_create(fds[i], "test_fd", false);
- }
-}
-
-static void test_fd_cleanup(test_fd* tfds, int num_fds) {
- int release_fd;
- int i;
-
- for (i = 0; i < num_fds; i++) {
- grpc_fd_shutdown(tfds[i].fd,
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("test_fd_cleanup"));
- grpc_core::ExecCtx::Get()->Flush();
-
- grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup");
- grpc_core::ExecCtx::Get()->Flush();
-
- GPR_ASSERT(release_fd == tfds[i].inner_fd);
- close(tfds[i].inner_fd);
- }
-}
-
-static void test_pollset_init(test_pollset* pollsets, int num_pollsets) {
- int i;
- for (i = 0; i < num_pollsets; i++) {
- pollsets[i].pollset =
- static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
- grpc_pollset_init(pollsets[i].pollset, &pollsets[i].mu);
- }
-}
-
-static void destroy_pollset(void* p, grpc_error* error) {
- grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
-}
-
-static void test_pollset_cleanup(test_pollset* pollsets, int num_pollsets) {
- grpc_closure destroyed;
- int i;
-
- for (i = 0; i < num_pollsets; i++) {
- GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, pollsets[i].pollset,
- grpc_schedule_on_exec_ctx);
- grpc_pollset_shutdown(pollsets[i].pollset, &destroyed);
-
- grpc_core::ExecCtx::Get()->Flush();
- gpr_free(pollsets[i].pollset);
- }
-}
-
- /*
- * Cases to test:
- * case 1) Polling islands of both fd and pollset are NULL
- * case 2) Polling island of fd is NULL but that of pollset is not-NULL
- * case 3) Polling island of fd is not-NULL but that of pollset is NULL
- * case 4) Polling islands of both fd and pollset are not-NULL and:
- * case 4.1) Polling islands of fd and pollset are equal
- * case 4.2) Polling islands of fd and pollset are NOT-equal (This results
- * in a merge)
- * */
-
-#define NUM_FDS 8
-#define NUM_POLLSETS 4
-
-static void test_add_fd_to_pollset() {
- grpc_core::ExecCtx exec_ctx;
- test_fd tfds[NUM_FDS];
- int fds[NUM_FDS];
- test_pollset pollsets[NUM_POLLSETS];
- void* expected_pi = nullptr;
- int i;
-
- test_fd_init(tfds, fds, NUM_FDS);
- test_pollset_init(pollsets, NUM_POLLSETS);
-
- /*Step 1.
- * Create three polling islands (This will exercise test case 1 and 2) with
- * the following configuration:
- * polling island 0 = { fds:0,1,2, pollsets:0}
- * polling island 1 = { fds:3,4, pollsets:1}
- * polling island 2 = { fds:5,6,7 pollsets:2}
- *
- *Step 2.
- * Add pollset 3 to polling island 0 (by adding fds 0 and 1 to pollset 3)
- * (This will exercise test cases 3 and 4.1). The configuration becomes:
- * polling island 0 = { fds:0,1,2, pollsets:0,3} <<< pollset 3 added here
- * polling island 1 = { fds:3,4, pollsets:1}
- * polling island 2 = { fds:5,6,7 pollsets:2}
- *
- *Step 3.
- * Merge polling islands 0 and 1 by adding fd 0 to pollset 1 (This will
- * exercise test case 4.2). The configuration becomes:
- * polling island (merged) = {fds: 0,1,2,3,4, pollsets: 0,1,3}
- * polling island 2 = {fds: 5,6,7 pollsets: 2}
- *
- *Step 4.
- * Finally do one more merge by adding fd 3 to pollset 2.
- * polling island (merged) = {fds: 0,1,2,3,4,5,6,7, pollsets: 0,1,2,3}
- */
-
- /* == Step 1 == */
- for (i = 0; i <= 2; i++) {
- grpc_pollset_add_fd(pollsets[0].pollset, tfds[i].fd);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- for (i = 3; i <= 4; i++) {
- grpc_pollset_add_fd(pollsets[1].pollset, tfds[i].fd);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- for (i = 5; i <= 7; i++) {
- grpc_pollset_add_fd(pollsets[2].pollset, tfds[i].fd);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- /* == Step 2 == */
- for (i = 0; i <= 1; i++) {
- grpc_pollset_add_fd(pollsets[3].pollset, tfds[i].fd);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- /* == Step 3 == */
- grpc_pollset_add_fd(pollsets[1].pollset, tfds[0].fd);
- grpc_core::ExecCtx::Get()->Flush();
-
- /* == Step 4 == */
- grpc_pollset_add_fd(pollsets[2].pollset, tfds[3].fd);
- grpc_core::ExecCtx::Get()->Flush();
-
- /* All polling islands are merged at this point */
-
- /* Compare Fd:0's polling island with that of all other Fds */
- expected_pi = grpc_fd_get_polling_island(tfds[0].fd);
- for (i = 1; i < NUM_FDS; i++) {
- GPR_ASSERT(grpc_are_polling_islands_equal(
- expected_pi, grpc_fd_get_polling_island(tfds[i].fd)));
- }
-
- /* Compare Fd:0's polling island with that of all other pollsets */
- for (i = 0; i < NUM_POLLSETS; i++) {
- GPR_ASSERT(grpc_are_polling_islands_equal(
- expected_pi, grpc_pollset_get_polling_island(pollsets[i].pollset)));
- }
-
- test_fd_cleanup(tfds, NUM_FDS);
- test_pollset_cleanup(pollsets, NUM_POLLSETS);
-}
-
-#undef NUM_FDS
-#undef NUM_POLLSETS
-
-typedef struct threading_shared {
- gpr_mu* mu;
- grpc_pollset* pollset;
- grpc_wakeup_fd* wakeup_fd;
- grpc_fd* wakeup_desc;
- grpc_closure on_wakeup;
- int wakeups;
-} threading_shared;
-
-static __thread int thread_wakeups = 0;
-
-static void test_threading_loop(void* arg) {
- threading_shared* shared = static_cast<threading_shared*>(arg);
- while (thread_wakeups < 1000000) {
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_worker* worker;
- gpr_mu_lock(shared->mu);
- GPR_ASSERT(GRPC_LOG_IF_ERROR(
- "pollset_work",
- grpc_pollset_work(shared->pollset, &worker, GRPC_MILLIS_INF_FUTURE)));
- gpr_mu_unlock(shared->mu);
- }
-}
-
-static void test_threading_wakeup(void* arg, grpc_error* error) {
- threading_shared* shared = static_cast<threading_shared*>(arg);
- ++shared->wakeups;
- ++thread_wakeups;
- if (error == GRPC_ERROR_NONE) {
- GPR_ASSERT(GRPC_LOG_IF_ERROR(
- "consume_wakeup", grpc_wakeup_fd_consume_wakeup(shared->wakeup_fd)));
- grpc_fd_notify_on_read(shared->wakeup_desc, &shared->on_wakeup);
- GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_next",
- grpc_wakeup_fd_wakeup(shared->wakeup_fd)));
- }
-}
-
-static void test_threading(void) {
- threading_shared shared;
- shared.pollset = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
- grpc_pollset_init(shared.pollset, &shared.mu);
-
- grpc_core::Thread thds[10];
- for (auto& th : thds) {
- th = grpc_core::Thread("test_thread", test_threading_loop, &shared);
- th.Start();
- }
- grpc_wakeup_fd fd;
- GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_fd_init", grpc_wakeup_fd_init(&fd)));
- shared.wakeup_fd = &fd;
- shared.wakeup_desc = grpc_fd_create(fd.read_fd, "wakeup", false);
- shared.wakeups = 0;
- {
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_add_fd(shared.pollset, shared.wakeup_desc);
- grpc_fd_notify_on_read(
- shared.wakeup_desc,
- GRPC_CLOSURE_INIT(&shared.on_wakeup, test_threading_wakeup, &shared,
- grpc_schedule_on_exec_ctx));
- }
- GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_first",
- grpc_wakeup_fd_wakeup(shared.wakeup_fd)));
- for (auto& th : thds) {
- th.Join();
- }
- fd.read_fd = 0;
- grpc_wakeup_fd_destroy(&fd);
- {
- grpc_core::ExecCtx exec_ctx;
- grpc_fd_shutdown(shared.wakeup_desc, GRPC_ERROR_CANCELLED);
- grpc_fd_orphan(shared.wakeup_desc, nullptr, nullptr, "done");
- grpc_pollset_shutdown(shared.pollset,
- GRPC_CLOSURE_CREATE(destroy_pollset, shared.pollset,
- grpc_schedule_on_exec_ctx));
- }
- gpr_free(shared.pollset);
-}
-
-int main(int argc, char** argv) {
- const char* poll_strategy = nullptr;
- grpc_test_init(argc, argv);
- grpc_init();
- {
- grpc_core::ExecCtx exec_ctx;
-
- poll_strategy = grpc_get_poll_strategy_name();
- if (poll_strategy != nullptr && strcmp(poll_strategy, "epollsig") == 0) {
- test_add_fd_to_pollset();
- test_threading();
- } else {
- gpr_log(GPR_INFO,
- "Skipping the test. The test is only relevant for 'epollsig' "
- "strategy. and the current strategy is: '%s'",
- poll_strategy);
- }
- }
-
- grpc_shutdown();
- return 0;
-}
-#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */
-int main(int argc, char** argv) { return 0; }
-#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */
diff --git a/test/core/iomgr/pollset_set_test.cc b/test/core/iomgr/pollset_set_test.cc
deleted file mode 100644
index 1aae1daa02..0000000000
--- a/test/core/iomgr/pollset_set_test.cc
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-#include "src/core/lib/iomgr/port.h"
-
-/* This test only relevant on linux systems where epoll is available */
-#ifdef GRPC_LINUX_EPOLL_CREATE1
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/gpr/useful.h"
-#include "src/core/lib/iomgr/ev_posix.h"
-#include "src/core/lib/iomgr/iomgr.h"
-#include "test/core/util/test_config.h"
-
-/*******************************************************************************
- * test_pollset_set
- */
-
-typedef struct test_pollset_set {
- grpc_pollset_set* pss;
-} test_pollset_set;
-
-void init_test_pollset_sets(test_pollset_set* pollset_sets, const int num_pss) {
- for (int i = 0; i < num_pss; i++) {
- pollset_sets[i].pss = grpc_pollset_set_create();
- }
-}
-
-void cleanup_test_pollset_sets(test_pollset_set* pollset_sets,
- const int num_pss) {
- for (int i = 0; i < num_pss; i++) {
- grpc_pollset_set_destroy(pollset_sets[i].pss);
- pollset_sets[i].pss = nullptr;
- }
-}
-
-/*******************************************************************************
- * test_pollset
- */
-
-typedef struct test_pollset {
- grpc_pollset* ps;
- gpr_mu* mu;
-} test_pollset;
-
-static void init_test_pollsets(test_pollset* pollsets, const int num_pollsets) {
- for (int i = 0; i < num_pollsets; i++) {
- pollsets[i].ps =
- static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
- grpc_pollset_init(pollsets[i].ps, &pollsets[i].mu);
- }
-}
-
-static void destroy_pollset(void* p, grpc_error* error) {
- grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
-}
-
-static void cleanup_test_pollsets(test_pollset* pollsets,
- const int num_pollsets) {
- grpc_closure destroyed;
- for (int i = 0; i < num_pollsets; i++) {
- GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, pollsets[i].ps,
- grpc_schedule_on_exec_ctx);
- grpc_pollset_shutdown(pollsets[i].ps, &destroyed);
-
- grpc_core::ExecCtx::Get()->Flush();
- gpr_free(pollsets[i].ps);
- pollsets[i].ps = nullptr;
- }
-}
-
-/*******************************************************************************
- * test_fd
- */
-
-typedef struct test_fd {
- grpc_fd* fd;
- grpc_wakeup_fd wakeup_fd;
-
- bool is_on_readable_called; /* Is on_readable closure is called ? */
- grpc_closure on_readable; /* Closure to call when this fd is readable */
-} test_fd;
-
-void on_readable(void* tfd, grpc_error* error) {
- (static_cast<test_fd*>(tfd))->is_on_readable_called = true;
-}
-
-static void reset_test_fd(test_fd* tfd) {
- tfd->is_on_readable_called = false;
-
- GRPC_CLOSURE_INIT(&tfd->on_readable, on_readable, tfd,
- grpc_schedule_on_exec_ctx);
- grpc_fd_notify_on_read(tfd->fd, &tfd->on_readable);
-}
-
-static void init_test_fds(test_fd* tfds, const int num_fds) {
- for (int i = 0; i < num_fds; i++) {
- GPR_ASSERT(GRPC_ERROR_NONE == grpc_wakeup_fd_init(&tfds[i].wakeup_fd));
- tfds[i].fd = grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&tfds[i].wakeup_fd),
- "test_fd", false);
- reset_test_fd(&tfds[i]);
- }
-}
-
-static void cleanup_test_fds(test_fd* tfds, const int num_fds) {
- int release_fd;
-
- for (int i = 0; i < num_fds; i++) {
- grpc_fd_shutdown(tfds[i].fd,
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("fd cleanup"));
- grpc_core::ExecCtx::Get()->Flush();
-
- /* grpc_fd_orphan frees the memory allocated for grpc_fd. Normally it also
- * calls close() on the underlying fd. In our case, we are using
- * grpc_wakeup_fd and we would like to destroy it ourselves (by calling
- * grpc_wakeup_fd_destroy). To prevent grpc_fd from calling close() on the
- * underlying fd, call it with a non-NULL 'release_fd' parameter */
- grpc_fd_orphan(tfds[i].fd, nullptr, &release_fd, "test_fd_cleanup");
- grpc_core::ExecCtx::Get()->Flush();
-
- grpc_wakeup_fd_destroy(&tfds[i].wakeup_fd);
- }
-}
-
-static void make_test_fds_readable(test_fd* tfds, const int num_fds) {
- for (int i = 0; i < num_fds; i++) {
- GPR_ASSERT(GRPC_ERROR_NONE == grpc_wakeup_fd_wakeup(&tfds[i].wakeup_fd));
- }
-}
-
-static void verify_readable_and_reset(test_fd* tfds, const int num_fds) {
- for (int i = 0; i < num_fds; i++) {
- /* Verify that the on_readable callback was called */
- GPR_ASSERT(tfds[i].is_on_readable_called);
-
- /* Reset the tfd[i] structure */
- GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_wakeup_fd_consume_wakeup(&tfds[i].wakeup_fd));
- reset_test_fd(&tfds[i]);
- }
-}
-
-/*******************************************************************************
- * Main tests
- */
-
-/* Test some typical scenarios in pollset_set */
-static void pollset_set_test_basic() {
- /* We construct the following structure for this test:
- *
- * +---> FD0 (Added before PSS1, PS1 and PS2 are added to PSS0)
- * |
- * +---> FD5 (Added after PSS1, PS1 and PS2 are added to PSS0)
- * |
- * |
- * | +---> FD1 (Added before PSS1 is added to PSS0)
- * | |
- * | +---> FD6 (Added after PSS1 is added to PSS0)
- * | |
- * +---> PSS1--+ +--> FD2 (Added before PS0 is added to PSS1)
- * | | |
- * | +---> PS0---+
- * | |
- * PSS0---+ +--> FD7 (Added after PS0 is added to PSS1)
- * |
- * |
- * | +---> FD3 (Added before PS1 is added to PSS0)
- * | |
- * +---> PS1---+
- * | |
- * | +---> FD8 (Added after PS1 added to PSS0)
- * |
- * |
- * | +---> FD4 (Added before PS2 is added to PSS0)
- * | |
- * +---> PS2---+
- * |
- * +---> FD9 (Added after PS2 is added to PSS0)
- */
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_worker* worker;
- grpc_millis deadline;
-
- test_fd tfds[10];
- test_pollset pollsets[3];
- test_pollset_set pollset_sets[2];
- const int num_fds = GPR_ARRAY_SIZE(tfds);
- const int num_ps = GPR_ARRAY_SIZE(pollsets);
- const int num_pss = GPR_ARRAY_SIZE(pollset_sets);
-
- init_test_fds(tfds, num_fds);
- init_test_pollsets(pollsets, num_ps);
- init_test_pollset_sets(pollset_sets, num_pss);
-
- /* Construct the pollset_set/pollset/fd tree (see diagram above) */
-
- grpc_pollset_set_add_fd(pollset_sets[0].pss, tfds[0].fd);
- grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[1].fd);
-
- grpc_pollset_add_fd(pollsets[0].ps, tfds[2].fd);
- grpc_pollset_add_fd(pollsets[1].ps, tfds[3].fd);
- grpc_pollset_add_fd(pollsets[2].ps, tfds[4].fd);
-
- grpc_pollset_set_add_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss);
-
- grpc_pollset_set_add_pollset(pollset_sets[1].pss, pollsets[0].ps);
- grpc_pollset_set_add_pollset(pollset_sets[0].pss, pollsets[1].ps);
- grpc_pollset_set_add_pollset(pollset_sets[0].pss, pollsets[2].ps);
-
- grpc_pollset_set_add_fd(pollset_sets[0].pss, tfds[5].fd);
- grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[6].fd);
-
- grpc_pollset_add_fd(pollsets[0].ps, tfds[7].fd);
- grpc_pollset_add_fd(pollsets[1].ps, tfds[8].fd);
- grpc_pollset_add_fd(pollsets[2].ps, tfds[9].fd);
-
- grpc_core::ExecCtx::Get()->Flush();
-
- /* Test that if any FD in the above structure is readable, it is observable by
- * doing grpc_pollset_work on any pollset
- *
- * For every pollset, do the following:
- * - (Ensure that all FDs are in reset state)
- * - Make all FDs readable
- * - Call grpc_pollset_work() on the pollset
- * - Flush the exec_ctx
- * - Verify that on_readable call back was called for all FDs (and
- * reset the FDs)
- * */
- for (int i = 0; i < num_ps; i++) {
- make_test_fds_readable(tfds, num_fds);
-
- gpr_mu_lock(pollsets[i].mu);
- deadline = grpc_timespec_to_millis_round_up(
- grpc_timeout_milliseconds_to_deadline(2));
- GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_pollset_work(pollsets[i].ps, &worker, deadline));
- gpr_mu_unlock(pollsets[i].mu);
-
- grpc_core::ExecCtx::Get()->Flush();
-
- verify_readable_and_reset(tfds, num_fds);
- grpc_core::ExecCtx::Get()->Flush();
- }
-
- /* Test tear down */
- grpc_pollset_set_del_fd(pollset_sets[0].pss, tfds[0].fd);
- grpc_pollset_set_del_fd(pollset_sets[0].pss, tfds[5].fd);
- grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[1].fd);
- grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[6].fd);
- grpc_core::ExecCtx::Get()->Flush();
-
- grpc_pollset_set_del_pollset(pollset_sets[1].pss, pollsets[0].ps);
- grpc_pollset_set_del_pollset(pollset_sets[0].pss, pollsets[1].ps);
- grpc_pollset_set_del_pollset(pollset_sets[0].pss, pollsets[2].ps);
-
- grpc_pollset_set_del_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss);
- grpc_core::ExecCtx::Get()->Flush();
-
- cleanup_test_fds(tfds, num_fds);
- cleanup_test_pollsets(pollsets, num_ps);
- cleanup_test_pollset_sets(pollset_sets, num_pss);
-}
-
-/* Same FD added multiple times to the pollset_set tree */
-void pollset_set_test_dup_fds() {
- /* We construct the following structure for this test:
- *
- * +---> FD0
- * |
- * |
- * PSS0---+
- * | +---> FD0 (also under PSS0)
- * | |
- * +---> PSS1--+ +--> FD1 (also under PSS1)
- * | |
- * +---> PS ---+
- * | |
- * | +--> FD2
- * +---> FD1
- */
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_worker* worker;
- grpc_millis deadline;
-
- test_fd tfds[3];
- test_pollset pollset;
- test_pollset_set pollset_sets[2];
- const int num_fds = GPR_ARRAY_SIZE(tfds);
- const int num_ps = 1;
- const int num_pss = GPR_ARRAY_SIZE(pollset_sets);
-
- init_test_fds(tfds, num_fds);
- init_test_pollsets(&pollset, num_ps);
- init_test_pollset_sets(pollset_sets, num_pss);
-
- /* Construct the structure */
- grpc_pollset_set_add_fd(pollset_sets[0].pss, tfds[0].fd);
- grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[0].fd);
- grpc_pollset_set_add_fd(pollset_sets[1].pss, tfds[1].fd);
-
- grpc_pollset_add_fd(pollset.ps, tfds[1].fd);
- grpc_pollset_add_fd(pollset.ps, tfds[2].fd);
-
- grpc_pollset_set_add_pollset(pollset_sets[1].pss, pollset.ps);
- grpc_pollset_set_add_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss);
-
- /* Test. Make all FDs readable and make sure that can be observed by doing a
- * grpc_pollset_work on the pollset 'PS' */
- make_test_fds_readable(tfds, num_fds);
-
- gpr_mu_lock(pollset.mu);
- deadline = grpc_timespec_to_millis_round_up(
- grpc_timeout_milliseconds_to_deadline(2));
- GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_pollset_work(pollset.ps, &worker, deadline));
- gpr_mu_unlock(pollset.mu);
- grpc_core::ExecCtx::Get()->Flush();
-
- verify_readable_and_reset(tfds, num_fds);
- grpc_core::ExecCtx::Get()->Flush();
-
- /* Tear down */
- grpc_pollset_set_del_fd(pollset_sets[0].pss, tfds[0].fd);
- grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[0].fd);
- grpc_pollset_set_del_fd(pollset_sets[1].pss, tfds[1].fd);
-
- grpc_pollset_set_del_pollset(pollset_sets[1].pss, pollset.ps);
- grpc_pollset_set_del_pollset_set(pollset_sets[0].pss, pollset_sets[1].pss);
- grpc_core::ExecCtx::Get()->Flush();
-
- cleanup_test_fds(tfds, num_fds);
- cleanup_test_pollsets(&pollset, num_ps);
- cleanup_test_pollset_sets(pollset_sets, num_pss);
-}
-
-/* Pollset_set with an empty pollset */
-void pollset_set_test_empty_pollset() {
- /* We construct the following structure for this test:
- *
- * +---> PS0 (EMPTY)
- * |
- * +---> FD0
- * |
- * PSS0---+
- * | +---> FD1
- * | |
- * +---> PS1--+
- * |
- * +---> FD2
- */
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_worker* worker;
- grpc_millis deadline;
-
- test_fd tfds[3];
- test_pollset pollsets[2];
- test_pollset_set pollset_set;
- const int num_fds = GPR_ARRAY_SIZE(tfds);
- const int num_ps = GPR_ARRAY_SIZE(pollsets);
- const int num_pss = 1;
-
- init_test_fds(tfds, num_fds);
- init_test_pollsets(pollsets, num_ps);
- init_test_pollset_sets(&pollset_set, num_pss);
-
- /* Construct the structure */
- grpc_pollset_set_add_fd(pollset_set.pss, tfds[0].fd);
- grpc_pollset_add_fd(pollsets[1].ps, tfds[1].fd);
- grpc_pollset_add_fd(pollsets[1].ps, tfds[2].fd);
-
- grpc_pollset_set_add_pollset(pollset_set.pss, pollsets[0].ps);
- grpc_pollset_set_add_pollset(pollset_set.pss, pollsets[1].ps);
-
- /* Test. Make all FDs readable and make sure that can be observed by doing
- * grpc_pollset_work on the empty pollset 'PS0' */
- make_test_fds_readable(tfds, num_fds);
-
- gpr_mu_lock(pollsets[0].mu);
- deadline = grpc_timespec_to_millis_round_up(
- grpc_timeout_milliseconds_to_deadline(2));
- GPR_ASSERT(GRPC_ERROR_NONE ==
- grpc_pollset_work(pollsets[0].ps, &worker, deadline));
- gpr_mu_unlock(pollsets[0].mu);
- grpc_core::ExecCtx::Get()->Flush();
-
- verify_readable_and_reset(tfds, num_fds);
- grpc_core::ExecCtx::Get()->Flush();
-
- /* Tear down */
- grpc_pollset_set_del_fd(pollset_set.pss, tfds[0].fd);
- grpc_pollset_set_del_pollset(pollset_set.pss, pollsets[0].ps);
- grpc_pollset_set_del_pollset(pollset_set.pss, pollsets[1].ps);
- grpc_core::ExecCtx::Get()->Flush();
-
- cleanup_test_fds(tfds, num_fds);
- cleanup_test_pollsets(pollsets, num_ps);
- cleanup_test_pollset_sets(&pollset_set, num_pss);
-}
-
-int main(int argc, char** argv) {
- grpc_test_init(argc, argv);
- grpc_init();
- {
- grpc_core::ExecCtx exec_ctx;
- const char* poll_strategy = grpc_get_poll_strategy_name();
-
- if (poll_strategy != nullptr &&
- (strcmp(poll_strategy, "epollsig") == 0 ||
- strcmp(poll_strategy, "epoll-threadpool") == 0)) {
- pollset_set_test_basic();
- pollset_set_test_dup_fds();
- pollset_set_test_empty_pollset();
- } else {
- gpr_log(GPR_INFO,
- "Skipping the test. The test is only relevant for 'epoll' "
- "strategy. and the current strategy is: '%s'",
- poll_strategy);
- }
- }
- grpc_shutdown();
- return 0;
-}
-#else /* defined(GRPC_LINUX_EPOLL_CREATE1) */
-int main(int argc, char** argv) { return 0; }
-#endif /* !defined(GRPC_LINUX_EPOLL_CREATE1) */
diff --git a/test/core/iomgr/resolve_address_test.cc b/test/core/iomgr/resolve_address_test.cc
index 2fb831a6a4..52e4840c7c 100644
--- a/test/core/iomgr/resolve_address_test.cc
+++ b/test/core/iomgr/resolve_address_test.cc
@@ -22,8 +22,14 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
+
+#include <string.h>
+
+#include "src/core/lib/gpr/env.h"
+#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr.h"
+#include "test/core/util/cmdline.h"
#include "test/core/util/test_config.h"
static gpr_timespec test_deadline(void) {
@@ -240,6 +246,28 @@ static void test_unparseable_hostports(void) {
}
int main(int argc, char** argv) {
+ // First set the resolver type based off of --resolver
+ const char* resolver_type = nullptr;
+ gpr_cmdline* cl = gpr_cmdline_create("resolve address test");
+ gpr_cmdline_add_string(cl, "resolver", "Resolver type (ares or native)",
+ &resolver_type);
+ gpr_cmdline_parse(cl, argc, argv);
+ const char* cur_resolver = gpr_getenv("GRPC_DNS_RESOLVER");
+ if (cur_resolver != nullptr && strlen(cur_resolver) != 0) {
+ gpr_log(GPR_INFO, "Warning: overriding resolver setting of %s",
+ cur_resolver);
+ }
+ if (gpr_stricmp(resolver_type, "native") == 0) {
+ gpr_setenv("GRPC_DNS_RESOLVER", "native");
+ } else if (gpr_stricmp(resolver_type, "ares") == 0) {
+#ifndef GRPC_UV
+ gpr_setenv("GRPC_DNS_RESOLVER", "ares");
+#endif
+ } else {
+ gpr_log(GPR_ERROR, "--resolver_type was not set to ares or native");
+ abort();
+ }
+ // Run the test.
grpc_test_init(argc, argv);
grpc_init();
{
@@ -250,10 +278,18 @@ int main(int argc, char** argv) {
test_missing_default_port();
test_ipv6_with_port();
test_ipv6_without_port();
- test_invalid_ip_addresses();
- test_unparseable_hostports();
+ if (gpr_stricmp(resolver_type, "ares") != 0) {
+ // These tests can trigger DNS queries to the nearby nameserver
+ // that need to come back in order for the test to succeed.
+ // c-ares is prone to not using the local system caches that the
+ // native getaddrinfo implementations take advantage of, so running
+ // these unit tests under c-ares risks flakiness.
+ test_invalid_ip_addresses();
+ test_unparseable_hostports();
+ }
grpc_executor_shutdown();
}
+ gpr_cmdline_destroy(cl);
grpc_shutdown();
return 0;
diff --git a/test/core/surface/completion_queue_test.cc b/test/core/surface/completion_queue_test.cc
index b889fd0fc6..f7ce8a7042 100644
--- a/test/core/surface/completion_queue_test.cc
+++ b/test/core/surface/completion_queue_test.cc
@@ -369,11 +369,15 @@ static void test_callback(void) {
LOG_TEST("test_callback");
bool got_shutdown = false;
- class ShutdownCallback : public grpc_core::CQCallbackInterface {
+ class ShutdownCallback : public grpc_experimental_completion_queue_functor {
public:
- ShutdownCallback(bool* done) : done_(done) {}
+ ShutdownCallback(bool* done) : done_(done) {
+ functor_run = &ShutdownCallback::Run;
+ }
~ShutdownCallback() {}
- void Run(bool ok) override { *done_ = ok; }
+ static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
+ *static_cast<ShutdownCallback*>(cb)->done_ = static_cast<bool>(ok);
+ }
private:
bool* done_;
@@ -391,14 +395,17 @@ static void test_callback(void) {
grpc_completion_queue_factory_lookup(&attr), &attr, nullptr);
int counter = 0;
- class TagCallback : public grpc_core::CQCallbackInterface {
+ class TagCallback : public grpc_experimental_completion_queue_functor {
public:
- TagCallback(int* counter, int tag) : counter_(counter), tag_(tag) {}
+ TagCallback(int* counter, int tag) : counter_(counter), tag_(tag) {
+ functor_run = &TagCallback::Run;
+ }
~TagCallback() {}
- void Run(bool ok) override {
- GPR_ASSERT(ok);
- *counter_ += tag_;
- grpc_core::Delete(this);
+ static void Run(grpc_experimental_completion_queue_functor* cb, int ok) {
+ GPR_ASSERT(static_cast<bool>(ok));
+ auto* callback = static_cast<TagCallback*>(cb);
+ *callback->counter_ += callback->tag_;
+ grpc_core::Delete(callback);
};
private:
diff --git a/test/core/transport/chttp2/hpack_encoder_test.cc b/test/core/transport/chttp2/hpack_encoder_test.cc
index 2a57198ab6..ab819f9092 100644
--- a/test/core/transport/chttp2/hpack_encoder_test.cc
+++ b/test/core/transport/chttp2/hpack_encoder_test.cc
@@ -202,7 +202,7 @@ static void verify_table_size_change_match_elem_size(const char* key,
grpc_mdelem elem = grpc_mdelem_from_slices(
grpc_slice_intern(grpc_slice_from_static_string(key)),
grpc_slice_intern(grpc_slice_from_static_string(value)));
- size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, use_true_binary);
+ size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, use_true_binary);
size_t initial_table_size = g_compressor.table_size;
grpc_linked_mdelem* e =
static_cast<grpc_linked_mdelem*>(gpr_malloc(sizeof(*e)));
diff --git a/test/core/transport/metadata_test.cc b/test/core/transport/metadata_test.cc
index 4be34f72d9..8ab9639dfa 100644
--- a/test/core/transport/metadata_test.cc
+++ b/test/core/transport/metadata_test.cc
@@ -27,6 +27,7 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+#include "src/core/ext/transport/chttp2/transport/hpack_table.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_internal.h"
@@ -293,7 +294,7 @@ static void verify_ascii_header_size(const char* key, const char* value,
grpc_mdelem elem = grpc_mdelem_from_slices(
maybe_intern(grpc_slice_from_static_string(key), intern_key),
maybe_intern(grpc_slice_from_static_string(value), intern_value));
- size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false);
+ size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, false);
size_t expected_size = 32 + strlen(key) + strlen(value);
GPR_ASSERT(expected_size == elem_size);
GRPC_MDELEM_UNREF(elem);
@@ -307,7 +308,7 @@ static void verify_binary_header_size(const char* key, const uint8_t* value,
maybe_intern(grpc_slice_from_static_buffer(value, value_len),
intern_value));
GPR_ASSERT(grpc_is_binary_header(GRPC_MDKEY(elem)));
- size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem, false);
+ size_t elem_size = grpc_chttp2_get_size_in_hpack_table(elem, false);
grpc_slice value_slice = grpc_slice_from_copied_buffer(
reinterpret_cast<const char*>(value), value_len);
grpc_slice base64_encoded = grpc_chttp2_base64_encode(value_slice);
diff --git a/test/core/tsi/alts/fake_handshaker/BUILD b/test/core/tsi/alts/fake_handshaker/BUILD
index a09a046d27..98cd628a7d 100644
--- a/test/core/tsi/alts/fake_handshaker/BUILD
+++ b/test/core/tsi/alts/fake_handshaker/BUILD
@@ -37,21 +37,22 @@ grpc_cc_library(
name = "fake_handshaker_lib",
testonly = True,
srcs = ["fake_handshaker_server.cc"],
+ hdrs = ["fake_handshaker_server.h"],
language = "C++",
deps = [
"handshaker_proto",
"transport_security_common_proto",
"//:grpc++",
- "//test/cpp/util:test_config",
],
)
grpc_cc_binary(
name = "fake_handshaker_server",
testonly = True,
- srcs = ["fake_handshaker_server.cc"],
+ srcs = ["fake_handshaker_server_main.cc"],
language = "C++",
deps = [
+ "//test/cpp/util:test_config",
"fake_handshaker_lib",
],
)
diff --git a/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc
index f6a4791b49..ba246b07eb 100644
--- a/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc
+++ b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.cc
@@ -15,12 +15,12 @@
* limitations under the License.
*
*/
+#include "test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h"
#include <memory>
#include <sstream>
#include <string>
-#include <gflags/gflags.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpcpp/impl/codegen/async_stream.h>
@@ -32,10 +32,6 @@
#include "test/core/tsi/alts/fake_handshaker/handshaker.grpc.pb.h"
#include "test/core/tsi/alts/fake_handshaker/handshaker.pb.h"
#include "test/core/tsi/alts/fake_handshaker/transport_security_common.pb.h"
-#include "test/cpp/util/test_config.h"
-
-DEFINE_int32(handshaker_port, 55056,
- "TCP port on which the fake handshaker server listens to.");
// Fake handshake messages.
constexpr char kClientInitFrame[] = "ClientInit";
@@ -243,26 +239,9 @@ class FakeHandshakerService : public HandshakerService::Service {
}
};
-} // namespace gcp
-} // namespace grpc
-
-void RunServer() {
- GPR_ASSERT(FLAGS_handshaker_port != 0);
- std::ostringstream server_address;
- server_address << "[::1]:" << FLAGS_handshaker_port;
- grpc::gcp::FakeHandshakerService service;
- grpc::ServerBuilder builder;
- builder.AddListeningPort(server_address.str(),
- grpc::InsecureServerCredentials());
- builder.RegisterService(&service);
- std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
- gpr_log(GPR_INFO, "Fake handshaker server listening on %s",
- server_address.str().c_str());
- server->Wait();
+std::unique_ptr<grpc::Service> CreateFakeHandshakerService() {
+ return std::unique_ptr<grpc::Service>{new grpc::gcp::FakeHandshakerService};
}
-int main(int argc, char** argv) {
- grpc::testing::InitTest(&argc, &argv, true);
- RunServer();
- return 0;
-}
+} // namespace gcp
+} // namespace grpc
diff --git a/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h
new file mode 100644
index 0000000000..eb4bfdffa1
--- /dev/null
+++ b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <memory>
+#include <string>
+
+#include <grpcpp/grpcpp.h>
+
+namespace grpc {
+namespace gcp {
+
+std::unique_ptr<grpc::Service> CreateFakeHandshakerService();
+
+} // namespace gcp
+} // namespace grpc
diff --git a/test/core/tsi/alts/fake_handshaker/fake_handshaker_server_main.cc b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server_main.cc
new file mode 100644
index 0000000000..60351533d9
--- /dev/null
+++ b/test/core/tsi/alts/fake_handshaker/fake_handshaker_server_main.cc
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h"
+
+#include <sstream>
+
+#include <gflags/gflags.h>
+#include <grpc/support/log.h>
+#include <grpcpp/impl/codegen/service_type.h>
+#include <grpcpp/server_builder.h>
+
+#include "test/cpp/util/test_config.h"
+
+DEFINE_int32(handshaker_port, 55056,
+ "TCP port on which the fake handshaker server listens to.");
+
+static void RunFakeHandshakerServer(const std::string& server_address) {
+ std::unique_ptr<grpc::Service> service =
+ grpc::gcp::CreateFakeHandshakerService();
+ grpc::ServerBuilder builder;
+ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ builder.RegisterService(service.get());
+ gpr_log(GPR_INFO, "Fake handshaker server listening on %s",
+ server_address.c_str());
+ std::unique_ptr<grpc::Server> server = builder.BuildAndStart();
+ server->Wait();
+}
+
+int main(int argc, char** argv) {
+ grpc::testing::InitTest(&argc, &argv, true);
+
+ GPR_ASSERT(FLAGS_handshaker_port != 0);
+ std::ostringstream server_address;
+ server_address << "[::1]:" << FLAGS_handshaker_port;
+
+ RunFakeHandshakerServer(server_address.str());
+ return 0;
+}
diff --git a/test/core/util/port_isolated_runtime_environment.cc b/test/core/util/port_isolated_runtime_environment.cc
index c1ca185a67..1f678c08e5 100644
--- a/test/core/util/port_isolated_runtime_environment.cc
+++ b/test/core/util/port_isolated_runtime_environment.cc
@@ -30,8 +30,8 @@
#include "test/core/util/port.h"
-#define MIN_PORT 49152
-#define MAX_PORT 65535
+#define MIN_PORT 1025
+#define MAX_PORT 32766
static int get_random_port_offset() {
srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden
index 756f6a0224..93e1e68654 100644
--- a/test/cpp/codegen/compiler_test_golden
+++ b/test/cpp/codegen/compiler_test_golden
@@ -26,6 +26,7 @@
#include "src/proto/grpc/testing/compiler_test.pb.h"
+#include <functional>
#include <grpcpp/impl/codegen/async_generic_service.h>
#include <grpcpp/impl/codegen/async_stream.h>
#include <grpcpp/impl/codegen/async_unary_call.h>
@@ -105,6 +106,23 @@ class ServiceA final {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< ::grpc::testing::Request, ::grpc::testing::Response>>(PrepareAsyncMethodA4Raw(context, cq));
}
// Method A4 trailing comment 1
+ class experimental_async_interface {
+ public:
+ virtual ~experimental_async_interface() {}
+ // MethodA1 leading comment 1
+ virtual void MethodA1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) = 0;
+ // MethodA1 trailing comment 1
+ // MethodA2 detached leading comment 1
+ //
+ // Method A2 leading comment 1
+ // Method A2 leading comment 2
+ // MethodA2 trailing comment 1
+ // Method A3 leading comment 1
+ // Method A3 trailing comment 1
+ // Method A4 leading comment 1
+ // Method A4 trailing comment 1
+ };
+ virtual class experimental_async_interface* experimental_async() { return nullptr; }
private:
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* PrepareAsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
@@ -155,9 +173,21 @@ class ServiceA final {
std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>> PrepareAsyncMethodA4(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>>(PrepareAsyncMethodA4Raw(context, cq));
}
+ class experimental_async final :
+ public StubInterface::experimental_async_interface {
+ public:
+ void MethodA1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) override;
+ private:
+ friend class Stub;
+ explicit experimental_async(Stub* stub): stub_(stub) { }
+ Stub* stub() { return stub_; }
+ Stub* stub_;
+ };
+ class experimental_async_interface* experimental_async() override { return &async_stub_; }
private:
std::shared_ptr< ::grpc::ChannelInterface> channel_;
+ class experimental_async async_stub_{this};
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* PrepareAsyncMethodA1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientWriter< ::grpc::testing::Request>* MethodA2Raw(::grpc::ClientContext* context, ::grpc::testing::Response* response) override;
@@ -488,6 +518,14 @@ class ServiceB final {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>>(PrepareAsyncMethodB1Raw(context, request, cq));
}
// MethodB1 trailing comment 1
+ class experimental_async_interface {
+ public:
+ virtual ~experimental_async_interface() {}
+ // MethodB1 leading comment 1
+ virtual void MethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) = 0;
+ // MethodB1 trailing comment 1
+ };
+ virtual class experimental_async_interface* experimental_async() { return nullptr; }
private:
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* AsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::grpc::testing::Response>* PrepareAsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) = 0;
@@ -502,9 +540,21 @@ class ServiceB final {
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>> PrepareAsyncMethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>>(PrepareAsyncMethodB1Raw(context, request, cq));
}
+ class experimental_async final :
+ public StubInterface::experimental_async_interface {
+ public:
+ void MethodB1(::grpc::ClientContext* context, const ::grpc::testing::Request* request, ::grpc::testing::Response* response, std::function<void(::grpc::Status)>) override;
+ private:
+ friend class Stub;
+ explicit experimental_async(Stub* stub): stub_(stub) { }
+ Stub* stub() { return stub_; }
+ Stub* stub_;
+ };
+ class experimental_async_interface* experimental_async() override { return &async_stub_; }
private:
std::shared_ptr< ::grpc::ChannelInterface> channel_;
+ class experimental_async async_stub_{this};
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* PrepareAsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override;
const ::grpc::internal::RpcMethod rpcmethod_MethodB1_;
diff --git a/test/cpp/common/alarm_test.cc b/test/cpp/common/alarm_test.cc
index 57d958349e..e909d03658 100644
--- a/test/cpp/common/alarm_test.cc
+++ b/test/cpp/common/alarm_test.cc
@@ -16,9 +16,13 @@
*
*/
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+
#include <grpcpp/alarm.h>
#include <grpcpp/completion_queue.h>
-#include <thread>
#include <gtest/gtest.h>
@@ -43,6 +47,66 @@ TEST(AlarmTest, RegularExpiry) {
EXPECT_EQ(junk, output_tag);
}
+struct Completion {
+ bool completed = false;
+ std::mutex mu;
+ std::condition_variable cv;
+};
+
+TEST(AlarmTest, CallbackRegularExpiry) {
+ Alarm alarm;
+
+ auto c = std::make_shared<Completion>();
+ alarm.experimental().Set(
+ std::chrono::system_clock::now() + std::chrono::seconds(1), [c](bool ok) {
+ EXPECT_TRUE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c] { return c->completed; }));
+}
+
+TEST(AlarmTest, CallbackZeroExpiry) {
+ Alarm alarm;
+
+ auto c = std::make_shared<Completion>();
+ alarm.experimental().Set(grpc_timeout_seconds_to_deadline(0), [c](bool ok) {
+ EXPECT_TRUE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c] { return c->completed; }));
+}
+
+TEST(AlarmTest, CallbackNegativeExpiry) {
+ Alarm alarm;
+
+ auto c = std::make_shared<Completion>();
+ alarm.experimental().Set(
+ std::chrono::system_clock::now() + std::chrono::seconds(-1),
+ [c](bool ok) {
+ EXPECT_TRUE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c] { return c->completed; }));
+}
+
TEST(AlarmTest, MultithreadedRegularExpiry) {
CompletionQueue cq;
void* junk = reinterpret_cast<void*>(1618033);
@@ -182,6 +246,26 @@ TEST(AlarmTest, Cancellation) {
EXPECT_EQ(junk, output_tag);
}
+TEST(AlarmTest, CallbackCancellation) {
+ Alarm alarm;
+
+ auto c = std::make_shared<Completion>();
+ alarm.experimental().Set(
+ std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c](bool ok) {
+ EXPECT_FALSE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+ alarm.Cancel();
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(1),
+ [c] { return c->completed; }));
+}
+
TEST(AlarmTest, SetDestruction) {
CompletionQueue cq;
void* junk = reinterpret_cast<void*>(1618033);
@@ -200,6 +284,26 @@ TEST(AlarmTest, SetDestruction) {
EXPECT_EQ(junk, output_tag);
}
+TEST(AlarmTest, CallbackSetDestruction) {
+ auto c = std::make_shared<Completion>();
+ {
+ Alarm alarm;
+ alarm.experimental().Set(
+ std::chrono::system_clock::now() + std::chrono::seconds(10),
+ [c](bool ok) {
+ EXPECT_FALSE(ok);
+ std::lock_guard<std::mutex> l(c->mu);
+ c->completed = true;
+ c->cv.notify_one();
+ });
+ }
+
+ std::unique_lock<std::mutex> l(c->mu);
+ EXPECT_TRUE(c->cv.wait_until(
+ l, std::chrono::system_clock::now() + std::chrono::seconds(1),
+ [c] { return c->completed; }));
+}
+
TEST(AlarmTest, UnsetDestruction) {
CompletionQueue cq;
Alarm alarm;
diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD
index 75dec56a60..0415efc1ef 100644
--- a/test/cpp/end2end/BUILD
+++ b/test/cpp/end2end/BUILD
@@ -98,6 +98,25 @@ grpc_cc_binary(
],
)
+grpc_cc_test(
+ name = "client_callback_end2end_test",
+ srcs = ["client_callback_end2end_test.cc"],
+ external_deps = [
+ "gtest",
+ ],
+ deps = [
+ ":test_service_impl",
+ "//:gpr",
+ "//:grpc",
+ "//:grpc++",
+ "//src/proto/grpc/testing:echo_messages_proto",
+ "//src/proto/grpc/testing:echo_proto",
+ "//test/core/util:gpr_test_util",
+ "//test/core/util:grpc_test_util",
+ "//test/cpp/util:test_util",
+ ],
+)
+
grpc_cc_library(
name = "end2end_test_lib",
testonly = True,
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index c9246f0806..d97ea071d1 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -178,7 +178,7 @@ class Verifier {
EXPECT_EQ(it2->second.ok, ok);
}
} else {
- gpr_log(GPR_ERROR, "Unexpected tag: %p", tag);
+ gpr_log(GPR_ERROR, "Unexpected tag: %p", got_tag);
abort();
}
}
diff --git a/test/cpp/end2end/client_callback_end2end_test.cc b/test/cpp/end2end/client_callback_end2end_test.cc
new file mode 100644
index 0000000000..62a85641c7
--- /dev/null
+++ b/test/cpp/end2end/client_callback_end2end_test.cc
@@ -0,0 +1,241 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <functional>
+#include <mutex>
+#include <thread>
+
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/generic/generic_stub.h>
+#include <grpcpp/impl/codegen/proto_utils.h>
+#include <grpcpp/server.h>
+#include <grpcpp/server_builder.h>
+#include <grpcpp/server_context.h>
+#include <grpcpp/support/client_callback.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/test_service_impl.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+namespace {
+
+class ClientCallbackEnd2endTest : public ::testing::Test {
+ protected:
+ ClientCallbackEnd2endTest() {}
+
+ void SetUp() override {
+ ServerBuilder builder;
+ builder.RegisterService(&service_);
+
+ server_ = builder.BuildAndStart();
+ is_server_started_ = true;
+ }
+
+ void ResetStub() {
+ ChannelArguments args;
+ channel_ = server_->InProcessChannel(args);
+ stub_ = grpc::testing::EchoTestService::NewStub(channel_);
+ generic_stub_.reset(new GenericStub(channel_));
+ }
+
+ void TearDown() override {
+ if (is_server_started_) {
+ server_->Shutdown();
+ }
+ }
+
+ void SendRpcs(int num_rpcs, bool with_binary_metadata) {
+ grpc::string test_string("");
+ for (int i = 0; i < num_rpcs; i++) {
+ EchoRequest request;
+ EchoResponse response;
+ ClientContext cli_ctx;
+
+ test_string += "Hello world. ";
+ request.set_message(test_string);
+
+ if (with_binary_metadata) {
+ char bytes[8] = {'\0', '\1', '\2', '\3',
+ '\4', '\5', '\6', static_cast<char>(i)};
+ cli_ctx.AddMetadata("custom-bin", grpc::string(bytes, 8));
+ }
+
+ cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
+
+ std::mutex mu;
+ std::condition_variable cv;
+ bool done = false;
+ stub_->experimental_async()->Echo(
+ &cli_ctx, &request, &response,
+ [&request, &response, &done, &mu, &cv](Status s) {
+ GPR_ASSERT(s.ok());
+
+ EXPECT_EQ(request.message(), response.message());
+ std::lock_guard<std::mutex> l(mu);
+ done = true;
+ cv.notify_one();
+ });
+ std::unique_lock<std::mutex> l(mu);
+ while (!done) {
+ cv.wait(l);
+ }
+ }
+ }
+
+ void SendRpcsGeneric(int num_rpcs, bool maybe_except) {
+ const grpc::string kMethodName("/grpc.testing.EchoTestService/Echo");
+ grpc::string test_string("");
+ for (int i = 0; i < num_rpcs; i++) {
+ EchoRequest request;
+ std::unique_ptr<ByteBuffer> send_buf;
+ ByteBuffer recv_buf;
+ ClientContext cli_ctx;
+
+ test_string += "Hello world. ";
+ request.set_message(test_string);
+ send_buf = SerializeToByteBuffer(&request);
+
+ std::mutex mu;
+ std::condition_variable cv;
+ bool done = false;
+ generic_stub_->experimental().UnaryCall(
+ &cli_ctx, kMethodName, send_buf.get(), &recv_buf,
+ [&request, &recv_buf, &done, &mu, &cv, maybe_except](Status s) {
+ GPR_ASSERT(s.ok());
+
+ EchoResponse response;
+ EXPECT_TRUE(ParseFromByteBuffer(&recv_buf, &response));
+ EXPECT_EQ(request.message(), response.message());
+ std::lock_guard<std::mutex> l(mu);
+ done = true;
+ cv.notify_one();
+#if GRPC_ALLOW_EXCEPTIONS
+ if (maybe_except) {
+ throw - 1;
+ }
+#else
+ GPR_ASSERT(!maybe_except);
+#endif
+ });
+ std::unique_lock<std::mutex> l(mu);
+ while (!done) {
+ cv.wait(l);
+ }
+ }
+ }
+
+ bool is_server_started_;
+ std::shared_ptr<Channel> channel_;
+ std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
+ std::unique_ptr<grpc::GenericStub> generic_stub_;
+ TestServiceImpl service_;
+ std::unique_ptr<Server> server_;
+};
+
+TEST_F(ClientCallbackEnd2endTest, SimpleRpc) {
+ ResetStub();
+ SendRpcs(1, false);
+}
+
+TEST_F(ClientCallbackEnd2endTest, SequentialRpcs) {
+ ResetStub();
+ SendRpcs(10, false);
+}
+
+TEST_F(ClientCallbackEnd2endTest, SequentialRpcsWithVariedBinaryMetadataValue) {
+ ResetStub();
+ SendRpcs(10, true);
+}
+
+TEST_F(ClientCallbackEnd2endTest, SequentialGenericRpcs) {
+ ResetStub();
+ SendRpcsGeneric(10, false);
+}
+
+#if GRPC_ALLOW_EXCEPTIONS
+TEST_F(ClientCallbackEnd2endTest, ExceptingRpc) {
+ ResetStub();
+ SendRpcsGeneric(10, true);
+}
+#endif
+
+TEST_F(ClientCallbackEnd2endTest, MultipleRpcsWithVariedBinaryMetadataValue) {
+ ResetStub();
+ std::vector<std::thread> threads;
+ threads.reserve(10);
+ for (int i = 0; i < 10; ++i) {
+ threads.emplace_back([this] { SendRpcs(10, true); });
+ }
+ for (int i = 0; i < 10; ++i) {
+ threads[i].join();
+ }
+}
+
+TEST_F(ClientCallbackEnd2endTest, MultipleRpcs) {
+ ResetStub();
+ std::vector<std::thread> threads;
+ threads.reserve(10);
+ for (int i = 0; i < 10; ++i) {
+ threads.emplace_back([this] { SendRpcs(10, false); });
+ }
+ for (int i = 0; i < 10; ++i) {
+ threads[i].join();
+ }
+}
+
+TEST_F(ClientCallbackEnd2endTest, CancelRpcBeforeStart) {
+ ResetStub();
+ EchoRequest request;
+ EchoResponse response;
+ ClientContext context;
+ request.set_message("hello");
+ context.TryCancel();
+
+ std::mutex mu;
+ std::condition_variable cv;
+ bool done = false;
+ stub_->experimental_async()->Echo(
+ &context, &request, &response, [&response, &done, &mu, &cv](Status s) {
+ EXPECT_EQ("", response.message());
+ EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+ std::lock_guard<std::mutex> l(mu);
+ done = true;
+ cv.notify_one();
+ });
+ std::unique_lock<std::mutex> l(mu);
+ while (!done) {
+ cv.wait(l);
+ }
+}
+
+} // namespace
+} // namespace testing
+} // namespace grpc
+
+int main(int argc, char** argv) {
+ grpc_test_init(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc
index e5d6132012..a9d68ab058 100644
--- a/test/cpp/end2end/client_lb_end2end_test.cc
+++ b/test/cpp/end2end/client_lb_end2end_test.cc
@@ -119,6 +119,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
}
void SetUp() override {
+ grpc_init();
response_generator_ =
grpc_core::MakeRefCounted<grpc_core::FakeResolverResponseGenerator>();
}
@@ -127,6 +128,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
for (size_t i = 0; i < servers_.size(); ++i) {
servers_[i]->Shutdown();
}
+ grpc_shutdown();
}
void CreateServers(size_t num_servers,
@@ -560,7 +562,23 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdateSuperset) {
EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
}
-TEST_F(ClientLbEnd2endTest, PickFirstManyUpdates) {
+class ClientLbEnd2endWithParamTest
+ : public ClientLbEnd2endTest,
+ public ::testing::WithParamInterface<bool> {
+ protected:
+ void SetUp() override {
+ grpc_subchannel_index_test_only_set_force_creation(GetParam());
+ ClientLbEnd2endTest::SetUp();
+ }
+
+ void TearDown() override {
+ ClientLbEnd2endTest::TearDown();
+ grpc_subchannel_index_test_only_set_force_creation(false);
+ }
+};
+
+TEST_P(ClientLbEnd2endWithParamTest, PickFirstManyUpdates) {
+ gpr_log(GPR_INFO, "subchannel force creation: %d", GetParam());
// Start servers and send one RPC per server.
const int kNumServers = 3;
StartServers(kNumServers);
@@ -570,20 +588,21 @@ TEST_F(ClientLbEnd2endTest, PickFirstManyUpdates) {
for (size_t i = 0; i < servers_.size(); ++i) {
ports.emplace_back(servers_[i]->port_);
}
- for (const bool force_creation : {true, false}) {
- grpc_subchannel_index_test_only_set_force_creation(force_creation);
- gpr_log(GPR_INFO, "Force subchannel creation: %d", force_creation);
- for (size_t i = 0; i < 1000; ++i) {
- std::shuffle(ports.begin(), ports.end(),
- std::mt19937(std::random_device()()));
- SetNextResolution(ports);
- if (i % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
- }
+ for (size_t i = 0; i < 1000; ++i) {
+ std::shuffle(ports.begin(), ports.end(),
+ std::mt19937(std::random_device()()));
+ SetNextResolution(ports);
+ // We should re-enter core at the end of the loop to give the resolution
+ // setting closure a chance to run.
+ if ((i + 1) % 10 == 0) CheckRpcSendOk(stub, DEBUG_LOCATION);
}
// Check LB policy name for the channel.
EXPECT_EQ("pick_first", channel->GetLoadBalancingPolicyName());
}
+INSTANTIATE_TEST_CASE_P(SubchannelForceCreation, ClientLbEnd2endWithParamTest,
+ ::testing::Bool());
+
TEST_F(ClientLbEnd2endTest, PickFirstReresolutionNoSelected) {
// Prepare the ports for up servers and down servers.
const int kNumServers = 3;
@@ -984,8 +1003,6 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc_test_init(argc, argv);
- grpc_init();
const auto result = RUN_ALL_TESTS();
- grpc_shutdown();
return result;
}
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 7bcf23c0eb..a4b1a85f85 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -57,6 +57,7 @@ DEFINE_string(
"half_duplex : half-duplex streaming;\n"
"jwt_token_creds: large_unary with JWT token auth;\n"
"large_unary : single request and (large) response;\n"
+ "long_lived_channel: sends large_unary rpcs over a long-lived channel;\n"
"oauth2_auth_token: raw oauth2 access token auth;\n"
"per_rpc_creds: raw oauth2 access token on a single rpc;\n"
"ping_pong : full-duplex streaming;\n"
@@ -84,10 +85,12 @@ DEFINE_bool(do_not_abort_on_transient_failures, false,
"whether abort() is called or not. It does not control whether the "
"test is retried in case of transient failures (and currently the "
"interop tests are not retried even if this flag is set to true)");
-
DEFINE_int32(soak_iterations, 1000,
"number of iterations to use for the two soak tests; rpc_soak and "
"channel_soak");
+DEFINE_int32(iteration_interval, 10,
+ "The interval in seconds between rpcs. This is used by "
+ "long_connection test");
using grpc::testing::CreateChannelForTestCase;
using grpc::testing::GetServiceAccountJsonKey;
@@ -163,6 +166,9 @@ int main(int argc, char** argv) {
FLAGS_soak_iterations);
actions["rpc_soak"] = std::bind(&grpc::testing::InteropClient::DoRpcSoakTest,
&client, FLAGS_soak_iterations);
+ actions["long_lived_channel"] =
+ std::bind(&grpc::testing::InteropClient::DoLongLivedChannelTest, &client,
+ FLAGS_soak_iterations, FLAGS_iteration_interval);
UpdateActions(&actions);
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index b7ce90803b..a99cf8122f 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -1052,6 +1052,34 @@ bool InteropClient::DoChannelSoakTest(int32_t soak_iterations) {
return true;
}
+bool InteropClient::DoLongLivedChannelTest(int32_t soak_iterations,
+ int32_t iteration_interval) {
+ gpr_log(GPR_DEBUG, "Sending %d RPCs...", soak_iterations);
+ GPR_ASSERT(soak_iterations > 0);
+ GPR_ASSERT(iteration_interval > 0);
+ SimpleRequest request;
+ SimpleResponse response;
+ int num_failures = 0;
+ for (int i = 0; i < soak_iterations; ++i) {
+ gpr_log(GPR_DEBUG, "Sending RPC number %d...", i);
+ if (!PerformLargeUnary(&request, &response)) {
+ gpr_log(GPR_ERROR, "Iteration %d failed.", i);
+ num_failures++;
+ }
+ gpr_sleep_until(
+ gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+ gpr_time_from_seconds(iteration_interval, GPR_TIMESPAN)));
+ }
+ if (num_failures == 0) {
+ gpr_log(GPR_DEBUG, "long_lived_channel test done.");
+ return true;
+ } else {
+ gpr_log(GPR_DEBUG, "long_lived_channel test failed with %d rpc failures.",
+ num_failures);
+ return false;
+ }
+}
+
bool InteropClient::DoUnimplementedService() {
gpr_log(GPR_DEBUG, "Sending a request for an unimplemented service...");
diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h
index e5be44d1d4..0ceff55c5c 100644
--- a/test/cpp/interop/interop_client.h
+++ b/test/cpp/interop/interop_client.h
@@ -76,6 +76,8 @@ class InteropClient {
// languages
bool DoChannelSoakTest(int32_t soak_iterations);
bool DoRpcSoakTest(int32_t soak_iterations);
+ bool DoLongLivedChannelTest(int32_t soak_iterations,
+ int32_t iteration_interval);
// Auth tests.
// username is a string containing the user email
diff --git a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
index 6fcf048bf3..ba4b57ad22 100644
--- a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
+++ b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc
@@ -27,6 +27,7 @@
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
+#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/static_metadata.h"
@@ -456,8 +457,9 @@ static void BM_HpackParserParseHeader(benchmark::State& state) {
std::vector<grpc_slice> benchmark_slices = Fixture::GetBenchmarkSlices();
grpc_chttp2_hpack_parser p;
grpc_chttp2_hpack_parser_init(&p);
+ const int kArenaSize = 4096 * 4096;
+ p.on_header_user_data = gpr_arena_create(kArenaSize);
p.on_header = OnHeader;
- p.on_header_user_data = nullptr;
for (auto slice : init_slices) {
GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
}
@@ -466,7 +468,14 @@ static void BM_HpackParserParseHeader(benchmark::State& state) {
GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice));
}
grpc_core::ExecCtx::Get()->Flush();
+ // Recreate arena every 4k iterations to avoid oom
+ if (0 == (state.iterations() & 0xfff)) {
+ gpr_arena_destroy((gpr_arena*)p.on_header_user_data);
+ p.on_header_user_data = gpr_arena_create(kArenaSize);
+ }
}
+ // Clean up
+ gpr_arena_destroy((gpr_arena*)p.on_header_user_data);
for (auto slice : init_slices) grpc_slice_unref(slice);
for (auto slice : benchmark_slices) grpc_slice_unref(slice);
grpc_chttp2_hpack_parser_destroy(&p);
@@ -766,8 +775,58 @@ class RepresentativeServerTrailingMetadata {
static void free_timeout(void* p) { gpr_free(p); }
-// New implementation.
-static void OnHeaderNew(void* user_data, grpc_mdelem md) {
+// Benchmark the current on_initial_header implementation
+static void OnInitialHeader(void* user_data, grpc_mdelem md) {
+ // Setup for benchmark. This will bloat the absolute values of this benchmark
+ grpc_chttp2_incoming_metadata_buffer buffer;
+ grpc_chttp2_incoming_metadata_buffer_init(&buffer, (gpr_arena*)user_data);
+ bool seen_error = false;
+
+ // Below here is the code we actually care about benchmarking
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) &&
+ !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+ seen_error = true;
+ }
+ if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
+ grpc_millis* cached_timeout =
+ static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
+ grpc_millis timeout;
+ if (cached_timeout != nullptr) {
+ timeout = *cached_timeout;
+ } else {
+ if (GPR_UNLIKELY(
+ !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
+ char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+ gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
+ gpr_free(val);
+ timeout = GRPC_MILLIS_INF_FUTURE;
+ }
+ if (GRPC_MDELEM_IS_INTERNED(md)) {
+ /* not already parsed: parse it now, and store the
+ * result away */
+ cached_timeout =
+ static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
+ *cached_timeout = timeout;
+ grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+ }
+ }
+ benchmark::DoNotOptimize(timeout);
+ GRPC_MDELEM_UNREF(md);
+ } else {
+ const size_t new_size = buffer.size + GRPC_MDELEM_LENGTH(md);
+ if (!seen_error) {
+ buffer.size = new_size;
+ }
+ grpc_error* error = grpc_chttp2_incoming_metadata_buffer_add(&buffer, md);
+ if (error != GRPC_ERROR_NONE) {
+ GPR_ASSERT(0);
+ }
+ }
+ grpc_chttp2_incoming_metadata_buffer_destroy(&buffer);
+}
+
+// Benchmark timeout handling
+static void OnHeaderTimeout(void* user_data, grpc_mdelem md) {
if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) {
grpc_millis* cached_timeout =
static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
@@ -853,8 +912,13 @@ BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerInitialMetadata, UnrefHeader);
BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
RepresentativeServerTrailingMetadata, UnrefHeader);
-
-BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderNew);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeClientInitialMetadata, OnInitialHeader);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ MoreRepresentativeClientInitialMetadata, OnInitialHeader);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader,
+ RepresentativeServerInitialMetadata, OnInitialHeader);
+BENCHMARK_TEMPLATE(BM_HpackParserParseHeader, SameDeadline, OnHeaderTimeout);
} // namespace hpack_parser_fixtures
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index 9d70277fbc..d390ae08f6 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -48,6 +48,7 @@ namespace testing {
class FixtureConfiguration {
public:
+ virtual ~FixtureConfiguration() {}
virtual void ApplyCommonChannelArguments(ChannelArguments* c) const {
c->SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, INT_MAX);
c->SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, INT_MAX);
diff --git a/test/cpp/microbenchmarks/helpers.cc b/test/cpp/microbenchmarks/helpers.cc
index e4ba37e2d6..bce72985dc 100644
--- a/test/cpp/microbenchmarks/helpers.cc
+++ b/test/cpp/microbenchmarks/helpers.cc
@@ -38,6 +38,7 @@ void TrackCounters::AddLabel(const grpc::string& label) {
}
void TrackCounters::AddToLabel(std::ostream& out, benchmark::State& state) {
+#ifdef GRPC_COLLECT_STATS
grpc_stats_data stats_end;
grpc_stats_collect(&stats_end);
grpc_stats_data stats;
@@ -53,6 +54,7 @@ void TrackCounters::AddToLabel(std::ostream& out, benchmark::State& state) {
<< " " << grpc_stats_histogram_name[i] << "-99p:"
<< grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 99.0);
}
+#endif
#ifdef GPR_LOW_LEVEL_COUNTERS
grpc_memory_counters counters_at_end = grpc_memory_counters_snapshot();
out << " locks/iter:"
diff --git a/test/cpp/microbenchmarks/helpers.h b/test/cpp/microbenchmarks/helpers.h
index 4aabd4094a..25d34b5f87 100644
--- a/test/cpp/microbenchmarks/helpers.h
+++ b/test/cpp/microbenchmarks/helpers.h
@@ -63,6 +63,7 @@ extern gpr_atm gpr_now_call_count;
class TrackCounters {
public:
TrackCounters() { grpc_stats_collect(&stats_begin_); }
+ virtual ~TrackCounters() {}
virtual void Finish(benchmark::State& state);
virtual void AddLabel(const grpc::string& label);
virtual void AddToLabel(std::ostream& out, benchmark::State& state);
diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc
index 04c300876c..fc6721d0ba 100644
--- a/test/cpp/naming/address_sorting_test.cc
+++ b/test/cpp/naming/address_sorting_test.cc
@@ -216,7 +216,7 @@ TEST_F(AddressSortingTest, TestDepriotizesUnreachableAddresses) {
{"1.2.3.4:443", AF_INET},
{"5.6.7.8:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"1.2.3.4:443",
"5.6.7.8:443",
@@ -235,7 +235,7 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) {
{"[2607:f8b0:400a:801::1002]:443", AF_INET6},
{"1.2.3.4:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"1.2.3.4:443",
"[2607:f8b0:400a:801::1002]:443",
@@ -255,7 +255,7 @@ TEST_F(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) {
{"[2607:f8b0:400a:801::1002]:443", AF_INET6},
{"1.2.3.4:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[2607:f8b0:400a:801::1002]:443",
"1.2.3.4:443",
@@ -279,7 +279,7 @@ TEST_F(AddressSortingTest, TestDepriotizesNonMatchingScope) {
{"[2000:f8b0:400a:801::1002]:443", AF_INET6},
{"[fec0::5000]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[fec0::5000]:443",
"[2000:f8b0:400a:801::1002]:443",
@@ -302,7 +302,7 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTable) {
{"[2002::5001]:443", AF_INET6},
{"[2001::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[2001::5001]:443",
"[2002::5001]:443",
@@ -325,7 +325,7 @@ TEST_F(AddressSortingTest, TestUsesLabelFromDefaultTableInputFlipped) {
{"[2001::5001]:443", AF_INET6},
{"[2002::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[2001::5001]:443",
"[2002::5001]:443",
@@ -348,7 +348,7 @@ TEST_F(AddressSortingTest,
{"[3ffe::5001]:443", AF_INET6},
{"1.2.3.4:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(
lb_addrs, {
// The AF_INET address should be IPv4-mapped by the sort,
@@ -381,7 +381,7 @@ TEST_F(AddressSortingTest,
{v4_compat_dest, AF_INET6},
{"[::1]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[::1]:443",
v4_compat_dest,
@@ -404,7 +404,7 @@ TEST_F(AddressSortingTest,
{"[1234::2]:443", AF_INET6},
{"[::1]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(
lb_addrs,
{
@@ -428,7 +428,7 @@ TEST_F(AddressSortingTest,
{"[2001::1234]:443", AF_INET6},
{"[2000::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(
lb_addrs, {
// The 2000::/16 address should match the ::/0 prefix rule
@@ -452,7 +452,7 @@ TEST_F(
{"[2001::1231]:443", AF_INET6},
{"[2000::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[2000::5001]:443",
"[2001::1231]:443",
@@ -473,7 +473,7 @@ TEST_F(AddressSortingTest,
{"[fec0::1234]:443", AF_INET6},
{"[fc00::5001]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[fc00::5001]:443",
"[fec0::1234]:443",
@@ -498,7 +498,7 @@ TEST_F(
{"[::ffff:1.1.1.2]:443", AF_INET6},
{"[1234::2]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
// ::ffff:0:2 should match the v4-mapped
// precedence entry and be deprioritized.
@@ -525,7 +525,7 @@ TEST_F(AddressSortingTest, TestPrefersSmallerScope) {
{"[3ffe::5001]:443", AF_INET6},
{"[fec0::1234]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[fec0::1234]:443",
"[3ffe::5001]:443",
@@ -550,7 +550,7 @@ TEST_F(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) {
{"[3ffe:5001::]:443", AF_INET6},
{"[3ffe:1234::]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe:1234::]:443",
"[3ffe:5001::]:443",
@@ -571,7 +571,7 @@ TEST_F(AddressSortingTest,
{"[3ffe::5001]:443", AF_INET6},
{"[3ffe::1234]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe::1234]:443",
"[3ffe::5001]:443",
@@ -591,7 +591,7 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) {
{"[3ffe:8000::]:443", AF_INET6},
{"[3ffe:2000::]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe:2000::]:443",
"[3ffe:8000::]:443",
@@ -611,7 +611,7 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) {
{"[3ffe:6::]:443", AF_INET6},
{"[3ffe:c::]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe:c::]:443",
"[3ffe:6::]:443",
@@ -633,7 +633,7 @@ TEST_F(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) {
{"[3ffe:1111:1111:1110::]:443", AF_INET6},
{"[3ffe:1111:1111:1111::]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe:1111:1111:1111::]:443",
"[3ffe:1111:1111:1110::]:443",
@@ -655,7 +655,7 @@ TEST_F(AddressSortingTest, TestStableSort) {
{"[3ffe::1234]:443", AF_INET6},
{"[3ffe::1235]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe::1234]:443",
"[3ffe::1235]:443",
@@ -681,7 +681,7 @@ TEST_F(AddressSortingTest, TestStableSortFiveElements) {
{"[3ffe::1234]:443", AF_INET6},
{"[3ffe::1235]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe::1231]:443",
"[3ffe::1232]:443",
@@ -702,7 +702,7 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExist) {
{"[3ffe::1234]:443", AF_INET6},
{"[3ffe::1235]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[3ffe::1231]:443",
"[3ffe::1232]:443",
@@ -720,7 +720,7 @@ TEST_F(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) {
{"[::ffff:5.6.7.8]:443", AF_INET6},
{"1.2.3.4:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[::ffff:5.6.7.8]:443",
"1.2.3.4:443",
@@ -748,7 +748,7 @@ TEST_F(AddressSortingTest, TestStableSortV4CompatAndSiteLocalAddresses) {
{"[fec0::2000]:443", AF_INET6},
{v4_compat_dest, AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs,
{
// The sort should be stable since
@@ -769,7 +769,7 @@ TEST_F(AddressSortingTest, TestPrefersIpv6Loopback) {
{"[::1]:443", AF_INET6},
{"127.0.0.1:443", AF_INET},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[::1]:443",
"127.0.0.1:443",
@@ -783,7 +783,7 @@ TEST_F(AddressSortingTest, TestPrefersIpv6LoopbackInputsFlipped) {
{"127.0.0.1:443", AF_INET},
{"[::1]:443", AF_INET6},
});
- grpc_cares_wrapper_test_only_address_sorting_sort(lb_addrs);
+ grpc_cares_wrapper_address_sorting_sort(lb_addrs);
VerifyLbAddrOutputs(lb_addrs, {
"[::1]:443",
"127.0.0.1:443",
diff --git a/test/cpp/util/cli_credentials.cc b/test/cpp/util/cli_credentials.cc
index 0a922617bb..1125b2d945 100644
--- a/test/cpp/util/cli_credentials.cc
+++ b/test/cpp/util/cli_credentials.cc
@@ -19,6 +19,11 @@
#include "test/cpp/util/cli_credentials.h"
#include <gflags/gflags.h>
+#include <grpc/slice.h>
+#include <grpc/support/log.h>
+#include <grpcpp/impl/codegen/slice.h>
+
+#include "src/core/lib/iomgr/load_file.h"
DEFINE_bool(
enable_ssl, false,
@@ -35,6 +40,14 @@ DEFINE_string(
"If not empty, treat the server host name as this for ssl/tls certificate "
"validation.");
DEFINE_string(
+ ssl_client_cert, "",
+ "If not empty, load this PEM formated client certificate file. Requires "
+ "use of --ssl_client_key.");
+DEFINE_string(
+ ssl_client_key, "",
+ "If not empty, load this PEM formated private key. Requires use of "
+ "--ssl_client_cert");
+DEFINE_string(
channel_creds_type, "",
"The channel creds type: insecure, ssl, gdc (Google Default Credentials) "
"or alts.");
@@ -99,7 +112,27 @@ CliCredentials::GetChannelCredentials() const {
if (FLAGS_channel_creds_type.compare("insecure") == 0) {
return grpc::InsecureChannelCredentials();
} else if (FLAGS_channel_creds_type.compare("ssl") == 0) {
- return grpc::SslCredentials(grpc::SslCredentialsOptions());
+ grpc::SslCredentialsOptions ssl_creds_options;
+ // TODO(@Capstan): This won't affect Google Default Credentials using SSL.
+ if (!FLAGS_ssl_client_cert.empty()) {
+ grpc_slice cert_slice = grpc_empty_slice();
+ GRPC_LOG_IF_ERROR(
+ "load_file",
+ grpc_load_file(FLAGS_ssl_client_cert.c_str(), 1, &cert_slice));
+ ssl_creds_options.pem_cert_chain =
+ grpc::StringFromCopiedSlice(cert_slice);
+ grpc_slice_unref(cert_slice);
+ }
+ if (!FLAGS_ssl_client_key.empty()) {
+ grpc_slice key_slice = grpc_empty_slice();
+ GRPC_LOG_IF_ERROR(
+ "load_file",
+ grpc_load_file(FLAGS_ssl_client_key.c_str(), 1, &key_slice));
+ ssl_creds_options.pem_private_key =
+ grpc::StringFromCopiedSlice(key_slice);
+ grpc_slice_unref(key_slice);
+ }
+ return grpc::SslCredentials(ssl_creds_options);
} else if (FLAGS_channel_creds_type.compare("gdc") == 0) {
return grpc::GoogleDefaultCredentials();
} else if (FLAGS_channel_creds_type.compare("alts") == 0) {
@@ -178,6 +211,8 @@ const grpc::string CliCredentials::GetCredentialUsage() const {
" overrides --use_auth\n"
" ; (deprecated)\n"
" --ssl_target ; Set server host for ssl validation\n"
+ " --ssl_client_cert ; Client cert for ssl\n"
+ " --ssl_client_key ; Client private key for ssl\n"
" --channel_creds_type ; Set to insecure, ssl, gdc, or alts\n"
" --call_creds ; Set to none, or"
" access_token=<token>\n";
diff --git a/test/distrib/csharp/run_distrib_test.sh b/test/distrib/csharp/run_distrib_test.sh
index f9371410e7..61924b91df 100755
--- a/test/distrib/csharp/run_distrib_test.sh
+++ b/test/distrib/csharp/run_distrib_test.sh
@@ -21,7 +21,8 @@ unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip
./update_version.sh auto
-nuget restore
+# Retry "nuget restore" to work around https://github.com/grpc/grpc/issues/16312
+nuget restore || nuget restore || nuget restore
xbuild DistribTest.sln
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index 25da3fdd5f..ab2e5a671a 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -23,10 +23,14 @@ import subprocess
import re
import perfection
-# configuration: a list of either strings or 2-tuples of strings
-# a single string represents a static grpc_mdstr
-# a 2-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will
-# also be created)
+# Configuration: a list of either strings or 2-tuples of strings or 3-tuples of
+# strings.
+# A single string represents a static grpc_mdstr.
+# A 2-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will
+# also be created).
+# A 3-tuple represents a static grpc_mdelem (and appropriate grpc_mdstrs will
+# also be created), with the last value equivalent to the mdelem's static hpack
+# table index as defined by RFC 7541
CONFIG = [
# metadata strings
@@ -72,105 +76,104 @@ CONFIG = [
('grpc-encoding', 'deflate'),
('te', 'trailers'),
('content-type', 'application/grpc'),
- (':method', 'POST'),
- (':status', '200'),
- (':status', '404'),
- (':scheme', 'http'),
- (':scheme', 'https'),
- (':scheme', 'grpc'),
- (':authority', ''),
- (':method', 'GET'),
+ (':method', 'POST', 3),
+ (':status', '200', 8),
+ (':status', '404', 13),
+ (':scheme', 'http', 6),
+ (':scheme', 'https', 7),
+ (':scheme', 'grpc', 0),
+ (':authority', '', 1),
+ (':method', 'GET', 2),
(':method', 'PUT'),
- (':path', '/'),
- (':path', '/index.html'),
- (':status', '204'),
- (':status', '206'),
- (':status', '304'),
- (':status', '400'),
- (':status', '500'),
- ('accept-charset', ''),
+ (':path', '/', 4),
+ (':path', '/index.html', 5),
+ (':status', '204', 9),
+ (':status', '206', 10),
+ (':status', '304', 11),
+ (':status', '400', 12),
+ (':status', '500', 14),
+ ('accept-charset', '', 15),
('accept-encoding', ''),
- ('accept-encoding', 'gzip, deflate'),
- ('accept-language', ''),
- ('accept-ranges', ''),
- ('accept', ''),
- ('access-control-allow-origin', ''),
- ('age', ''),
- ('allow', ''),
- ('authorization', ''),
- ('cache-control', ''),
- ('content-disposition', ''),
+ ('accept-encoding', 'gzip, deflate', 16),
+ ('accept-language', '', 17),
+ ('accept-ranges', '', 18),
+ ('accept', '', 19),
+ ('access-control-allow-origin', '', 20),
+ ('age', '', 21),
+ ('allow', '', 22),
+ ('authorization', '', 23),
+ ('cache-control', '', 24),
+ ('content-disposition', '', 25),
('content-encoding', 'identity'),
('content-encoding', 'gzip'),
- ('content-encoding', ''),
- ('content-language', ''),
- ('content-length', ''),
- ('content-location', ''),
- ('content-range', ''),
- ('content-type', ''),
- ('cookie', ''),
- ('date', ''),
- ('etag', ''),
- ('expect', ''),
- ('expires', ''),
- ('from', ''),
- ('host', ''),
- ('if-match', ''),
- ('if-modified-since', ''),
- ('if-none-match', ''),
- ('if-range', ''),
- ('if-unmodified-since', ''),
- ('last-modified', ''),
+ ('content-encoding', '', 26),
+ ('content-language', '', 27),
+ ('content-length', '', 28),
+ ('content-location', '', 29),
+ ('content-range', '', 30),
+ ('content-type', '', 31),
+ ('cookie', '', 32),
+ ('date', '', 33),
+ ('etag', '', 34),
+ ('expect', '', 35),
+ ('expires', '', 36),
+ ('from', '', 37),
+ ('host', '', 38),
+ ('if-match', '', 39),
+ ('if-modified-since', '', 40),
+ ('if-none-match', '', 41),
+ ('if-range', '', 42),
+ ('if-unmodified-since', '', 43),
+ ('last-modified', '', 44),
('lb-token', ''),
('lb-cost-bin', ''),
- ('link', ''),
- ('location', ''),
- ('max-forwards', ''),
- ('proxy-authenticate', ''),
- ('proxy-authorization', ''),
- ('range', ''),
- ('referer', ''),
- ('refresh', ''),
- ('retry-after', ''),
- ('server', ''),
- ('set-cookie', ''),
- ('strict-transport-security', ''),
- ('transfer-encoding', ''),
- ('user-agent', ''),
- ('vary', ''),
- ('via', ''),
- ('www-authenticate', ''),
+ ('link', '', 45),
+ ('location', '', 46),
+ ('max-forwards', '', 47),
+ ('proxy-authenticate', '', 48),
+ ('proxy-authorization', '', 49),
+ ('range', '', 50),
+ ('referer', '', 51),
+ ('refresh', '', 52),
+ ('retry-after', '', 53),
+ ('server', '', 54),
+ ('set-cookie', '', 55),
+ ('strict-transport-security', '', 56),
+ ('transfer-encoding', '', 57),
+ ('user-agent', '', 58),
+ ('vary', '', 59),
+ ('via', '', 60),
+ ('www-authenticate', '', 61),
]
-# Entries marked with is_default=True are ignored when counting
-# non-default initial metadata that prevents the chttp2 server from
-# sending a Trailers-Only response.
+# All entries here are ignored when counting non-default initial metadata that
+# prevents the chttp2 server from sending a Trailers-Only response.
METADATA_BATCH_CALLOUTS = [
- # (name, is_default)
- (':path', True),
- (':method', True),
- (':status', True),
- (':authority', True),
- (':scheme', True),
- ('te', True),
- ('grpc-message', True),
- ('grpc-status', True),
- ('grpc-payload-bin', True),
- ('grpc-encoding', True),
- ('grpc-accept-encoding', True),
- ('grpc-server-stats-bin', True),
- ('grpc-tags-bin', True),
- ('grpc-trace-bin', True),
- ('content-type', True),
- ('content-encoding', True),
- ('accept-encoding', True),
- ('grpc-internal-encoding-request', True),
- ('grpc-internal-stream-encoding-request', True),
- ('user-agent', True),
- ('host', True),
- ('lb-token', True),
- ('grpc-previous-rpc-attempts', True),
- ('grpc-retry-pushback-ms', True),
+ # (name)
+ (':path'),
+ (':method'),
+ (':status'),
+ (':authority'),
+ (':scheme'),
+ ('te'),
+ ('grpc-message'),
+ ('grpc-status'),
+ ('grpc-payload-bin'),
+ ('grpc-encoding'),
+ ('grpc-accept-encoding'),
+ ('grpc-server-stats-bin'),
+ ('grpc-tags-bin'),
+ ('grpc-trace-bin'),
+ ('content-type'),
+ ('content-encoding'),
+ ('accept-encoding'),
+ ('grpc-internal-encoding-request'),
+ ('grpc-internal-stream-encoding-request'),
+ ('user-agent'),
+ ('host'),
+ ('lb-token'),
+ ('grpc-previous-rpc-attempts'),
+ ('grpc-retry-pushback-ms'),
]
COMPRESSION_ALGORITHMS = [
@@ -252,7 +255,7 @@ all_elems = list()
static_userdata = {}
# put metadata batch callouts first, to make the check of if a static metadata
# string is a callout trivial
-for elem, _ in METADATA_BATCH_CALLOUTS:
+for elem in METADATA_BATCH_CALLOUTS:
if elem not in all_strs:
all_strs.append(elem)
for elem in CONFIG:
@@ -323,6 +326,17 @@ else:
os.path.dirname(sys.argv[0]),
'../../../test/core/end2end/fuzzers/hpack.dictionary'), 'w')
+HPACK_H = open(
+ os.path.join(
+ os.path.dirname(sys.argv[0]),
+ '../../../src/core/ext/transport/chttp2/transport/hpack_mapping.h'),
+ 'w')
+HPACK_C = open(
+ os.path.join(
+ os.path.dirname(sys.argv[0]),
+ '../../../src/core/ext/transport/chttp2/transport/hpack_mapping.cc'),
+ 'w')
+
# copy-paste copyright notice from this file
with open(sys.argv[0]) as my_source:
copyright = []
@@ -337,7 +351,8 @@ with open(sys.argv[0]) as my_source:
if line[0] != '#':
break
copyright.append(line)
- put_banner([H, C], [line[2:].rstrip() for line in copyright])
+ put_banner([H, C, HPACK_H, HPACK_C],
+ [line[2:].rstrip() for line in copyright])
hex_bytes = [ord(c) for c in 'abcdefABCDEF0123456789']
@@ -364,16 +379,44 @@ See metadata.h for an explanation of the interface here, and metadata.cc for
an explanation of what's going on.
""".splitlines())
+put_banner([HPACK_H, HPACK_C], """WARNING: Auto-generated code.
+
+To make changes to this file, change
+tools/codegen/core/gen_static_metadata.py, and then re-run it.
+
+This file contains the mapping from the index of each metadata element in the
+grpc static metadata table to the index of that element in the hpack static
+metadata table. If the element is not contained in the static hpack table, then
+the returned index is 0.
+""".splitlines())
+
print >> H, '#ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
print >> H, '#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H'
print >> H
+print >> H, '#include <grpc/support/port_platform.h>'
+print >> H
print >> H, '#include "src/core/lib/transport/metadata.h"'
print >> H
-
+print >> C, '#include <grpc/support/port_platform.h>'
+print >> C
print >> C, '#include "src/core/lib/transport/static_metadata.h"'
print >> C
print >> C, '#include "src/core/lib/slice/slice_internal.h"'
print >> C
+print >> HPACK_H, ('#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_'
+ 'MAPPING_H')
+print >> HPACK_H, ('#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_'
+ 'MAPPING_H')
+print >> HPACK_H
+print >> HPACK_H, '#include <grpc/support/port_platform.h>'
+print >> HPACK_H
+print >> HPACK_H, '#include "src/core/lib/transport/static_metadata.h"'
+print >> HPACK_H
+print >> HPACK_C, '#include <grpc/support/port_platform.h>'
+print >> HPACK_C
+print >> HPACK_C, ('#include '
+ '"src/core/ext/transport/chttp2/transport/hpack_mapping.h"')
+print >> HPACK_C
str_ofs = 0
id2strofs = {}
@@ -388,7 +431,7 @@ def slice_def(i):
# validate configuration
-for elem, _ in METADATA_BATCH_CALLOUTS:
+for elem in METADATA_BATCH_CALLOUTS:
assert elem in all_strs
print >> H, '#define GRPC_STATIC_MDSTR_COUNT %d' % len(all_strs)
@@ -450,10 +493,28 @@ print >> H, ('extern grpc_mdelem_data '
print >> H, ('extern uintptr_t '
'grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];')
for i, elem in enumerate(all_elems):
- print >> H, '/* "%s": "%s" */' % elem
+ print >> H, '/* "%s": "%s" */' % (elem[0], elem[1])
print >> H, ('#define %s (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[%d], '
'GRPC_MDELEM_STORAGE_STATIC))') % (mangle(elem).upper(), i)
print >> H
+
+# Print out the chttp2 mapping between static mdelem index and the hpack static
+# table index
+print >> HPACK_H, ('extern const uint8_t grpc_hpack_static_mdelem_indices['
+ 'GRPC_STATIC_MDELEM_COUNT];')
+print >> HPACK_H
+print >> HPACK_C, ('const uint8_t grpc_hpack_static_mdelem_indices['
+ 'GRPC_STATIC_MDELEM_COUNT] = {')
+indices = ''
+for elem in all_elems:
+ index = 0
+ if len(elem) == 3:
+ index = elem[2]
+ indices += '%d,' % index
+print >> HPACK_C, ' %s' % indices
+print >> HPACK_C, '};'
+print >> HPACK_C
+
print >> C, ('uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] '
'= {')
print >> C, ' %s' % ','.join(
@@ -546,12 +607,13 @@ print >> C, '}'
print >> C
print >> C, 'grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {'
-for a, b in all_elems:
- print >> C, '{%s,%s},' % (slice_def(str_idx(a)), slice_def(str_idx(b)))
+for elem in all_elems:
+ print >> C, '{%s,%s},' % (slice_def(str_idx(elem[0])),
+ slice_def(str_idx(elem[1])))
print >> C, '};'
print >> H, 'typedef enum {'
-for elem, _ in METADATA_BATCH_CALLOUTS:
+for elem in METADATA_BATCH_CALLOUTS:
print >> H, ' %s,' % mangle(elem, 'batch').upper()
print >> H, ' GRPC_BATCH_CALLOUTS_COUNT'
print >> H, '} grpc_metadata_batch_callouts_index;'
@@ -559,7 +621,7 @@ print >> H
print >> H, 'typedef union {'
print >> H, ' struct grpc_linked_mdelem *array[GRPC_BATCH_CALLOUTS_COUNT];'
print >> H, ' struct {'
-for elem, _ in METADATA_BATCH_CALLOUTS:
+for elem in METADATA_BATCH_CALLOUTS:
print >> H, ' struct grpc_linked_mdelem *%s;' % mangle(elem, '').lower()
print >> H, ' } named;'
print >> H, '} grpc_metadata_batch_callouts;'
@@ -567,14 +629,6 @@ print >> H
print >> H, '#define GRPC_BATCH_INDEX_OF(slice) \\'
print >> H, ' (GRPC_IS_STATIC_METADATA_STRING((slice)) ? (grpc_metadata_batch_callouts_index)GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, GRPC_BATCH_CALLOUTS_COUNT) : GRPC_BATCH_CALLOUTS_COUNT)'
print >> H
-print >> H, ('extern bool grpc_static_callout_is_default['
- 'GRPC_BATCH_CALLOUTS_COUNT];')
-print >> H
-print >> C, 'bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {'
-for elem, is_default in METADATA_BATCH_CALLOUTS:
- print >> C, ' %s, // %s' % (str(is_default).lower(), elem)
-print >> C, '};'
-print >> C
print >> H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % (
1 << len(COMPRESSION_ALGORITHMS))
@@ -599,5 +653,8 @@ print >> H, '#define GRPC_MDELEM_ACCEPT_STREAM_ENCODING_FOR_ALGORITHMS(algs) (GR
print >> H, '#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */'
+print >> HPACK_H, ('#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_'
+ 'MAPPING_H */')
+
H.close()
C.close()
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 9a97ee84f2..3b7fd1fa8e 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -945,7 +945,9 @@ include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@@ -997,6 +999,7 @@ include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+include/grpcpp/support/client_callback.h \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 0cd4cfd647..c1bcdfd3d0 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -946,7 +946,9 @@ include/grpcpp/impl/codegen/async_unary_call.h \
include/grpcpp/impl/codegen/byte_buffer.h \
include/grpcpp/impl/codegen/call.h \
include/grpcpp/impl/codegen/call_hook.h \
+include/grpcpp/impl/codegen/callback_common.h \
include/grpcpp/impl/codegen/channel_interface.h \
+include/grpcpp/impl/codegen/client_callback.h \
include/grpcpp/impl/codegen/client_context.h \
include/grpcpp/impl/codegen/client_unary_call.h \
include/grpcpp/impl/codegen/completion_queue.h \
@@ -999,6 +1001,7 @@ include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
+include/grpcpp/support/client_callback.h \
include/grpcpp/support/config.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
@@ -1077,7 +1080,6 @@ src/core/lib/iomgr/error.h \
src/core/lib/iomgr/error_internal.h \
src/core/lib/iomgr/ev_epoll1_linux.h \
src/core/lib/iomgr/ev_epollex_linux.h \
-src/core/lib/iomgr/ev_epollsig_linux.h \
src/core/lib/iomgr/ev_poll_posix.h \
src/core/lib/iomgr/ev_posix.h \
src/core/lib/iomgr/exec_ctx.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 7cd1dc7bf3..9186056733 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1013,6 +1013,8 @@ src/core/ext/transport/chttp2/transport/frame_window_update.cc \
src/core/ext/transport/chttp2/transport/frame_window_update.h \
src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
src/core/ext/transport/chttp2/transport/hpack_encoder.h \
+src/core/ext/transport/chttp2/transport/hpack_mapping.cc \
+src/core/ext/transport/chttp2/transport/hpack_mapping.h \
src/core/ext/transport/chttp2/transport/hpack_parser.cc \
src/core/ext/transport/chttp2/transport/hpack_parser.h \
src/core/ext/transport/chttp2/transport/hpack_table.cc \
@@ -1179,8 +1181,6 @@ src/core/lib/iomgr/ev_epoll1_linux.cc \
src/core/lib/iomgr/ev_epoll1_linux.h \
src/core/lib/iomgr/ev_epollex_linux.cc \
src/core/lib/iomgr/ev_epollex_linux.h \
-src/core/lib/iomgr/ev_epollsig_linux.cc \
-src/core/lib/iomgr/ev_epollsig_linux.h \
src/core/lib/iomgr/ev_poll_posix.cc \
src/core/lib/iomgr/ev_poll_posix.h \
src/core/lib/iomgr/ev_posix.cc \
diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py
index c55789f27e..15b53d1716 100644
--- a/tools/interop_matrix/client_matrix.py
+++ b/tools/interop_matrix/client_matrix.py
@@ -99,6 +99,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
],
'go': [
{
@@ -231,6 +234,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
],
'node': [
{
@@ -319,6 +325,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
],
'php': [
{
@@ -363,6 +372,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
],
'csharp': [
{
@@ -412,6 +424,9 @@ LANG_RELEASE_MATRIX = {
{
'v1.14.1': None
},
+ {
+ 'v1.15.0': None
+ },
],
}
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 8ea5126fde..29b72dca43 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -493,23 +493,6 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "ev_epollsig_linux_test",
- "src": [
- "test/core/iomgr/ev_epollsig_linux_test.cc"
- ],
- "third_party": false,
- "type": "target"
- },
- {
- "deps": [
- "gpr",
- "gpr_test_util",
- "grpc",
- "grpc_test_util"
- ],
- "headers": [],
- "is_filegroup": false,
- "language": "c",
"name": "fake_resolver_test",
"src": [
"test/core/client_channel/resolvers/fake_resolver_test.cc"
@@ -1863,9 +1846,9 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "pollset_set_test",
+ "name": "resolve_address_posix_test",
"src": [
- "test/core/iomgr/pollset_set_test.cc"
+ "test/core/iomgr/resolve_address_posix_test.cc"
],
"third_party": false,
"type": "target"
@@ -1880,9 +1863,9 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "resolve_address_posix_test",
+ "name": "resolve_address_using_ares_resolver_test",
"src": [
- "test/core/iomgr/resolve_address_posix_test.cc"
+ "test/core/iomgr/resolve_address_test.cc"
],
"third_party": false,
"type": "target"
@@ -1897,7 +1880,7 @@
"headers": [],
"is_filegroup": false,
"language": "c",
- "name": "resolve_address_test",
+ "name": "resolve_address_using_native_resolver_test",
"src": [
"test/core/iomgr/resolve_address_test.cc"
],
@@ -3331,6 +3314,25 @@
"grpc++_test_util",
"grpc_test_util"
],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c++",
+ "name": "client_callback_end2end_test",
+ "src": [
+ "test/cpp/end2end/client_callback_end2end_test.cc"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc++",
+ "grpc++_test_util",
+ "grpc_test_util"
+ ],
"headers": [
"src/proto/grpc/lb/v1/load_balancer.grpc.pb.h",
"src/proto/grpc/lb/v1/load_balancer.pb.h",
@@ -9515,7 +9517,6 @@
"src/core/lib/iomgr/error.cc",
"src/core/lib/iomgr/ev_epoll1_linux.cc",
"src/core/lib/iomgr/ev_epollex_linux.cc",
- "src/core/lib/iomgr/ev_epollsig_linux.cc",
"src/core/lib/iomgr/ev_poll_posix.cc",
"src/core/lib/iomgr/ev_posix.cc",
"src/core/lib/iomgr/ev_windows.cc",
@@ -9696,7 +9697,6 @@
"src/core/lib/iomgr/error_internal.h",
"src/core/lib/iomgr/ev_epoll1_linux.h",
"src/core/lib/iomgr/ev_epollex_linux.h",
- "src/core/lib/iomgr/ev_epollsig_linux.h",
"src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h",
"src/core/lib/iomgr/exec_ctx.h",
@@ -9848,7 +9848,6 @@
"src/core/lib/iomgr/error_internal.h",
"src/core/lib/iomgr/ev_epoll1_linux.h",
"src/core/lib/iomgr/ev_epollex_linux.h",
- "src/core/lib/iomgr/ev_epollsig_linux.h",
"src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h",
"src/core/lib/iomgr/exec_ctx.h",
@@ -10661,6 +10660,7 @@
"src/core/ext/transport/chttp2/transport/frame_settings.h",
"src/core/ext/transport/chttp2/transport/frame_window_update.h",
"src/core/ext/transport/chttp2/transport/hpack_encoder.h",
+ "src/core/ext/transport/chttp2/transport/hpack_mapping.h",
"src/core/ext/transport/chttp2/transport/hpack_parser.h",
"src/core/ext/transport/chttp2/transport/hpack_table.h",
"src/core/ext/transport/chttp2/transport/http2_settings.h",
@@ -10698,6 +10698,8 @@
"src/core/ext/transport/chttp2/transport/frame_window_update.h",
"src/core/ext/transport/chttp2/transport/hpack_encoder.cc",
"src/core/ext/transport/chttp2/transport/hpack_encoder.h",
+ "src/core/ext/transport/chttp2/transport/hpack_mapping.cc",
+ "src/core/ext/transport/chttp2/transport/hpack_mapping.h",
"src/core/ext/transport/chttp2/transport/hpack_parser.cc",
"src/core/ext/transport/chttp2/transport/hpack_parser.h",
"src/core/ext/transport/chttp2/transport/hpack_table.cc",
@@ -11081,7 +11083,9 @@
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
+ "include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
+ "include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_context.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
@@ -11147,7 +11151,9 @@
"include/grpcpp/impl/codegen/byte_buffer.h",
"include/grpcpp/impl/codegen/call.h",
"include/grpcpp/impl/codegen/call_hook.h",
+ "include/grpcpp/impl/codegen/callback_common.h",
"include/grpcpp/impl/codegen/channel_interface.h",
+ "include/grpcpp/impl/codegen/client_callback.h",
"include/grpcpp/impl/codegen/client_context.h",
"include/grpcpp/impl/codegen/client_unary_call.h",
"include/grpcpp/impl/codegen/completion_queue.h",
@@ -11305,6 +11311,7 @@
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
+ "include/grpcpp/support/client_callback.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
@@ -11409,6 +11416,7 @@
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
+ "include/grpcpp/support/client_callback.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index fba76d69d1..4fdd26efa4 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -605,26 +605,6 @@
"args": [],
"benchmark": false,
"ci_platforms": [
- "linux"
- ],
- "cpu_cost": 3,
- "exclude_configs": [],
- "exclude_iomgrs": [
- "uv"
- ],
- "flaky": false,
- "gtest": false,
- "language": "c",
- "name": "ev_epollsig_linux_test",
- "platforms": [
- "linux"
- ],
- "uses_polling": true
- },
- {
- "args": [],
- "benchmark": false,
- "ci_platforms": [
"linux",
"mac",
"posix",
@@ -2105,7 +2085,9 @@
"args": [],
"benchmark": false,
"ci_platforms": [
- "linux"
+ "linux",
+ "mac",
+ "posix"
],
"cpu_cost": 1.0,
"exclude_configs": [],
@@ -2115,38 +2097,44 @@
"flaky": false,
"gtest": false,
"language": "c",
- "name": "pollset_set_test",
+ "name": "resolve_address_posix_test",
"platforms": [
- "linux"
+ "linux",
+ "mac",
+ "posix"
],
"uses_polling": true
},
{
- "args": [],
+ "args": [
+ "--resolver=ares"
+ ],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
- "posix"
+ "posix",
+ "windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
- "exclude_iomgrs": [
- "uv"
- ],
+ "exclude_iomgrs": [],
"flaky": false,
"gtest": false,
"language": "c",
- "name": "resolve_address_posix_test",
+ "name": "resolve_address_using_ares_resolver_test",
"platforms": [
"linux",
"mac",
- "posix"
+ "posix",
+ "windows"
],
"uses_polling": true
},
{
- "args": [],
+ "args": [
+ "--resolver=native"
+ ],
"benchmark": false,
"ci_platforms": [
"linux",
@@ -2160,7 +2148,7 @@
"flaky": false,
"gtest": false,
"language": "c",
- "name": "resolve_address_test",
+ "name": "resolve_address_using_native_resolver_test",
"platforms": [
"linux",
"mac",
@@ -3978,6 +3966,30 @@
"posix",
"windows"
],
+ "cpu_cost": 0.5,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "client_callback_end2end_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
diff --git a/tools/run_tests/python_utils/upload_rbe_results.py b/tools/run_tests/python_utils/upload_rbe_results.py
index d29ebc6219..74f329048f 100644
--- a/tools/run_tests/python_utils/upload_rbe_results.py
+++ b/tools/run_tests/python_utils/upload_rbe_results.py
@@ -40,13 +40,14 @@ _RESULTS_SCHEMA = [
('test_case', 'STRING', 'Name of test case'),
('result', 'STRING', 'Test or build result'),
('timestamp', 'TIMESTAMP', 'Timestamp of test run'),
+ ('duration', 'FLOAT', 'Duration of the test run'),
]
_TABLE_ID = 'rbe_test_results'
def _get_api_key():
"""Returns string with API key to access ResultStore.
- Intended to be used in Kokoro envrionment."""
+ Intended to be used in Kokoro environment."""
api_key_directory = os.getenv('KOKORO_GFILE_DIR')
api_key_file = os.path.join(api_key_directory, 'resultstore_api_key')
assert os.path.isfile(api_key_file), 'Must add --api_key arg if not on ' \
@@ -57,7 +58,7 @@ def _get_api_key():
def _get_invocation_id():
"""Returns String of Bazel invocation ID. Intended to be used in
- Kokoro envirionment."""
+ Kokoro environment."""
bazel_id_directory = os.getenv('KOKORO_ARTIFACTS_DIR')
bazel_id_file = os.path.join(bazel_id_directory, 'bazel_invocation_ids')
assert os.path.isfile(bazel_id_file), 'bazel_invocation_ids file, written ' \
@@ -66,6 +67,16 @@ def _get_invocation_id():
return f.read().replace('\n', '')
+def _parse_test_duration(duration_str):
+ """Parse test duration string in '123.567s' format"""
+ try:
+ if duration_str.endswith('s'):
+ duration_str = duration_str[:-1]
+ return float(duration_str)
+ except:
+ return None
+
+
def _upload_results_to_bq(rows):
"""Upload test results to a BQ table.
@@ -205,6 +216,8 @@ if __name__ == "__main__":
result,
'timestamp':
action['timing']['startTime'],
+ 'duration':
+ _parse_test_duration(action['timing']['duration']),
}
})
except Exception as e:
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index ecb5e1d899..3d73f9ec0e 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -61,7 +61,7 @@ _FORCE_ENVIRON_FOR_WRAPPERS = {
}
_POLLING_STRATEGIES = {
- 'linux': ['epollex', 'epollsig', 'epoll1', 'poll', 'poll-cv'],
+ 'linux': ['epollex', 'epoll1', 'poll', 'poll-cv'],
'mac': ['poll'],
}
@@ -1430,7 +1430,7 @@ argp.add_argument(
default=None,
type=str,
help='Only use the specified comma-delimited list of polling engines. '
- 'Example: --force_use_pollers epollsig,poll '
+ 'Example: --force_use_pollers epoll1,poll '
' (This flag has no effect if --force_default_poller flag is also used)')
argp.add_argument(
'--max_time', default=-1, type=int, help='Maximum test runtime in seconds')
diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py
index 0af9e0cbbe..1bbec94ee1 100755
--- a/tools/run_tests/run_tests_matrix.py
+++ b/tools/run_tests/run_tests_matrix.py
@@ -53,12 +53,7 @@ def _safe_report_name(name):
def _report_filename(name):
- """Generates report file name"""
- return 'report_%s_%s' % (_safe_report_name(name), _REPORT_SUFFIX)
-
-
-def _report_filename_internal_ci(name):
- """Generates report file name that leads to better presentation by internal CI"""
+ """Generates report file name with directory structure that leads to better presentation by internal CI"""
return '%s/%s' % (_safe_report_name(name), _REPORT_SUFFIX)
@@ -507,8 +502,9 @@ if __name__ == "__main__":
default=False,
action='store_const',
const=True,
- help='Put reports into subdirectories to improve presentation of '
- 'results by Internal CI.')
+ help=
+ '(Deprecated, has no effect) Put reports into subdirectories to improve presentation of '
+ 'results by Kokoro.')
argp.add_argument(
'--bq_result_table',
default='',
@@ -517,9 +513,6 @@ if __name__ == "__main__":
help='Upload test results to a specified BQ table.')
args = argp.parse_args()
- if args.internal_ci:
- _report_filename = _report_filename_internal_ci # override the function
-
extra_args = []
if args.build_only:
extra_args.append('--build_only')