[promises] Server call (#31448)

* add experiment

* allow instantiation

* scratchings

* scratchings

* sniffly

* Automated change: Fix sanity tests

* fix

* fix

* fix

* Automated change: Fix sanity tests

* progress

* change pipe labels to enable server code to be written

* better api

* Automated change: Fix sanity tests

* progress

* [promises] Implementation of deadline for server-based-calls

* compression filter compiles again

* Automated change: Fix sanity tests

* fix

* server tracing fixes

* get client initial metadata

* progress

* progress

* server call surface progress

* Automated change: Fix sanity tests

* move payload

* server-progress

* recv-message-server-connchan

* logging

* fix context-gate

* recv fix@top

* Automated change: Fix sanity tests

* recv close on server

* top termination start

* [promises] Move Empty to be first class

* fixes

* fix

* flow control fix

* got to orphan!

* orphan

* call orphan

* spam cleanup

* fix

* new cancelation semantics

* progress

* large metadata fixes

* fix

* fix

* log

* better logs

* fix-chanz

* logging, necessaryness

* fix typo

* fixes

* fix

* fix

* fix-pipe

* cleanup logging

* fix

* build-fix

* fix

* Automated change: Fix sanity tests

* logging

* Automated change: Fix sanity tests

* Automated change: Fix sanity tests

* better primitive

* Revert "better primitive"

This reverts commit 119b5ee244.

* fix

* fix

* trrracing

* Automated change: Fix sanity tests

* get-trailing-metadata

* cancellation

* Automated change: Fix sanity tests

* add transform pipeline to pipe

* add transform pipeline to pipe

* interceptor lists

* new server initial md api into filters

* convert connected_channel

* convert call

* initial promise based filter conversion

* convert promise based filter

* build fixes

* compile fix

* fixes

* fix ordering

* fixes

* check-metadata

* revert later: debug code

* better debug

* fix metadata ordering with messages in promise based filter

* fix ordering problem between batch completion and promise completion

* properly handle failure on receive message path on client

* more debug, fix a repoll bug in pbf

* Automated change: Fix sanity tests

* fixes

* Automated change: Fix sanity tests

* cleanup logging

* fixes

* missing file

* fixes

* logging

* Automated change: Fix sanity tests

* fixes

* convert logging filter

* fix

* Automated change: Fix sanity tests

* fix bad server response test

* Revert "Disable logging test (#32049)"

This reverts commit 5fc92eaeae.

* fix

* Automated change: Fix sanity tests

* fix memory leaks, logging

* Automated change: Fix sanity tests

* slice refcount debugging

* asan-canaries

* leak-fix

* leak-fix

* Automated change: Fix sanity tests

* fix

* fix

* fix

* fix

* fix

* Automated change: Fix sanity tests

* fix

* remove mistaken line

* add-comment

* fix refcounting bug

* Automated change: Fix sanity tests

* rename variable

* renames

* bleh

* carry pipe close status from bottom of pipe to top to appease
recv-close-on-server

* backport cancellation

* Revert "carry pipe close status from bottom of pipe to top to appease"

This reverts commit fa33301dcd.

* fix

* Automated change: Fix sanity tests

* review-feedback

* comment-ordering

* monostate

* renames

* undo-review-feedback

* fix

* review-feedback

* review-feedback

* fix

* review-feedback

* drop debugloc constructor

* interceptor-list-rev-feedback

* interceptor-list-rev-feedback

* pipe test

* review-feedback

* undo-mistaken-change

* Automated change: Fix sanity tests

* pipe error state

* detect send/recv failures and report

* iwyu, build

* fix submodules

* fix

* warning

* cleanup

* Automated change: Fix sanity tests

* fix

* fix for windows

* fix

* null pointer fix

* iwyu

* gen projex

---------

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/32094/head^2
Craig Tiller 2 years ago committed by GitHub
parent 03ea0bb28d
commit bbeb15006a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      BUILD
  2. 148
      CMakeLists.txt
  3. 8
      Makefile
  4. 1
      bazel/experiments.bzl
  5. 259
      build_autogenerated.yaml
  6. 4
      config.m4
  7. 4
      config.w32
  8. 1
      doc/environment_variables.md
  9. 16
      gRPC-C++.podspec
  10. 20
      gRPC-Core.podspec
  11. 12
      grpc.gemspec
  12. 12
      grpc.gyp
  13. 12
      package.xml
  14. 95
      src/core/BUILD
  15. 21
      src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc
  16. 46
      src/core/ext/filters/http/client/http_client_filter.cc
  17. 223
      src/core/ext/filters/http/message_compress/compression_filter.cc
  18. 21
      src/core/ext/filters/http/message_compress/compression_filter.h
  19. 49
      src/core/ext/filters/http/server/http_server_filter.cc
  20. 51
      src/core/ext/filters/stateful_session/stateful_session_filter.cc
  21. 32
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  22. 14
      src/core/ext/transport/chttp2/transport/internal.h
  23. 135
      src/core/ext/transport/chttp2/transport/parsing.cc
  24. 15
      src/core/lib/channel/channel_stack_builder_impl.cc
  25. 1212
      src/core/lib/channel/connected_channel.cc
  26. 687
      src/core/lib/channel/promise_based_filter.cc
  27. 139
      src/core/lib/channel/promise_based_filter.h
  28. 2
      src/core/lib/event_engine/slice.cc
  29. 4
      src/core/lib/experiments/experiments.cc
  30. 9
      src/core/lib/experiments/experiments.h
  31. 8
      src/core/lib/experiments/experiments.yaml
  32. 3
      src/core/lib/gprpp/debug_location.h
  33. 8
      src/core/lib/iomgr/call_combiner.cc
  34. 27
      src/core/lib/iomgr/closure.cc
  35. 2
      src/core/lib/iomgr/closure.h
  36. 4
      src/core/lib/promise/activity.h
  37. 22
      src/core/lib/promise/for_each.h
  38. 61
      src/core/lib/promise/if.h
  39. 309
      src/core/lib/promise/interceptor_list.h
  40. 6
      src/core/lib/promise/intra_activity_waiter.h
  41. 30
      src/core/lib/promise/latch.h
  42. 32
      src/core/lib/promise/map_pipe.h
  43. 482
      src/core/lib/promise/pipe.h
  44. 5
      src/core/lib/promise/trace.cc
  45. 24
      src/core/lib/promise/trace.h
  46. 28
      src/core/lib/promise/try_concurrently.h
  47. 90
      src/core/lib/resource_quota/arena.h
  48. 6
      src/core/lib/slice/slice.cc
  49. 15
      src/core/lib/slice/slice.h
  50. 8
      src/core/lib/slice/slice_buffer.h
  51. 20
      src/core/lib/slice/slice_refcount.cc
  52. 26
      src/core/lib/slice/slice_refcount.h
  53. 1059
      src/core/lib/surface/call.cc
  54. 28
      src/core/lib/surface/call.h
  55. 28
      src/core/lib/surface/call_trace.cc
  56. 4
      src/core/lib/surface/lame_client.cc
  57. 299
      src/core/lib/surface/server.cc
  58. 3
      src/core/lib/surface/server.h
  59. 7
      src/core/lib/transport/transport.cc
  60. 18
      src/core/lib/transport/transport.h
  61. 11
      src/cpp/ext/filters/logging/BUILD
  62. 142
      src/cpp/ext/filters/logging/logging_filter.cc
  63. 4
      src/python/grpcio/grpc_core_dependencies.py
  64. 15
      test/core/end2end/fixtures/h2_sockpair_with_minstack.cc
  65. 2
      test/core/end2end/generate_tests.bzl
  66. 3
      test/core/end2end/tests/cancel_after_accept.cc
  67. 1
      test/core/end2end/tests/grpc_authz.cc
  68. 3
      test/core/end2end/tests/max_message_length.cc
  69. 2
      test/core/end2end/tests/no_logging.cc
  70. 11
      test/core/end2end/tests/server_streaming.cc
  71. 28
      test/core/filters/filter_fuzzer.cc
  72. 20
      test/core/promise/BUILD
  73. 4
      test/core/promise/activity_test.cc
  74. 1
      test/core/promise/for_each_test.cc
  75. 12
      test/core/promise/if_test.cc
  76. 144
      test/core/promise/interceptor_list_test.cc
  77. 4
      test/core/promise/latch_test.cc
  78. 1
      test/core/promise/map_pipe_test.cc
  79. 262
      test/core/promise/pipe_test.cc
  80. 45
      test/core/resource_quota/arena_test.cc
  81. 2
      test/core/slice/slice_test.cc
  82. 10
      test/cpp/ext/filters/logging/logging_test.cc
  83. 12
      tools/doxygen/Doxyfile.c++.internal
  84. 12
      tools/doxygen/Doxyfile.core.internal
  85. 24
      tools/run_tests/generated/tests.json

15
BUILD

@ -1421,6 +1421,8 @@ grpc_cc_library(
"//src/core:arena",
"//src/core:arena_promise",
"//src/core:atomic_utils",
"//src/core:basic_join",
"//src/core:basic_seq",
"//src/core:bitset",
"//src/core:channel_args",
"//src/core:channel_args_endpoint_config",
@ -1449,7 +1451,7 @@ grpc_cc_library(
"//src/core:iomgr_fwd",
"//src/core:iomgr_port",
"//src/core:json",
"//src/core:latch",
"//src/core:map",
"//src/core:match",
"//src/core:memory_quota",
"//src/core:no_destruct",
@ -1475,6 +1477,8 @@ grpc_cc_library(
"//src/core:thread_quota",
"//src/core:time",
"//src/core:transport_fwd",
"//src/core:try_join",
"//src/core:try_seq",
"//src/core:useful",
],
)
@ -3260,9 +3264,9 @@ grpc_cc_library(
"grpc_public_hdrs",
"grpc_trace",
"promise",
"//src/core:activity",
"//src/core:arena",
"//src/core:arena_promise",
"//src/core:basic_seq",
"//src/core:channel_args",
"//src/core:channel_fwd",
"//src/core:channel_init",
@ -3270,15 +3274,14 @@ grpc_cc_library(
"//src/core:context",
"//src/core:grpc_message_size_filter",
"//src/core:latch",
"//src/core:map_pipe",
"//src/core:map",
"//src/core:percent_encoding",
"//src/core:pipe",
"//src/core:promise_like",
"//src/core:seq",
"//src/core:poll",
"//src/core:race",
"//src/core:slice",
"//src/core:slice_buffer",
"//src/core:transport_fwd",
"//src/core:try_concurrently",
],
)

148
CMakeLists.txt generated

@ -1015,6 +1015,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx init_test)
add_dependencies(buildtests_cxx initial_settings_frame_bad_client_test)
add_dependencies(buildtests_cxx insecure_security_connector_test)
add_dependencies(buildtests_cxx interceptor_list_test)
add_dependencies(buildtests_cxx interop_client)
add_dependencies(buildtests_cxx interop_server)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX OR _gRPC_PLATFORM_WINDOWS)
@ -2209,6 +2210,7 @@ add_library(grpc
src/core/lib/iomgr/buffer_list.cc
src/core/lib/iomgr/call_combiner.cc
src/core/lib/iomgr/cfstream_handle.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/dualstack_socket_posix.cc
src/core/lib/iomgr/endpoint.cc
@ -2290,8 +2292,8 @@ add_library(grpc
src/core/lib/load_balancing/lb_policy_registry.cc
src/core/lib/matchers/matchers.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/pipe.cc
src/core/lib/promise/sleep.cc
src/core/lib/promise/trace.cc
src/core/lib/resolver/resolver.cc
src/core/lib/resolver/resolver_registry.cc
src/core/lib/resolver/server_address.cc
@ -2369,6 +2371,7 @@ add_library(grpc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
src/core/lib/surface/builtins.cc
@ -2892,6 +2895,7 @@ add_library(grpc_unsecure
src/core/lib/iomgr/buffer_list.cc
src/core/lib/iomgr/call_combiner.cc
src/core/lib/iomgr/cfstream_handle.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/dualstack_socket_posix.cc
src/core/lib/iomgr/endpoint.cc
@ -2971,8 +2975,8 @@ add_library(grpc_unsecure
src/core/lib/load_balancing/lb_policy.cc
src/core/lib/load_balancing/lb_policy_registry.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/pipe.cc
src/core/lib/promise/sleep.cc
src/core/lib/promise/trace.cc
src/core/lib/resolver/resolver.cc
src/core/lib/resolver/resolver_registry.cc
src/core/lib/resolver/server_address.cc
@ -3019,6 +3023,7 @@ add_library(grpc_unsecure
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
src/core/lib/surface/builtins.cc
@ -4402,6 +4407,7 @@ add_library(grpc_authorization_provider
src/core/lib/iomgr/buffer_list.cc
src/core/lib/iomgr/call_combiner.cc
src/core/lib/iomgr/cfstream_handle.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/dualstack_socket_posix.cc
src/core/lib/iomgr/endpoint.cc
@ -4481,7 +4487,7 @@ add_library(grpc_authorization_provider
src/core/lib/load_balancing/lb_policy_registry.cc
src/core/lib/matchers/matchers.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/pipe.cc
src/core/lib/promise/trace.cc
src/core/lib/resolver/resolver.cc
src/core/lib/resolver/resolver_registry.cc
src/core/lib/resolver/server_address.cc
@ -4528,6 +4534,7 @@ add_library(grpc_authorization_provider
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
src/core/lib/surface/builtins.cc
@ -8288,6 +8295,7 @@ add_executable(chunked_vector_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/exec_ctx.cc
@ -8302,6 +8310,7 @@ add_executable(chunked_vector_test
src/core/lib/resource_quota/trace.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/gprpp/chunked_vector_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -10577,6 +10586,7 @@ add_executable(exec_ctx_wakeup_scheduler_test
src/core/lib/debug/trace.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/exec_ctx.cc
@ -10585,6 +10595,7 @@ add_executable(exec_ctx_wakeup_scheduler_test
src/core/lib/promise/activity.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/promise/exec_ctx_wakeup_scheduler_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -11050,6 +11061,7 @@ add_executable(flow_control_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/exec_ctx.cc
@ -11063,6 +11075,7 @@ add_executable(flow_control_test
src/core/lib/resource_quota/trace.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/transport/bdp_estimator.cc
src/core/lib/transport/pid_controller.cc
@ -11119,13 +11132,14 @@ add_executable(for_each_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/iomgr_internal.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/pipe.cc
src/core/lib/promise/trace.cc
src/core/lib/resource_quota/arena.cc
src/core/lib/resource_quota/memory_quota.cc
src/core/lib/resource_quota/periodic_update.cc
@ -11134,6 +11148,7 @@ add_executable(for_each_test
src/core/lib/resource_quota/trace.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/promise/for_each_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -11478,6 +11493,7 @@ add_executable(frame_test
src/core/lib/iomgr/buffer_list.cc
src/core/lib/iomgr/call_combiner.cc
src/core/lib/iomgr/cfstream_handle.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/dualstack_socket_posix.cc
src/core/lib/iomgr/endpoint.cc
@ -11556,7 +11572,7 @@ add_executable(frame_test
src/core/lib/load_balancing/lb_policy.cc
src/core/lib/load_balancing/lb_policy_registry.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/pipe.cc
src/core/lib/promise/trace.cc
src/core/lib/resolver/resolver.cc
src/core/lib/resolver/resolver_registry.cc
src/core/lib/resolver/server_address.cc
@ -11580,6 +11596,7 @@ add_executable(frame_test
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
src/core/lib/surface/builtins.cc
@ -13917,6 +13934,77 @@ target_link_libraries(insecure_security_connector_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(interceptor_list_test
src/core/ext/upb-generated/google/protobuf/any.upb.c
src/core/ext/upb-generated/google/rpc/status.upb.c
src/core/lib/debug/trace.cc
src/core/lib/event_engine/memory_allocator.cc
src/core/lib/experiments/config.cc
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/iomgr_internal.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/trace.cc
src/core/lib/resource_quota/arena.cc
src/core/lib/resource_quota/memory_quota.cc
src/core/lib/resource_quota/periodic_update.cc
src/core/lib/resource_quota/resource_quota.cc
src/core/lib/resource_quota/thread_quota.cc
src/core/lib/resource_quota/trace.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/promise/interceptor_list_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_compile_features(interceptor_list_test PUBLIC cxx_std_14)
target_include_directories(interceptor_list_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(interceptor_list_test
${_gRPC_BASELIB_LIBRARIES}
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ZLIB_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::flat_hash_set
absl::any_invocable
absl::function_ref
absl::hash
absl::type_traits
absl::statusor
absl::utility
gpr
upb
)
endif()
if(gRPC_BUILD_TESTS)
@ -14399,7 +14487,9 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(latch_test
src/core/lib/debug/trace.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/trace.cc
test/core/promise/latch_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
@ -14646,13 +14736,14 @@ add_executable(map_pipe_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/iomgr_internal.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/pipe.cc
src/core/lib/promise/trace.cc
src/core/lib/resource_quota/arena.cc
src/core/lib/resource_quota/memory_quota.cc
src/core/lib/resource_quota/periodic_update.cc
@ -14661,6 +14752,7 @@ add_executable(map_pipe_test
src/core/lib/resource_quota/trace.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/promise/map_pipe_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -16016,6 +16108,7 @@ add_executable(periodic_update_test
src/core/lib/debug/trace.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/exec_ctx.cc
@ -16024,6 +16117,7 @@ add_executable(periodic_update_test
src/core/lib/resource_quota/periodic_update.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/resource_quota/periodic_update_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -16153,30 +16247,6 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(pipe_test
src/core/ext/upb-generated/google/protobuf/any.upb.c
src/core/ext/upb-generated/google/rpc/status.upb.c
src/core/lib/debug/trace.cc
src/core/lib/event_engine/memory_allocator.cc
src/core/lib/experiments/config.cc
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/iomgr_internal.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/pipe.cc
src/core/lib/resource_quota/arena.cc
src/core/lib/resource_quota/memory_quota.cc
src/core/lib/resource_quota/periodic_update.cc
src/core/lib/resource_quota/resource_quota.cc
src/core/lib/resource_quota/thread_quota.cc
src/core/lib/resource_quota/trace.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/promise/pipe_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
@ -16206,15 +16276,7 @@ target_link_libraries(pipe_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ZLIB_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::flat_hash_set
absl::any_invocable
absl::function_ref
absl::hash
absl::type_traits
absl::statusor
absl::utility
gpr
upb
grpc
)
@ -18768,7 +18830,9 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(slice_string_helpers_test
src/core/lib/debug/trace.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/slice/slice_string_helpers_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -20162,12 +20226,14 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(test_core_event_engine_slice_buffer_test
src/core/lib/debug/trace.cc
src/core/lib/event_engine/event_engine.cc
src/core/lib/event_engine/resolved_address.cc
src/core/lib/event_engine/slice.cc
src/core/lib/event_engine/slice_buffer.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/event_engine/slice_buffer_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -21515,19 +21581,21 @@ add_executable(try_concurrently_test
src/core/lib/experiments/experiments.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/time.cc
src/core/lib/iomgr/closure.cc
src/core/lib/iomgr/combiner.cc
src/core/lib/iomgr/error.cc
src/core/lib/iomgr/exec_ctx.cc
src/core/lib/iomgr/executor.cc
src/core/lib/iomgr/iomgr_internal.cc
src/core/lib/promise/activity.cc
src/core/lib/promise/pipe.cc
src/core/lib/promise/trace.cc
src/core/lib/resource_quota/arena.cc
src/core/lib/resource_quota/memory_quota.cc
src/core/lib/resource_quota/periodic_update.cc
src/core/lib/resource_quota/trace.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_refcount.cc
src/core/lib/slice/slice_string_helpers.cc
test/core/promise/try_concurrently_test.cc
third_party/googletest/googletest/src/gtest-all.cc

8
Makefile generated

@ -1473,6 +1473,7 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/buffer_list.cc \
src/core/lib/iomgr/call_combiner.cc \
src/core/lib/iomgr/cfstream_handle.cc \
src/core/lib/iomgr/closure.cc \
src/core/lib/iomgr/combiner.cc \
src/core/lib/iomgr/dualstack_socket_posix.cc \
src/core/lib/iomgr/endpoint.cc \
@ -1554,8 +1555,8 @@ LIBGRPC_SRC = \
src/core/lib/load_balancing/lb_policy_registry.cc \
src/core/lib/matchers/matchers.cc \
src/core/lib/promise/activity.cc \
src/core/lib/promise/pipe.cc \
src/core/lib/promise/sleep.cc \
src/core/lib/promise/trace.cc \
src/core/lib/resolver/resolver.cc \
src/core/lib/resolver/resolver_registry.cc \
src/core/lib/resolver/server_address.cc \
@ -1633,6 +1634,7 @@ LIBGRPC_SRC = \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
src/core/lib/surface/builtins.cc \
@ -2009,6 +2011,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/buffer_list.cc \
src/core/lib/iomgr/call_combiner.cc \
src/core/lib/iomgr/cfstream_handle.cc \
src/core/lib/iomgr/closure.cc \
src/core/lib/iomgr/combiner.cc \
src/core/lib/iomgr/dualstack_socket_posix.cc \
src/core/lib/iomgr/endpoint.cc \
@ -2088,8 +2091,8 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/load_balancing/lb_policy.cc \
src/core/lib/load_balancing/lb_policy_registry.cc \
src/core/lib/promise/activity.cc \
src/core/lib/promise/pipe.cc \
src/core/lib/promise/sleep.cc \
src/core/lib/promise/trace.cc \
src/core/lib/resolver/resolver.cc \
src/core/lib/resolver/resolver_registry.cc \
src/core/lib/resolver/server_address.cc \
@ -2136,6 +2139,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
src/core/lib/surface/builtins.cc \

@ -25,6 +25,7 @@ EXPERIMENTS = {
],
"core_end2end_test": [
"promise_based_client_call",
"promise_based_server_call",
],
"endpoint_test": [
"tcp_frame_size_tuning",

@ -930,25 +930,27 @@ libs:
- src/core/lib/promise/activity.h
- src/core/lib/promise/arena_promise.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_join.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/for_each.h
- src/core/lib/promise/if.h
- src/core/lib/promise/interceptor_list.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/latch.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
- src/core/lib/promise/map_pipe.h
- src/core/lib/promise/pipe.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/promise.h
- src/core/lib/promise/race.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/sleep.h
- src/core/lib/promise/try_concurrently.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resolver/resolver.h
- src/core/lib/resolver/resolver_factory.h
@ -1608,6 +1610,7 @@ libs:
- src/core/lib/iomgr/buffer_list.cc
- src/core/lib/iomgr/call_combiner.cc
- src/core/lib/iomgr/cfstream_handle.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/dualstack_socket_posix.cc
- src/core/lib/iomgr/endpoint.cc
@ -1689,8 +1692,8 @@ libs:
- src/core/lib/load_balancing/lb_policy_registry.cc
- src/core/lib/matchers/matchers.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/pipe.cc
- src/core/lib/promise/sleep.cc
- src/core/lib/promise/trace.cc
- src/core/lib/resolver/resolver.cc
- src/core/lib/resolver/resolver_registry.cc
- src/core/lib/resolver/server_address.cc
@ -1768,6 +1771,7 @@ libs:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/lib/surface/api_trace.cc
- src/core/lib/surface/builtins.cc
@ -2258,25 +2262,27 @@ libs:
- src/core/lib/promise/activity.h
- src/core/lib/promise/arena_promise.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_join.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/for_each.h
- src/core/lib/promise/if.h
- src/core/lib/promise/interceptor_list.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/latch.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
- src/core/lib/promise/map_pipe.h
- src/core/lib/promise/pipe.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/promise.h
- src/core/lib/promise/race.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/sleep.h
- src/core/lib/promise/try_concurrently.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resolver/resolver.h
- src/core/lib/resolver/resolver_factory.h
@ -2552,6 +2558,7 @@ libs:
- src/core/lib/iomgr/buffer_list.cc
- src/core/lib/iomgr/call_combiner.cc
- src/core/lib/iomgr/cfstream_handle.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/dualstack_socket_posix.cc
- src/core/lib/iomgr/endpoint.cc
@ -2631,8 +2638,8 @@ libs:
- src/core/lib/load_balancing/lb_policy.cc
- src/core/lib/load_balancing/lb_policy_registry.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/pipe.cc
- src/core/lib/promise/sleep.cc
- src/core/lib/promise/trace.cc
- src/core/lib/resolver/resolver.cc
- src/core/lib/resolver/resolver_registry.cc
- src/core/lib/resolver/server_address.cc
@ -2679,6 +2686,7 @@ libs:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/lib/surface/api_trace.cc
- src/core/lib/surface/builtins.cc
@ -3703,14 +3711,16 @@ libs:
- src/core/lib/promise/activity.h
- src/core/lib/promise/arena_promise.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_join.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/if.h
- src/core/lib/promise/interceptor_list.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/latch.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
- src/core/lib/promise/pipe.h
@ -3718,6 +3728,8 @@ libs:
- src/core/lib/promise/promise.h
- src/core/lib/promise/race.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resolver/resolver.h
- src/core/lib/resolver/resolver_factory.h
@ -3878,6 +3890,7 @@ libs:
- src/core/lib/iomgr/buffer_list.cc
- src/core/lib/iomgr/call_combiner.cc
- src/core/lib/iomgr/cfstream_handle.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/dualstack_socket_posix.cc
- src/core/lib/iomgr/endpoint.cc
@ -3957,7 +3970,7 @@ libs:
- src/core/lib/load_balancing/lb_policy_registry.cc
- src/core/lib/matchers/matchers.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/pipe.cc
- src/core/lib/promise/trace.cc
- src/core/lib/resolver/resolver.cc
- src/core/lib/resolver/resolver_registry.cc
- src/core/lib/resolver/server_address.cc
@ -4004,6 +4017,7 @@ libs:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/lib/surface/api_trace.cc
- src/core/lib/surface/builtins.cc
@ -5799,6 +5813,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/exec_ctx.cc
@ -5813,6 +5828,7 @@ targets:
- src/core/lib/resource_quota/trace.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/gprpp/chunked_vector_test.cc
deps:
@ -6797,6 +6813,7 @@ targets:
- src/core/lib/debug/trace.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/exec_ctx.cc
@ -6805,6 +6822,7 @@ targets:
- src/core/lib/promise/activity.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/promise/exec_ctx_wakeup_scheduler_test.cc
deps:
@ -7092,6 +7110,7 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/exec_ctx.cc
@ -7105,6 +7124,7 @@ targets:
- src/core/lib/resource_quota/trace.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/lib/transport/bdp_estimator.cc
- src/core/lib/transport/pid_controller.cc
@ -7156,6 +7176,8 @@ targets:
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/for_each.h
- src/core/lib/promise/if.h
- src/core/lib/promise/interceptor_list.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/join.h
- src/core/lib/promise/loop.h
@ -7164,6 +7186,7 @@ targets:
- src/core/lib/promise/poll.h
- src/core/lib/promise/race.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resource_quota/arena.h
- src/core/lib/resource_quota/memory_quota.h
@ -7186,13 +7209,14 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/exec_ctx.cc
- src/core/lib/iomgr/executor.cc
- src/core/lib/iomgr/iomgr_internal.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/pipe.cc
- src/core/lib/promise/trace.cc
- src/core/lib/resource_quota/arena.cc
- src/core/lib/resource_quota/memory_quota.cc
- src/core/lib/resource_quota/periodic_update.cc
@ -7201,6 +7225,7 @@ targets:
- src/core/lib/resource_quota/trace.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/promise/for_each_test.cc
deps:
@ -7500,14 +7525,16 @@ targets:
- src/core/lib/promise/activity.h
- src/core/lib/promise/arena_promise.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_join.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/if.h
- src/core/lib/promise/interceptor_list.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/latch.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
- src/core/lib/promise/pipe.h
@ -7515,6 +7542,9 @@ targets:
- src/core/lib/promise/promise.h
- src/core/lib/promise/race.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_join.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resolver/resolver.h
- src/core/lib/resolver/resolver_factory.h
- src/core/lib/resolver/resolver_registry.h
@ -7658,6 +7688,7 @@ targets:
- src/core/lib/iomgr/buffer_list.cc
- src/core/lib/iomgr/call_combiner.cc
- src/core/lib/iomgr/cfstream_handle.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/dualstack_socket_posix.cc
- src/core/lib/iomgr/endpoint.cc
@ -7736,7 +7767,7 @@ targets:
- src/core/lib/load_balancing/lb_policy.cc
- src/core/lib/load_balancing/lb_policy_registry.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/pipe.cc
- src/core/lib/promise/trace.cc
- src/core/lib/resolver/resolver.cc
- src/core/lib/resolver/resolver_registry.cc
- src/core/lib/resolver/server_address.cc
@ -7760,6 +7791,7 @@ targets:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/lib/surface/api_trace.cc
- src/core/lib/surface/builtins.cc
@ -8701,6 +8733,7 @@ targets:
build: test
language: c++
headers:
- src/core/lib/gprpp/construct_destruct.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/if.h
@ -8769,6 +8802,98 @@ targets:
- test/core/util/tracer_util.cc
deps:
- grpc_test_util
- name: interceptor_list_test
gtest: true
build: test
language: c++
headers:
- src/core/ext/upb-generated/google/protobuf/any.upb.h
- src/core/ext/upb-generated/google/rpc/status.upb.h
- src/core/lib/debug/trace.h
- src/core/lib/experiments/config.h
- src/core/lib/experiments/experiments.h
- src/core/lib/gpr/spinlock.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/bitset.h
- src/core/lib/gprpp/cpp_impl_of.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/status_helper.h
- src/core/lib/gprpp/time.h
- src/core/lib/iomgr/closure.h
- src/core/lib/iomgr/combiner.h
- src/core/lib/iomgr/error.h
- src/core/lib/iomgr/exec_ctx.h
- src/core/lib/iomgr/executor.h
- src/core/lib/iomgr/iomgr_internal.h
- src/core/lib/promise/activity.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/interceptor_list.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/race.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/trace.h
- src/core/lib/resource_quota/arena.h
- src/core/lib/resource_quota/memory_quota.h
- src/core/lib/resource_quota/periodic_update.h
- src/core/lib/resource_quota/resource_quota.h
- src/core/lib/resource_quota/thread_quota.h
- src/core/lib/resource_quota/trace.h
- src/core/lib/slice/percent_encoding.h
- src/core/lib/slice/slice.h
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
- test/core/promise/test_context.h
src:
- src/core/ext/upb-generated/google/protobuf/any.upb.c
- src/core/ext/upb-generated/google/rpc/status.upb.c
- src/core/lib/debug/trace.cc
- src/core/lib/event_engine/memory_allocator.cc
- src/core/lib/experiments/config.cc
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/exec_ctx.cc
- src/core/lib/iomgr/executor.cc
- src/core/lib/iomgr/iomgr_internal.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/trace.cc
- src/core/lib/resource_quota/arena.cc
- src/core/lib/resource_quota/memory_quota.cc
- src/core/lib/resource_quota/periodic_update.cc
- src/core/lib/resource_quota/resource_quota.cc
- src/core/lib/resource_quota/thread_quota.cc
- src/core/lib/resource_quota/trace.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/promise/interceptor_list_test.cc
deps:
- absl/container:flat_hash_set
- absl/functional:any_invocable
- absl/functional:function_ref
- absl/hash:hash
- absl/meta:type_traits
- absl/status:statusor
- absl/utility:utility
- gpr
- upb
uses_polling: false
- name: interop_client
build: test
run: false
@ -8973,6 +9098,7 @@ targets:
build: test
language: c++
headers:
- src/core/lib/debug/trace.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/bitset.h
- src/core/lib/gprpp/orphanable.h
@ -8991,9 +9117,12 @@ targets:
- src/core/lib/promise/latch.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/trace.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/trace.cc
- test/core/promise/latch_test.cc
deps:
- absl/meta:type_traits
@ -9112,6 +9241,8 @@ targets:
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/for_each.h
- src/core/lib/promise/if.h
- src/core/lib/promise/interceptor_list.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/join.h
- src/core/lib/promise/loop.h
@ -9121,6 +9252,7 @@ targets:
- src/core/lib/promise/poll.h
- src/core/lib/promise/race.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resource_quota/arena.h
- src/core/lib/resource_quota/memory_quota.h
@ -9143,13 +9275,14 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/exec_ctx.cc
- src/core/lib/iomgr/executor.cc
- src/core/lib/iomgr/iomgr_internal.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/pipe.cc
- src/core/lib/promise/trace.cc
- src/core/lib/resource_quota/arena.cc
- src/core/lib/resource_quota/memory_quota.cc
- src/core/lib/resource_quota/periodic_update.cc
@ -9158,6 +9291,7 @@ targets:
- src/core/lib/resource_quota/trace.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/promise/map_pipe_test.cc
deps:
@ -9706,6 +9840,7 @@ targets:
- src/core/lib/debug/trace.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/exec_ctx.cc
@ -9714,6 +9849,7 @@ targets:
- src/core/lib/resource_quota/periodic_update.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/resource_quota/periodic_update_test.cc
deps:
@ -9774,92 +9910,12 @@ targets:
build: test
language: c++
headers:
- src/core/ext/upb-generated/google/protobuf/any.upb.h
- src/core/ext/upb-generated/google/rpc/status.upb.h
- src/core/lib/debug/trace.h
- src/core/lib/experiments/config.h
- src/core/lib/experiments/experiments.h
- src/core/lib/gpr/spinlock.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/bitset.h
- src/core/lib/gprpp/cpp_impl_of.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/status_helper.h
- src/core/lib/gprpp/time.h
- src/core/lib/iomgr/closure.h
- src/core/lib/iomgr/combiner.h
- src/core/lib/iomgr/error.h
- src/core/lib/iomgr/exec_ctx.h
- src/core/lib/iomgr/executor.h
- src/core/lib/iomgr/iomgr_internal.h
- src/core/lib/promise/activity.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_join.h
- src/core/lib/promise/detail/basic_seq.h
- src/core/lib/promise/detail/promise_factory.h
- src/core/lib/promise/detail/promise_like.h
- src/core/lib/promise/detail/status.h
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/join.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
- src/core/lib/promise/pipe.h
- src/core/lib/promise/poll.h
- src/core/lib/promise/race.h
- src/core/lib/promise/seq.h
- src/core/lib/resource_quota/arena.h
- src/core/lib/resource_quota/memory_quota.h
- src/core/lib/resource_quota/periodic_update.h
- src/core/lib/resource_quota/resource_quota.h
- src/core/lib/resource_quota/thread_quota.h
- src/core/lib/resource_quota/trace.h
- src/core/lib/slice/percent_encoding.h
- src/core/lib/slice/slice.h
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/ext/upb-generated/google/protobuf/any.upb.c
- src/core/ext/upb-generated/google/rpc/status.upb.c
- src/core/lib/debug/trace.cc
- src/core/lib/event_engine/memory_allocator.cc
- src/core/lib/experiments/config.cc
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/exec_ctx.cc
- src/core/lib/iomgr/executor.cc
- src/core/lib/iomgr/iomgr_internal.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/pipe.cc
- src/core/lib/resource_quota/arena.cc
- src/core/lib/resource_quota/memory_quota.cc
- src/core/lib/resource_quota/periodic_update.cc
- src/core/lib/resource_quota/resource_quota.cc
- src/core/lib/resource_quota/thread_quota.cc
- src/core/lib/resource_quota/trace.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/promise/pipe_test.cc
deps:
- absl/container:flat_hash_set
- absl/functional:any_invocable
- absl/functional:function_ref
- absl/hash:hash
- absl/meta:type_traits
- absl/status:statusor
- absl/utility:utility
- gpr
- upb
- grpc
uses_polling: false
- name: poll_test
gtest: true
@ -10932,12 +10988,15 @@ targets:
build: test
language: c++
headers:
- src/core/lib/debug/trace.h
- src/core/lib/slice/slice.h
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/slice/slice_string_helpers_test.cc
deps:
@ -11561,6 +11620,7 @@ targets:
build: test
language: c++
headers:
- src/core/lib/debug/trace.h
- src/core/lib/event_engine/handle_containers.h
- src/core/lib/event_engine/resolved_address_internal.h
- src/core/lib/iomgr/port.h
@ -11571,12 +11631,14 @@ targets:
- src/core/lib/slice/slice_refcount.h
- src/core/lib/slice/slice_string_helpers.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/event_engine/event_engine.cc
- src/core/lib/event_engine/resolved_address.cc
- src/core/lib/event_engine/slice.cc
- src/core/lib/event_engine/slice_buffer.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/event_engine/slice_buffer_test.cc
deps:
@ -12184,6 +12246,8 @@ targets:
- src/core/lib/promise/detail/switch.h
- src/core/lib/promise/exec_ctx_wakeup_scheduler.h
- src/core/lib/promise/for_each.h
- src/core/lib/promise/if.h
- src/core/lib/promise/interceptor_list.h
- src/core/lib/promise/intra_activity_waiter.h
- src/core/lib/promise/loop.h
- src/core/lib/promise/map.h
@ -12192,6 +12256,7 @@ targets:
- src/core/lib/promise/poll.h
- src/core/lib/promise/race.h
- src/core/lib/promise/seq.h
- src/core/lib/promise/trace.h
- src/core/lib/promise/try_concurrently.h
- src/core/lib/promise/try_seq.h
- src/core/lib/resource_quota/arena.h
@ -12212,19 +12277,21 @@ targets:
- src/core/lib/experiments/experiments.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/time.cc
- src/core/lib/iomgr/closure.cc
- src/core/lib/iomgr/combiner.cc
- src/core/lib/iomgr/error.cc
- src/core/lib/iomgr/exec_ctx.cc
- src/core/lib/iomgr/executor.cc
- src/core/lib/iomgr/iomgr_internal.cc
- src/core/lib/promise/activity.cc
- src/core/lib/promise/pipe.cc
- src/core/lib/promise/trace.cc
- src/core/lib/resource_quota/arena.cc
- src/core/lib/resource_quota/memory_quota.cc
- src/core/lib/resource_quota/periodic_update.cc
- src/core/lib/resource_quota/trace.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_refcount.cc
- src/core/lib/slice/slice_string_helpers.cc
- test/core/promise/try_concurrently_test.cc
deps:

4
config.m4 generated

@ -598,6 +598,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/buffer_list.cc \
src/core/lib/iomgr/call_combiner.cc \
src/core/lib/iomgr/cfstream_handle.cc \
src/core/lib/iomgr/closure.cc \
src/core/lib/iomgr/combiner.cc \
src/core/lib/iomgr/dualstack_socket_posix.cc \
src/core/lib/iomgr/endpoint.cc \
@ -679,8 +680,8 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/load_balancing/lb_policy_registry.cc \
src/core/lib/matchers/matchers.cc \
src/core/lib/promise/activity.cc \
src/core/lib/promise/pipe.cc \
src/core/lib/promise/sleep.cc \
src/core/lib/promise/trace.cc \
src/core/lib/resolver/resolver.cc \
src/core/lib/resolver/resolver_registry.cc \
src/core/lib/resolver/server_address.cc \
@ -758,6 +759,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
src/core/lib/surface/builtins.cc \

4
config.w32 generated

@ -564,6 +564,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\iomgr\\buffer_list.cc " +
"src\\core\\lib\\iomgr\\call_combiner.cc " +
"src\\core\\lib\\iomgr\\cfstream_handle.cc " +
"src\\core\\lib\\iomgr\\closure.cc " +
"src\\core\\lib\\iomgr\\combiner.cc " +
"src\\core\\lib\\iomgr\\dualstack_socket_posix.cc " +
"src\\core\\lib\\iomgr\\endpoint.cc " +
@ -645,8 +646,8 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\load_balancing\\lb_policy_registry.cc " +
"src\\core\\lib\\matchers\\matchers.cc " +
"src\\core\\lib\\promise\\activity.cc " +
"src\\core\\lib\\promise\\pipe.cc " +
"src\\core\\lib\\promise\\sleep.cc " +
"src\\core\\lib\\promise\\trace.cc " +
"src\\core\\lib\\resolver\\resolver.cc " +
"src\\core\\lib\\resolver\\resolver_registry.cc " +
"src\\core\\lib\\resolver\\server_address.cc " +
@ -724,6 +725,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\slice\\percent_encoding.cc " +
"src\\core\\lib\\slice\\slice.cc " +
"src\\core\\lib\\slice\\slice_buffer.cc " +
"src\\core\\lib\\slice\\slice_refcount.cc " +
"src\\core\\lib\\slice\\slice_string_helpers.cc " +
"src\\core\\lib\\surface\\api_trace.cc " +
"src\\core\\lib\\surface\\builtins.cc " +

@ -118,6 +118,7 @@ some configuration as environment variables that can be set.
- queue_refcount
- error_refcount
- stream_refcount
- slice_refcount
- workqueue_refcount
- fd_refcount
- cq_refcount

16
gRPC-C++.podspec generated

@ -907,25 +907,27 @@ Pod::Spec.new do |s|
'src/core/lib/promise/activity.h',
'src/core/lib/promise/arena_promise.h',
'src/core/lib/promise/context.h',
'src/core/lib/promise/detail/basic_join.h',
'src/core/lib/promise/detail/basic_seq.h',
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/status.h',
'src/core/lib/promise/detail/switch.h',
'src/core/lib/promise/exec_ctx_wakeup_scheduler.h',
'src/core/lib/promise/for_each.h',
'src/core/lib/promise/if.h',
'src/core/lib/promise/interceptor_list.h',
'src/core/lib/promise/intra_activity_waiter.h',
'src/core/lib/promise/latch.h',
'src/core/lib/promise/loop.h',
'src/core/lib/promise/map.h',
'src/core/lib/promise/map_pipe.h',
'src/core/lib/promise/pipe.h',
'src/core/lib/promise/poll.h',
'src/core/lib/promise/promise.h',
'src/core/lib/promise/race.h',
'src/core/lib/promise/seq.h',
'src/core/lib/promise/sleep.h',
'src/core/lib/promise/try_concurrently.h',
'src/core/lib/promise/trace.h',
'src/core/lib/promise/try_join.h',
'src/core/lib/promise/try_seq.h',
'src/core/lib/resolver/resolver.h',
'src/core/lib/resolver/resolver_factory.h',
@ -1834,25 +1836,27 @@ Pod::Spec.new do |s|
'src/core/lib/promise/activity.h',
'src/core/lib/promise/arena_promise.h',
'src/core/lib/promise/context.h',
'src/core/lib/promise/detail/basic_join.h',
'src/core/lib/promise/detail/basic_seq.h',
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/status.h',
'src/core/lib/promise/detail/switch.h',
'src/core/lib/promise/exec_ctx_wakeup_scheduler.h',
'src/core/lib/promise/for_each.h',
'src/core/lib/promise/if.h',
'src/core/lib/promise/interceptor_list.h',
'src/core/lib/promise/intra_activity_waiter.h',
'src/core/lib/promise/latch.h',
'src/core/lib/promise/loop.h',
'src/core/lib/promise/map.h',
'src/core/lib/promise/map_pipe.h',
'src/core/lib/promise/pipe.h',
'src/core/lib/promise/poll.h',
'src/core/lib/promise/promise.h',
'src/core/lib/promise/race.h',
'src/core/lib/promise/seq.h',
'src/core/lib/promise/sleep.h',
'src/core/lib/promise/try_concurrently.h',
'src/core/lib/promise/trace.h',
'src/core/lib/promise/try_join.h',
'src/core/lib/promise/try_seq.h',
'src/core/lib/resolver/resolver.h',
'src/core/lib/resolver/resolver_factory.h',

20
gRPC-Core.podspec generated

@ -1321,6 +1321,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/call_combiner.h',
'src/core/lib/iomgr/cfstream_handle.cc',
'src/core/lib/iomgr/cfstream_handle.h',
'src/core/lib/iomgr/closure.cc',
'src/core/lib/iomgr/closure.h',
'src/core/lib/iomgr/combiner.cc',
'src/core/lib/iomgr/combiner.h',
@ -1476,19 +1477,19 @@ Pod::Spec.new do |s|
'src/core/lib/promise/activity.h',
'src/core/lib/promise/arena_promise.h',
'src/core/lib/promise/context.h',
'src/core/lib/promise/detail/basic_join.h',
'src/core/lib/promise/detail/basic_seq.h',
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/status.h',
'src/core/lib/promise/detail/switch.h',
'src/core/lib/promise/exec_ctx_wakeup_scheduler.h',
'src/core/lib/promise/for_each.h',
'src/core/lib/promise/if.h',
'src/core/lib/promise/interceptor_list.h',
'src/core/lib/promise/intra_activity_waiter.h',
'src/core/lib/promise/latch.h',
'src/core/lib/promise/loop.h',
'src/core/lib/promise/map.h',
'src/core/lib/promise/map_pipe.h',
'src/core/lib/promise/pipe.cc',
'src/core/lib/promise/pipe.h',
'src/core/lib/promise/poll.h',
'src/core/lib/promise/promise.h',
@ -1496,7 +1497,9 @@ Pod::Spec.new do |s|
'src/core/lib/promise/seq.h',
'src/core/lib/promise/sleep.cc',
'src/core/lib/promise/sleep.h',
'src/core/lib/promise/try_concurrently.h',
'src/core/lib/promise/trace.cc',
'src/core/lib/promise/trace.h',
'src/core/lib/promise/try_join.h',
'src/core/lib/promise/try_seq.h',
'src/core/lib/resolver/resolver.cc',
'src/core/lib/resolver/resolver.h',
@ -1651,6 +1654,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_buffer.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_refcount.h',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/slice/slice_string_helpers.h',
@ -2517,25 +2521,27 @@ Pod::Spec.new do |s|
'src/core/lib/promise/activity.h',
'src/core/lib/promise/arena_promise.h',
'src/core/lib/promise/context.h',
'src/core/lib/promise/detail/basic_join.h',
'src/core/lib/promise/detail/basic_seq.h',
'src/core/lib/promise/detail/promise_factory.h',
'src/core/lib/promise/detail/promise_like.h',
'src/core/lib/promise/detail/status.h',
'src/core/lib/promise/detail/switch.h',
'src/core/lib/promise/exec_ctx_wakeup_scheduler.h',
'src/core/lib/promise/for_each.h',
'src/core/lib/promise/if.h',
'src/core/lib/promise/interceptor_list.h',
'src/core/lib/promise/intra_activity_waiter.h',
'src/core/lib/promise/latch.h',
'src/core/lib/promise/loop.h',
'src/core/lib/promise/map.h',
'src/core/lib/promise/map_pipe.h',
'src/core/lib/promise/pipe.h',
'src/core/lib/promise/poll.h',
'src/core/lib/promise/promise.h',
'src/core/lib/promise/race.h',
'src/core/lib/promise/seq.h',
'src/core/lib/promise/sleep.h',
'src/core/lib/promise/try_concurrently.h',
'src/core/lib/promise/trace.h',
'src/core/lib/promise/try_join.h',
'src/core/lib/promise/try_seq.h',
'src/core/lib/resolver/resolver.h',
'src/core/lib/resolver/resolver_factory.h',

12
grpc.gemspec generated

@ -1230,6 +1230,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/call_combiner.h )
s.files += %w( src/core/lib/iomgr/cfstream_handle.cc )
s.files += %w( src/core/lib/iomgr/cfstream_handle.h )
s.files += %w( src/core/lib/iomgr/closure.cc )
s.files += %w( src/core/lib/iomgr/closure.h )
s.files += %w( src/core/lib/iomgr/combiner.cc )
s.files += %w( src/core/lib/iomgr/combiner.h )
@ -1385,19 +1386,19 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/promise/activity.h )
s.files += %w( src/core/lib/promise/arena_promise.h )
s.files += %w( src/core/lib/promise/context.h )
s.files += %w( src/core/lib/promise/detail/basic_join.h )
s.files += %w( src/core/lib/promise/detail/basic_seq.h )
s.files += %w( src/core/lib/promise/detail/promise_factory.h )
s.files += %w( src/core/lib/promise/detail/promise_like.h )
s.files += %w( src/core/lib/promise/detail/status.h )
s.files += %w( src/core/lib/promise/detail/switch.h )
s.files += %w( src/core/lib/promise/exec_ctx_wakeup_scheduler.h )
s.files += %w( src/core/lib/promise/for_each.h )
s.files += %w( src/core/lib/promise/if.h )
s.files += %w( src/core/lib/promise/interceptor_list.h )
s.files += %w( src/core/lib/promise/intra_activity_waiter.h )
s.files += %w( src/core/lib/promise/latch.h )
s.files += %w( src/core/lib/promise/loop.h )
s.files += %w( src/core/lib/promise/map.h )
s.files += %w( src/core/lib/promise/map_pipe.h )
s.files += %w( src/core/lib/promise/pipe.cc )
s.files += %w( src/core/lib/promise/pipe.h )
s.files += %w( src/core/lib/promise/poll.h )
s.files += %w( src/core/lib/promise/promise.h )
@ -1405,7 +1406,9 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/promise/seq.h )
s.files += %w( src/core/lib/promise/sleep.cc )
s.files += %w( src/core/lib/promise/sleep.h )
s.files += %w( src/core/lib/promise/try_concurrently.h )
s.files += %w( src/core/lib/promise/trace.cc )
s.files += %w( src/core/lib/promise/trace.h )
s.files += %w( src/core/lib/promise/try_join.h )
s.files += %w( src/core/lib/promise/try_seq.h )
s.files += %w( src/core/lib/resolver/resolver.cc )
s.files += %w( src/core/lib/resolver/resolver.h )
@ -1560,6 +1563,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/slice/slice_buffer.cc )
s.files += %w( src/core/lib/slice/slice_buffer.h )
s.files += %w( src/core/lib/slice/slice_internal.h )
s.files += %w( src/core/lib/slice/slice_refcount.cc )
s.files += %w( src/core/lib/slice/slice_refcount.h )
s.files += %w( src/core/lib/slice/slice_string_helpers.cc )
s.files += %w( src/core/lib/slice/slice_string_helpers.h )

12
grpc.gyp generated

@ -886,6 +886,7 @@
'src/core/lib/iomgr/buffer_list.cc',
'src/core/lib/iomgr/call_combiner.cc',
'src/core/lib/iomgr/cfstream_handle.cc',
'src/core/lib/iomgr/closure.cc',
'src/core/lib/iomgr/combiner.cc',
'src/core/lib/iomgr/dualstack_socket_posix.cc',
'src/core/lib/iomgr/endpoint.cc',
@ -967,8 +968,8 @@
'src/core/lib/load_balancing/lb_policy_registry.cc',
'src/core/lib/matchers/matchers.cc',
'src/core/lib/promise/activity.cc',
'src/core/lib/promise/pipe.cc',
'src/core/lib/promise/sleep.cc',
'src/core/lib/promise/trace.cc',
'src/core/lib/resolver/resolver.cc',
'src/core/lib/resolver/resolver_registry.cc',
'src/core/lib/resolver/server_address.cc',
@ -1046,6 +1047,7 @@
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
'src/core/lib/surface/builtins.cc',
@ -1364,6 +1366,7 @@
'src/core/lib/iomgr/buffer_list.cc',
'src/core/lib/iomgr/call_combiner.cc',
'src/core/lib/iomgr/cfstream_handle.cc',
'src/core/lib/iomgr/closure.cc',
'src/core/lib/iomgr/combiner.cc',
'src/core/lib/iomgr/dualstack_socket_posix.cc',
'src/core/lib/iomgr/endpoint.cc',
@ -1443,8 +1446,8 @@
'src/core/lib/load_balancing/lb_policy.cc',
'src/core/lib/load_balancing/lb_policy_registry.cc',
'src/core/lib/promise/activity.cc',
'src/core/lib/promise/pipe.cc',
'src/core/lib/promise/sleep.cc',
'src/core/lib/promise/trace.cc',
'src/core/lib/resolver/resolver.cc',
'src/core/lib/resolver/resolver_registry.cc',
'src/core/lib/resolver/server_address.cc',
@ -1491,6 +1494,7 @@
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
'src/core/lib/surface/builtins.cc',
@ -1865,6 +1869,7 @@
'src/core/lib/iomgr/buffer_list.cc',
'src/core/lib/iomgr/call_combiner.cc',
'src/core/lib/iomgr/cfstream_handle.cc',
'src/core/lib/iomgr/closure.cc',
'src/core/lib/iomgr/combiner.cc',
'src/core/lib/iomgr/dualstack_socket_posix.cc',
'src/core/lib/iomgr/endpoint.cc',
@ -1944,7 +1949,7 @@
'src/core/lib/load_balancing/lb_policy_registry.cc',
'src/core/lib/matchers/matchers.cc',
'src/core/lib/promise/activity.cc',
'src/core/lib/promise/pipe.cc',
'src/core/lib/promise/trace.cc',
'src/core/lib/resolver/resolver.cc',
'src/core/lib/resolver/resolver_registry.cc',
'src/core/lib/resolver/server_address.cc',
@ -1991,6 +1996,7 @@
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
'src/core/lib/surface/builtins.cc',

12
package.xml generated

@ -1212,6 +1212,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/call_combiner.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/cfstream_handle.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/cfstream_handle.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/closure.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/closure.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/combiner.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/combiner.h" role="src" />
@ -1367,19 +1368,19 @@
<file baseinstalldir="/" name="src/core/lib/promise/activity.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/arena_promise.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/context.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/basic_join.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/basic_seq.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/promise_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/promise_like.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/status.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/detail/switch.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/exec_ctx_wakeup_scheduler.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/for_each.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/if.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/interceptor_list.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/intra_activity_waiter.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/latch.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/loop.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/map.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/map_pipe.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/pipe.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/pipe.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/poll.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/promise.h" role="src" />
@ -1387,7 +1388,9 @@
<file baseinstalldir="/" name="src/core/lib/promise/seq.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/sleep.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/sleep.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/try_concurrently.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/trace.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/trace.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/try_join.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/promise/try_seq.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/resolver/resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/resolver/resolver.h" role="src" />
@ -1542,6 +1545,7 @@
<file baseinstalldir="/" name="src/core/lib/slice/slice_buffer.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_buffer.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_refcount.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_refcount.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" />

@ -380,6 +380,7 @@ grpc_cc_library(
hdrs = ["lib/promise/try_concurrently.h"],
external_deps = [
"absl/status",
"absl/strings",
"absl/types:variant",
],
language = "c++",
@ -387,6 +388,7 @@ grpc_cc_library(
"lib/promise/map_pipe.h",
],
deps = [
"activity",
"construct_destruct",
"for_each",
"map",
@ -395,8 +397,10 @@ grpc_cc_library(
"promise_factory",
"promise_like",
"promise_status",
"promise_trace",
"try_seq",
"//:gpr",
"//:grpc_trace",
],
)
@ -411,9 +415,13 @@ grpc_cc_library(
"for_each",
"map",
"pipe",
"poll",
"promise_factory",
"promise_trace",
"try_seq",
"//:gpr",
"//:gpr_platform",
"//:grpc_trace",
],
)
@ -524,6 +532,7 @@ grpc_cc_library(
language = "c++",
public_hdrs = ["lib/promise/if.h"],
deps = [
"construct_destruct",
"poll",
"promise_factory",
"promise_like",
@ -779,14 +788,18 @@ grpc_cc_library(
grpc_cc_library(
name = "latch",
external_deps = ["absl/strings"],
language = "c++",
public_hdrs = [
"lib/promise/latch.h",
],
deps = [
"activity",
"intra_activity_waiter",
"poll",
"promise_trace",
"//:gpr",
"//:grpc_trace",
],
)
@ -811,14 +824,37 @@ grpc_cc_library(
)
grpc_cc_library(
name = "pipe",
srcs = [
"lib/promise/pipe.cc",
name = "interceptor_list",
hdrs = [
"lib/promise/interceptor_list.h",
],
external_deps = [
"absl/strings",
"absl/strings:str_format",
"absl/types:optional",
"absl/types:variant",
],
deps = [
"arena",
"construct_destruct",
"context",
"poll",
"promise_factory",
"promise_trace",
"//:debug_location",
"//:gpr",
"//:grpc_trace",
],
)
grpc_cc_library(
name = "pipe",
hdrs = [
"lib/promise/pipe.h",
],
external_deps = [
"absl/base:core_headers",
"absl/memory",
"absl/strings",
"absl/types:optional",
"absl/types:variant",
@ -828,10 +864,32 @@ grpc_cc_library(
"activity",
"arena",
"context",
"if",
"interceptor_list",
"intra_activity_waiter",
"map",
"poll",
"promise_trace",
"seq",
"//:debug_location",
"//:gpr",
"//:grpc_trace",
"//:ref_counted_ptr",
],
)
grpc_cc_library(
name = "promise_trace",
srcs = [
"lib/promise/trace.cc",
],
hdrs = [
"lib/promise/trace.h",
],
language = "c++",
deps = [
"//:gpr_platform",
"//:grpc_trace",
],
)
@ -856,16 +914,20 @@ grpc_cc_library(
name = "for_each",
external_deps = [
"absl/status",
"absl/strings",
"absl/types:variant",
],
language = "c++",
public_hdrs = ["lib/promise/for_each.h"],
deps = [
"activity",
"construct_destruct",
"poll",
"promise_factory",
"promise_trace",
"//:gpr",
"//:gpr_platform",
"//:grpc_trace",
],
)
@ -1123,6 +1185,9 @@ grpc_cc_library(
grpc_cc_library(
name = "slice_refcount",
srcs = [
"lib/slice/slice_refcount.cc",
],
hdrs = [
"lib/slice/slice_refcount.h",
],
@ -1130,8 +1195,10 @@ grpc_cc_library(
"//:include/grpc/slice.h",
],
deps = [
"//:debug_location",
"//:event_engine_base_hdrs",
"//:gpr",
"//:grpc_trace",
],
)
@ -1155,6 +1222,7 @@ grpc_cc_library(
deps = [
"slice_cast",
"slice_refcount",
"//:debug_location",
"//:event_engine_base_hdrs",
"//:gpr",
],
@ -1169,6 +1237,7 @@ grpc_cc_library(
"lib/slice/slice_buffer.h",
"//:include/grpc/slice_buffer.h",
],
external_deps = ["absl/memory"],
deps = [
"slice",
"slice_refcount",
@ -1204,9 +1273,13 @@ grpc_cc_library(
grpc_cc_library(
name = "closure",
srcs = [
"lib/iomgr/closure.cc",
],
hdrs = [
"lib/iomgr/closure.h",
],
external_deps = ["absl/strings:str_format"],
visibility = ["@grpc:alt_grpc_base_legacy"],
deps = [
"error",
@ -3514,7 +3587,6 @@ grpc_cc_library(
"ext/filters/stateful_session/stateful_session_service_config_parser.h",
],
external_deps = [
"absl/status",
"absl/status:statusor",
"absl/strings",
"absl/types:optional",
@ -3523,7 +3595,6 @@ grpc_cc_library(
deps = [
"arena",
"arena_promise",
"basic_seq",
"channel_args",
"channel_fwd",
"context",
@ -3531,12 +3602,12 @@ grpc_cc_library(
"json",
"json_args",
"json_object_loader",
"latch",
"seq",
"map",
"pipe",
"poll",
"service_config_parser",
"slice",
"time",
"try_concurrently",
"unique_type_name",
"validation_errors",
"//:config",
@ -3574,26 +3645,29 @@ grpc_cc_library(
],
language = "c++",
deps = [
"arena",
"arena_promise",
"channel_args",
"channel_fwd",
"channel_init",
"channel_stack_type",
"closure",
"context",
"error",
"gpr_atm",
"grpc_sockaddr",
"json",
"json_args",
"json_object_loader",
"latch",
"lb_policy",
"lb_policy_factory",
"lb_policy_registry",
"map",
"pipe",
"poll",
"pollset_set",
"ref_counted",
"resolved_address",
"seq",
"slice",
"slice_refcount",
"status_helper",
@ -3617,7 +3691,6 @@ grpc_cc_library(
"//:grpc_security_base",
"//:grpc_trace",
"//:orphanable",
"//:promise",
"//:protobuf_duration_upb",
"//:protobuf_timestamp_upb",
"//:ref_counted_ptr",

@ -31,9 +31,11 @@
#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/promise/seq.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@ -61,16 +63,21 @@ ArenaPromise<ServerMetadataHandle> ClientLoadReportingFilter::MakeCallPromise(
client_stats.reset(*client_stats_md);
}
auto* server_initial_metadata = call_args.server_initial_metadata;
auto* saw_initial_metadata = GetContext<Arena>()->New<bool>(false);
call_args.server_initial_metadata->InterceptAndMap(
[saw_initial_metadata](ServerMetadataHandle md) {
*saw_initial_metadata = true;
return md;
});
return Seq(next_promise_factory(std::move(call_args)),
[server_initial_metadata, client_stats = std::move(client_stats)](
return Map(next_promise_factory(std::move(call_args)),
[saw_initial_metadata, client_stats = std::move(client_stats)](
ServerMetadataHandle trailing_metadata) {
if (client_stats != nullptr) {
client_stats->AddCallFinished(
trailing_metadata->get(GrpcStreamNetworkState()) ==
GrpcStreamNetworkState::kNotSentOnWire,
NowOrNever(server_initial_metadata->Wait()).has_value());
*saw_initial_metadata);
}
return trailing_metadata;
});

@ -40,10 +40,11 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/detail/basic_seq.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/seq.h"
#include "src/core/lib/promise/try_concurrently.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/race.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/transport/status_conversion.h"
@ -118,24 +119,27 @@ ArenaPromise<ServerMetadataHandle> HttpClientFilter::MakeCallPromise(
md->Set(ContentTypeMetadata(), ContentTypeMetadata::kApplicationGrpc);
md->Set(UserAgentMetadata(), user_agent_.Ref());
auto* read_latch = GetContext<Arena>()->New<Latch<ServerMetadata*>>();
auto* write_latch =
std::exchange(call_args.server_initial_metadata, read_latch);
return TryConcurrently(
Seq(next_promise_factory(std::move(call_args)),
[](ServerMetadataHandle md) -> ServerMetadataHandle {
auto r = CheckServerMetadata(md.get());
if (!r.ok()) return ServerMetadataFromStatus(r);
return md;
}))
.NecessaryPull(Seq(read_latch->Wait(),
[write_latch](ServerMetadata** md) -> absl::Status {
auto r = *md == nullptr ? absl::OkStatus()
: CheckServerMetadata(*md);
write_latch->Set(*md);
return r;
}));
auto* initial_metadata_err =
GetContext<Arena>()->New<Latch<ServerMetadataHandle>>();
call_args.server_initial_metadata->InterceptAndMap(
[initial_metadata_err](
ServerMetadataHandle md) -> absl::optional<ServerMetadataHandle> {
auto r = CheckServerMetadata(md.get());
if (!r.ok()) {
initial_metadata_err->Set(ServerMetadataFromStatus(r));
return absl::nullopt;
}
return std::move(md);
});
return Race(Map(next_promise_factory(std::move(call_args)),
[](ServerMetadataHandle md) -> ServerMetadataHandle {
auto r = CheckServerMetadata(md.get());
if (!r.ok()) return ServerMetadataFromStatus(r);
return md;
}),
initial_metadata_err->Wait());
}
HttpClientFilter::HttpClientFilter(HttpSchemeMetadata::ValueType scheme,

@ -21,7 +21,7 @@
#include <functional>
#include <initializer_list>
#include <memory>
#include <type_traits>
#include <string>
#include <utility>
#include "absl/meta/type_traits.h"
@ -43,17 +43,16 @@
#include "src/core/lib/compression/compression_internal.h"
#include "src/core/lib/compression/message_compress.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/detail/promise_like.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/map_pipe.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/promise/seq.h"
#include "src/core/lib/promise/try_concurrently.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/race.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/call_trace.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
@ -158,20 +157,19 @@ MessageHandle CompressionFilter::CompressMessage(
}
absl::StatusOr<MessageHandle> CompressionFilter::DecompressMessage(
MessageHandle message, grpc_compression_algorithm algorithm,
absl::optional<uint32_t> max_recv_message_length) const {
MessageHandle message, DecompressArgs args) const {
if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) {
gpr_log(GPR_ERROR, "DecompressMessage: len=%" PRIdPTR " max=%d alg=%d",
message->payload()->Length(), max_recv_message_length.value_or(-1),
algorithm);
message->payload()->Length(),
args.max_recv_message_length.value_or(-1), args.algorithm);
}
// Check max message length.
if (max_recv_message_length.has_value() &&
if (args.max_recv_message_length.has_value() &&
message->payload()->Length() >
static_cast<size_t>(*max_recv_message_length)) {
static_cast<size_t>(*args.max_recv_message_length)) {
return absl::ResourceExhaustedError(absl::StrFormat(
"Received message larger than max (%u vs. %d)",
message->payload()->Length(), *max_recv_message_length));
message->payload()->Length(), *args.max_recv_message_length));
}
// Check if decompression is enabled (if not, we can just pass the message
// up).
@ -181,11 +179,11 @@ absl::StatusOr<MessageHandle> CompressionFilter::DecompressMessage(
}
// Try to decompress the payload.
SliceBuffer decompressed_slices;
if (grpc_msg_decompress(algorithm, message->payload()->c_slice_buffer(),
if (grpc_msg_decompress(args.algorithm, message->payload()->c_slice_buffer(),
decompressed_slices.c_slice_buffer()) == 0) {
return absl::InternalError(
absl::StrCat("Unexpected error decompressing data for algorithm ",
CompressionAlgorithmAsString(algorithm)));
CompressionAlgorithmAsString(args.algorithm)));
}
// Swap the decompressed slices into the message.
message->payload()->Swap(&decompressed_slices);
@ -194,123 +192,114 @@ absl::StatusOr<MessageHandle> CompressionFilter::DecompressMessage(
return std::move(message);
}
class CompressionFilter::DecompressLoop {
public:
explicit DecompressLoop(CompressionFilter* filter, CallArgs& call_args)
: filter_(filter),
mapper_(PipeMapper<MessageHandle>::Intercept(
*call_args.incoming_messages)) {}
// Once we have a compression algorithm we can construct the decompression
// loop.
// Returns a promise that resolves to MessageHandle.
auto TakeAndRun(grpc_compression_algorithm algorithm) {
// Configure max receive size.
auto max_recv_message_length = filter_->max_recv_size_;
const MessageSizeParsedConfig* limits =
MessageSizeParsedConfig::GetFromCallContext(
GetContext<grpc_call_context_element>(),
filter_->message_size_service_config_parser_index_);
if (limits != nullptr && limits->max_recv_size().has_value() &&
(!max_recv_message_length.has_value() ||
*limits->max_recv_size() < *max_recv_message_length)) {
max_recv_message_length = *limits->max_recv_size();
}
// Interject decompression into the message loop.
return mapper_.TakeAndRun([algorithm, max_recv_message_length,
filter = filter_](MessageHandle message) {
return filter->DecompressMessage(std::move(message), algorithm,
max_recv_message_length);
});
grpc_compression_algorithm CompressionFilter::HandleOutgoingMetadata(
grpc_metadata_batch& outgoing_metadata) {
const auto algorithm = outgoing_metadata.Take(GrpcInternalEncodingRequest())
.value_or(default_compression_algorithm());
// Convey supported compression algorithms.
outgoing_metadata.Set(GrpcAcceptEncodingMetadata(),
enabled_compression_algorithms());
if (algorithm != GRPC_COMPRESS_NONE) {
outgoing_metadata.Set(GrpcEncodingMetadata(), algorithm);
}
return algorithm;
}
private:
CompressionFilter* filter_;
PipeMapper<MessageHandle> mapper_;
};
class CompressionFilter::CompressLoop {
public:
explicit CompressLoop(CompressionFilter* filter, CallArgs& call_args)
: filter_(filter),
mapper_(PipeMapper<MessageHandle>::Intercept(
*call_args.outgoing_messages)) {}
// Once we're ready to send initial metadata we can construct the compression
// loop.
// Returns a promise that resolves to MessageHandle.
auto TakeAndRun(grpc_metadata_batch& outgoing_metadata) {
const auto algorithm =
outgoing_metadata.Take(GrpcInternalEncodingRequest())
.value_or(filter_->default_compression_algorithm());
// Convey supported compression algorithms.
outgoing_metadata.Set(GrpcAcceptEncodingMetadata(),
filter_->enabled_compression_algorithms());
if (algorithm != GRPC_COMPRESS_NONE) {
outgoing_metadata.Set(GrpcEncodingMetadata(), algorithm);
}
// Interject compression into the message loop.
return mapper_.TakeAndRun([filter = filter_, algorithm](MessageHandle m) {
return filter->CompressMessage(std::move(m), algorithm);
});
CompressionFilter::DecompressArgs CompressionFilter::HandleIncomingMetadata(
const grpc_metadata_batch& incoming_metadata) {
// Configure max receive size.
auto max_recv_message_length = max_recv_size_;
const MessageSizeParsedConfig* limits =
MessageSizeParsedConfig::GetFromCallContext(
GetContext<grpc_call_context_element>(),
message_size_service_config_parser_index_);
if (limits != nullptr && limits->max_recv_size().has_value() &&
(!max_recv_message_length.has_value() ||
*limits->max_recv_size() < *max_recv_message_length)) {
max_recv_message_length = *limits->max_recv_size();
}
private:
CompressionFilter* filter_;
PipeMapper<MessageHandle> mapper_;
};
return DecompressArgs{incoming_metadata.get(GrpcEncodingMetadata())
.value_or(GRPC_COMPRESS_NONE),
max_recv_message_length};
}
ArenaPromise<ServerMetadataHandle> ClientCompressionFilter::MakeCallPromise(
CallArgs call_args, NextPromiseFactory next_promise_factory) {
auto compress_loop = CompressLoop(this, call_args)
.TakeAndRun(*call_args.client_initial_metadata);
DecompressLoop decompress_loop(this, call_args);
auto* server_initial_metadata = call_args.server_initial_metadata;
// Concurrently:
// - call the next filter
// - wait for initial metadata from the server and then commence decompression
// - compress outgoing messages
return TryConcurrently(next_promise_factory(std::move(call_args)))
.NecessaryPull(Seq(server_initial_metadata->Wait(),
[decompress_loop = std::move(decompress_loop)](
ServerMetadata** server_initial_metadata) mutable
-> ArenaPromise<absl::Status> {
if (*server_initial_metadata == nullptr) {
return ImmediateOkStatus();
}
return decompress_loop.TakeAndRun(
(*server_initial_metadata)
->get(GrpcEncodingMetadata())
.value_or(GRPC_COMPRESS_NONE));
}))
.Push(std::move(compress_loop));
auto compression_algorithm =
HandleOutgoingMetadata(*call_args.client_initial_metadata);
call_args.client_to_server_messages->InterceptAndMap(
[compression_algorithm,
this](MessageHandle message) -> absl::optional<MessageHandle> {
return CompressMessage(std::move(message), compression_algorithm);
});
auto* decompress_args = GetContext<Arena>()->New<DecompressArgs>(
DecompressArgs{GRPC_COMPRESS_NONE, absl::nullopt});
auto* decompress_err =
GetContext<Arena>()->New<Latch<ServerMetadataHandle>>();
call_args.server_initial_metadata->InterceptAndMap(
[decompress_args, this](ServerMetadataHandle server_initial_metadata)
-> absl::optional<ServerMetadataHandle> {
if (server_initial_metadata == nullptr) return absl::nullopt;
*decompress_args = HandleIncomingMetadata(*server_initial_metadata);
return std::move(server_initial_metadata);
});
call_args.server_to_client_messages->InterceptAndMap(
[decompress_err, decompress_args,
this](MessageHandle message) -> absl::optional<MessageHandle> {
auto r = DecompressMessage(std::move(message), *decompress_args);
if (!r.ok()) {
decompress_err->Set(ServerMetadataFromStatus(r.status()));
return absl::nullopt;
}
return std::move(*r);
});
// Run the next filter, and race it with getting an error from decompression.
return Race(next_promise_factory(std::move(call_args)),
decompress_err->Wait());
}
ArenaPromise<ServerMetadataHandle> ServerCompressionFilter::MakeCallPromise(
CallArgs call_args, NextPromiseFactory next_promise_factory) {
CompressLoop compress_loop(this, call_args);
auto decompress_loop = DecompressLoop(this, call_args)
.TakeAndRun(call_args.client_initial_metadata
->get(GrpcEncodingMetadata())
.value_or(GRPC_COMPRESS_NONE));
auto* read_latch = GetContext<Arena>()->New<Latch<ServerMetadata*>>();
auto* write_latch =
std::exchange(call_args.server_initial_metadata, read_latch);
auto decompress_args =
HandleIncomingMetadata(*call_args.client_initial_metadata);
auto* decompress_err =
GetContext<Arena>()->New<Latch<ServerMetadataHandle>>();
call_args.client_to_server_messages->InterceptAndMap(
[decompress_err, decompress_args,
this](MessageHandle message) -> absl::optional<MessageHandle> {
auto r = DecompressMessage(std::move(message), decompress_args);
gpr_log(GPR_DEBUG, "DecompressMessage returned %s",
r.status().ToString().c_str());
if (!r.ok()) {
decompress_err->Set(ServerMetadataFromStatus(r.status()));
return absl::nullopt;
}
return std::move(*r);
});
auto* compression_algorithm =
GetContext<Arena>()->New<grpc_compression_algorithm>();
call_args.server_initial_metadata->InterceptAndMap(
[this, compression_algorithm](ServerMetadataHandle md) {
if (grpc_call_trace.enabled()) {
gpr_log(GPR_INFO, "%s[compression] Write metadata",
Activity::current()->DebugTag().c_str());
}
// Find the compression algorithm.
*compression_algorithm = HandleOutgoingMetadata(*md);
return md;
});
call_args.server_to_client_messages->InterceptAndMap(
[compression_algorithm,
this](MessageHandle message) -> absl::optional<MessageHandle> {
return CompressMessage(std::move(message), *compression_algorithm);
});
// Concurrently:
// - call the next filter
// - decompress incoming messages
// - wait for initial metadata to be sent, and then commence compression of
// outgoing messages
return TryConcurrently(next_promise_factory(std::move(call_args)))
.Pull(std::move(decompress_loop))
.Push(Seq(read_latch->Wait(),
[write_latch, compress_loop = std::move(compress_loop)](
ServerMetadata** md) mutable {
// Find the compression algorithm.
auto loop = compress_loop.TakeAndRun(**md);
write_latch->Set(*md);
return loop;
}));
return Race(next_promise_factory(std::move(call_args)),
decompress_err->Wait());
}
} // namespace grpc_core

@ -34,6 +34,7 @@
#include "src/core/lib/channel/promise_based_filter.h"
#include "src/core/lib/compression/compression_internal.h"
#include "src/core/lib/promise/arena_promise.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
namespace grpc_core {
@ -62,10 +63,12 @@ namespace grpc_core {
class CompressionFilter : public ChannelFilter {
protected:
explicit CompressionFilter(const ChannelArgs& args);
struct DecompressArgs {
grpc_compression_algorithm algorithm;
absl::optional<uint32_t> max_recv_message_length;
};
class CompressLoop;
class DecompressLoop;
explicit CompressionFilter(const ChannelArgs& args);
grpc_compression_algorithm default_compression_algorithm() const {
return default_compression_algorithm_;
@ -75,15 +78,19 @@ class CompressionFilter : public ChannelFilter {
return enabled_compression_algorithms_;
}
private:
grpc_compression_algorithm HandleOutgoingMetadata(
grpc_metadata_batch& outgoing_metadata);
DecompressArgs HandleIncomingMetadata(
const grpc_metadata_batch& incoming_metadata);
// Compress one message synchronously.
MessageHandle CompressMessage(MessageHandle message,
grpc_compression_algorithm algorithm) const;
// Decompress one message synchronously.
absl::StatusOr<MessageHandle> DecompressMessage(
MessageHandle message, grpc_compression_algorithm algorithm,
absl::optional<uint32_t> max_recv_message_length) const;
absl::StatusOr<MessageHandle> DecompressMessage(MessageHandle message,
DecompressArgs args) const;
private:
// Max receive message length, if set.
absl::optional<uint32_t> max_recv_size_;
size_t message_size_service_config_parser_index_;

@ -22,6 +22,7 @@
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include "absl/base/attributes.h"
@ -30,18 +31,19 @@
#include "absl/types/optional.h"
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/detail/basic_seq.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/promise/seq.h"
#include "src/core/lib/promise/try_concurrently.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/surface/call_trace.h"
#include "src/core/lib/transport/metadata_batch.h"
namespace grpc_core {
@ -129,24 +131,23 @@ ArenaPromise<ServerMetadataHandle> HttpServerFilter::MakeCallPromise(
md->Remove(UserAgentMetadata());
}
auto* read_latch = GetContext<Arena>()->New<Latch<ServerMetadata*>>();
auto* write_latch =
std::exchange(call_args.server_initial_metadata, read_latch);
return TryConcurrently(
Seq(next_promise_factory(std::move(call_args)),
[](ServerMetadataHandle md) -> ServerMetadataHandle {
FilterOutgoingMetadata(md.get());
return md;
}))
.Push(Seq(read_latch->Wait(), [write_latch](ServerMetadata** md) {
FilterOutgoingMetadata(*md);
(*md)->Set(HttpStatusMetadata(), 200);
(*md)->Set(ContentTypeMetadata(),
ContentTypeMetadata::kApplicationGrpc);
write_latch->Set(*md);
return absl::OkStatus();
}));
call_args.server_initial_metadata->InterceptAndMap(
[](ServerMetadataHandle md) {
if (grpc_call_trace.enabled()) {
gpr_log(GPR_INFO, "%s[http-server] Write metadata",
Activity::current()->DebugTag().c_str());
}
FilterOutgoingMetadata(md.get());
md->Set(HttpStatusMetadata(), 200);
md->Set(ContentTypeMetadata(), ContentTypeMetadata::kApplicationGrpc);
return md;
});
return Map(next_promise_factory(std::move(call_args)),
[](ServerMetadataHandle md) -> ServerMetadataHandle {
FilterOutgoingMetadata(md.get());
return md;
});
}
absl::StatusOr<HttpServerFilter> HttpServerFilter::Create(

@ -27,7 +27,6 @@
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/escaping.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
@ -47,10 +46,9 @@
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/detail/basic_seq.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/seq.h"
#include "src/core/lib/promise/try_concurrently.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/service_config/service_config_call_data.h"
#include "src/core/lib/slice/slice.h"
@ -165,32 +163,23 @@ ArenaPromise<ServerMetadataHandle> StatefulSessionFilter::MakeCallPromise(
*cookie_value);
}
// Intercept server initial metadata.
auto* read_latch = GetContext<Arena>()->New<Latch<ServerMetadata*>>();
auto* write_latch =
std::exchange(call_args.server_initial_metadata, read_latch);
return TryConcurrently(
Seq(next_promise_factory(std::move(call_args)),
[cookie_config, cookie_value](ServerMetadataHandle md) {
// If we got a Trailers-Only response, then add the
// cookie to the trailing metadata instead of the
// initial metadata.
if (md->get(GrpcTrailersOnly()).value_or(false)) {
MaybeUpdateServerInitialMetadata(cookie_config,
cookie_value, md.get());
}
return md;
}))
.NecessaryPull(Seq(read_latch->Wait(),
[write_latch, cookie_config,
cookie_value](ServerMetadata** md) -> absl::Status {
if (*md != nullptr) {
// Add cookie to server initial metadata if needed.
MaybeUpdateServerInitialMetadata(
cookie_config, cookie_value, *md);
}
write_latch->Set(*md);
return absl::OkStatus();
}));
call_args.server_initial_metadata->InterceptAndMap(
[cookie_config, cookie_value](ServerMetadataHandle md) {
// Add cookie to server initial metadata if needed.
MaybeUpdateServerInitialMetadata(cookie_config, cookie_value, md.get());
return md;
});
return Map(next_promise_factory(std::move(call_args)),
[cookie_config, cookie_value](ServerMetadataHandle md) {
// If we got a Trailers-Only response, then add the
// cookie to the trailing metadata instead of the
// initial metadata.
if (md->get(GrpcTrailersOnly()).value_or(false)) {
MaybeUpdateServerInitialMetadata(cookie_config, cookie_value,
md.get());
}
return md;
});
}
absl::optional<absl::string_view>

@ -668,6 +668,10 @@ grpc_chttp2_stream::grpc_chttp2_stream(grpc_chttp2_transport* t,
flow_control(&t->flow_control) {
if (server_data) {
id = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(server_data));
if (grpc_http_trace.enabled()) {
gpr_log(GPR_DEBUG, "HTTP:%p/%p creating accept stream %d [from %p]", t,
this, id, server_data);
}
*t->accepting_stream = this;
grpc_chttp2_stream_map_add(&t->stream_map, id, this);
post_destructive_reclaimer(t);
@ -1829,6 +1833,12 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* t,
// Lambda is immediately invoked as a big scoped section that can be
// exited out of at any point by returning.
[&]() {
if (grpc_http_trace.enabled()) {
gpr_log(GPR_DEBUG,
"maybe_complete_recv_message %p final_metadata_requested=%d "
"seen_error=%d",
s, s->final_metadata_requested, s->seen_error);
}
if (s->final_metadata_requested && s->seen_error) {
grpc_slice_buffer_reset_and_unref(&s->frame_storage);
s->recv_message->reset();
@ -1839,6 +1849,12 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* t,
int64_t min_progress_size;
auto r = grpc_deframe_unprocessed_incoming_frames(
s, &min_progress_size, &**s->recv_message, s->recv_message_flags);
if (grpc_http_trace.enabled()) {
gpr_log(GPR_DEBUG, "Deframe data frame: %s",
grpc_core::PollToString(r, [](absl::Status r) {
return r.ToString();
}).c_str());
}
if (absl::holds_alternative<grpc_core::Pending>(r)) {
if (s->read_closed) {
grpc_slice_buffer_reset_and_unref(&s->frame_storage);
@ -1889,6 +1905,14 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* t,
void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_chttp2_transport* t,
grpc_chttp2_stream* s) {
grpc_chttp2_maybe_complete_recv_message(t, s);
if (grpc_http_trace.enabled()) {
gpr_log(GPR_DEBUG,
"maybe_complete_recv_trailing_metadata cli=%d s=%p closure=%p "
"read_closed=%d "
"write_closed=%d %" PRIdPTR,
t->is_client, s, s->recv_trailing_metadata_finished, s->read_closed,
s->write_closed, s->frame_storage.length);
}
if (s->recv_trailing_metadata_finished != nullptr && s->read_closed &&
s->write_closed) {
if (s->seen_error || !t->is_client) {
@ -2048,6 +2072,14 @@ void grpc_chttp2_fail_pending_writes(grpc_chttp2_transport* t,
void grpc_chttp2_mark_stream_closed(grpc_chttp2_transport* t,
grpc_chttp2_stream* s, int close_reads,
int close_writes, grpc_error_handle error) {
if (grpc_http_trace.enabled()) {
gpr_log(
GPR_DEBUG, "MARK_STREAM_CLOSED: t=%p s=%p(id=%d) %s [%s]", t, s, s->id,
(close_reads && close_writes)
? "read+write"
: (close_reads ? "read" : (close_writes ? "write" : "nothing??")),
error.ToString().c_str());
}
if (s->read_closed && s->write_closed) {
// already closed, but we should still fake the status if needed.
grpc_error_handle overall_error = removal_error(error, s, "Stream removed");

@ -389,12 +389,16 @@ struct grpc_chttp2_transport
uint32_t incoming_frame_size = 0;
uint32_t incoming_stream_id = 0;
// active parser
void* parser_data = nullptr;
grpc_chttp2_stream* incoming_stream = nullptr;
grpc_error_handle (*parser)(void* parser_user_data, grpc_chttp2_transport* t,
grpc_chttp2_stream* s, const grpc_slice& slice,
int is_last);
// active parser
struct Parser {
const char* name;
grpc_error_handle (*parser)(void* parser_user_data,
grpc_chttp2_transport* t, grpc_chttp2_stream* s,
const grpc_slice& slice, int is_last);
void* user_data = nullptr;
};
Parser parser;
grpc_chttp2_write_cb* write_cb_pool = nullptr;

@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <initializer_list>
@ -28,6 +28,7 @@
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include <grpc/slice.h>
#include <grpc/support/log.h>
@ -127,6 +128,65 @@ uint32_t grpc_chttp2_min_read_progress_size(grpc_chttp2_transport* t) {
GPR_UNREACHABLE_CODE(return 1);
}
namespace {
struct KnownFlag {
uint8_t flag;
absl::string_view name;
};
std::string MakeFrameTypeString(absl::string_view frame_type, uint8_t flags,
std::initializer_list<KnownFlag> known_flags) {
std::string result(frame_type);
for (const KnownFlag& known_flag : known_flags) {
if (flags & known_flag.flag) {
absl::StrAppend(&result, ":", known_flag.name);
flags &= ~known_flag.flag;
}
}
if (flags != 0) {
absl::StrAppend(&result, ":UNKNOWN_FLAGS=0x",
absl::Hex(flags, absl::kZeroPad2));
}
return result;
}
std::string FrameTypeString(uint8_t frame_type, uint8_t flags) {
switch (frame_type) {
case GRPC_CHTTP2_FRAME_DATA:
return MakeFrameTypeString(
"DATA", flags, {{GRPC_CHTTP2_DATA_FLAG_END_STREAM, "END_STREAM"}});
case GRPC_CHTTP2_FRAME_HEADER:
return MakeFrameTypeString(
"HEADERS", flags,
{{GRPC_CHTTP2_DATA_FLAG_END_STREAM, "END_STREAM"},
{GRPC_CHTTP2_DATA_FLAG_END_HEADERS, "END_HEADERS"},
{GRPC_CHTTP2_FLAG_HAS_PRIORITY, "PRIORITY"}});
case GRPC_CHTTP2_FRAME_CONTINUATION:
return MakeFrameTypeString(
"HEADERS", flags,
{{GRPC_CHTTP2_DATA_FLAG_END_STREAM, "END_STREAM"},
{GRPC_CHTTP2_DATA_FLAG_END_HEADERS, "END_HEADERS"},
{GRPC_CHTTP2_FLAG_HAS_PRIORITY, "PRIORITY"}});
case GRPC_CHTTP2_FRAME_RST_STREAM:
return MakeFrameTypeString("RST_STREAM", flags, {});
case GRPC_CHTTP2_FRAME_SETTINGS:
return MakeFrameTypeString("SETTINGS", flags,
{{GRPC_CHTTP2_FLAG_ACK, "ACK"}});
case GRPC_CHTTP2_FRAME_PING:
return MakeFrameTypeString("PING", flags,
{{GRPC_CHTTP2_FLAG_ACK, "ACK"}});
case GRPC_CHTTP2_FRAME_GOAWAY:
return MakeFrameTypeString("GOAWAY", flags, {});
case GRPC_CHTTP2_FRAME_WINDOW_UPDATE:
return MakeFrameTypeString("WINDOW_UPDATE", flags, {});
default:
return MakeFrameTypeString(
absl::StrCat("UNKNOWN_FRAME_TYPE_", static_cast<int>(frame_type)),
flags, {});
}
}
} // namespace
grpc_error_handle grpc_chttp2_perform_read(grpc_chttp2_transport* t,
const grpc_slice& slice) {
const uint8_t* beg = GRPC_SLICE_START_PTR(slice);
@ -250,6 +310,12 @@ grpc_error_handle grpc_chttp2_perform_read(grpc_chttp2_transport* t,
case GRPC_DTS_FH_8:
GPR_DEBUG_ASSERT(cur < end);
t->incoming_stream_id |= (static_cast<uint32_t>(*cur));
if (grpc_http_trace.enabled()) {
gpr_log(GPR_INFO, "INCOMING[%p]: %s len:%d id:0x%08x", t,
FrameTypeString(t->incoming_frame_type, t->incoming_frame_flags)
.c_str(),
t->incoming_frame_size, t->incoming_stream_id);
}
t->deframe_state = GRPC_DTS_FRAME;
err = init_frame_parser(t);
if (!err.ok()) {
@ -404,8 +470,8 @@ static HPackParser::LogInfo hpack_parser_log_info(
static grpc_error_handle init_header_skip_frame_parser(
grpc_chttp2_transport* t, HPackParser::Priority priority_type) {
bool is_eoh = t->expect_continuation_stream_id != 0;
t->parser = grpc_chttp2_header_parser_parse;
t->parser_data = &t->hpack_parser;
t->parser = grpc_chttp2_transport::Parser{
"header", grpc_chttp2_header_parser_parse, &t->hpack_parser};
t->hpack_parser.BeginFrame(
nullptr,
t->settings[GRPC_ACKED_SETTINGS]
@ -417,15 +483,17 @@ static grpc_error_handle init_header_skip_frame_parser(
static grpc_error_handle init_non_header_skip_frame_parser(
grpc_chttp2_transport* t) {
t->parser = skip_parser;
t->parser =
grpc_chttp2_transport::Parser{"skip_parser", skip_parser, nullptr};
return absl::OkStatus();
}
void grpc_chttp2_parsing_become_skip_parser(grpc_chttp2_transport* t) {
if (t->parser == grpc_chttp2_header_parser_parse) {
if (t->parser.parser == grpc_chttp2_header_parser_parse) {
t->hpack_parser.StopBufferingFrame();
} else {
t->parser = skip_parser;
t->parser =
grpc_chttp2_transport::Parser{"skip_parser", skip_parser, nullptr};
}
}
@ -472,9 +540,8 @@ static grpc_error_handle init_data_frame_parser(grpc_chttp2_transport* t) {
error_handler:
if (status.ok()) {
t->incoming_stream = s;
// t->parser = grpc_chttp2_data_parser_parse;
t->parser = grpc_chttp2_data_parser_parse;
t->parser_data = nullptr;
t->parser = grpc_chttp2_transport::Parser{
"data", grpc_chttp2_data_parser_parse, nullptr};
t->ping_state.last_ping_sent_time = grpc_core::Timestamp::InfPast();
return absl::OkStatus();
} else if (s != nullptr) {
@ -584,8 +651,8 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
t->incoming_stream = nullptr;
return init_header_skip_frame_parser(t, priority_type);
}
t->parser = grpc_chttp2_header_parser_parse;
t->parser_data = &t->hpack_parser;
t->parser = grpc_chttp2_transport::Parser{
"header", grpc_chttp2_header_parser_parse, &t->hpack_parser};
if (t->header_eof) {
s->eos_received = true;
}
@ -640,12 +707,17 @@ static grpc_error_handle init_window_update_frame_parser(
grpc_chttp2_stream* s = t->incoming_stream =
grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
if (s == nullptr) {
if (grpc_http_trace.enabled()) {
gpr_log(GPR_ERROR, "Stream %d not found, ignoring WINDOW_UPDATE",
t->incoming_stream_id);
}
return init_non_header_skip_frame_parser(t);
}
s->stats.incoming.framing_bytes += 9;
}
t->parser = grpc_chttp2_window_update_parser_parse;
t->parser_data = &t->simple.window_update;
t->parser = grpc_chttp2_transport::Parser{
"window_update", grpc_chttp2_window_update_parser_parse,
&t->simple.window_update};
return absl::OkStatus();
}
@ -653,8 +725,8 @@ static grpc_error_handle init_ping_parser(grpc_chttp2_transport* t) {
grpc_error_handle err = grpc_chttp2_ping_parser_begin_frame(
&t->simple.ping, t->incoming_frame_size, t->incoming_frame_flags);
if (!err.ok()) return err;
t->parser = grpc_chttp2_ping_parser_parse;
t->parser_data = &t->simple.ping;
t->parser = grpc_chttp2_transport::Parser{
"ping", grpc_chttp2_ping_parser_parse, &t->simple.ping};
return absl::OkStatus();
}
@ -668,8 +740,8 @@ static grpc_error_handle init_rst_stream_parser(grpc_chttp2_transport* t) {
return init_non_header_skip_frame_parser(t);
}
s->stats.incoming.framing_bytes += 9;
t->parser = grpc_chttp2_rst_stream_parser_parse;
t->parser_data = &t->simple.rst_stream;
t->parser = grpc_chttp2_transport::Parser{
"rst_stream", grpc_chttp2_rst_stream_parser_parse, &t->simple.rst_stream};
return absl::OkStatus();
}
@ -677,8 +749,8 @@ static grpc_error_handle init_goaway_parser(grpc_chttp2_transport* t) {
grpc_error_handle err = grpc_chttp2_goaway_parser_begin_frame(
&t->goaway_parser, t->incoming_frame_size, t->incoming_frame_flags);
if (!err.ok()) return err;
t->parser = grpc_chttp2_goaway_parser_parse;
t->parser_data = &t->goaway_parser;
t->parser = grpc_chttp2_transport::Parser{
"goaway", grpc_chttp2_goaway_parser_parse, &t->goaway_parser};
return absl::OkStatus();
}
@ -706,8 +778,8 @@ static grpc_error_handle init_settings_frame_parser(grpc_chttp2_transport* t) {
t, nullptr);
t->sent_local_settings = false;
}
t->parser = grpc_chttp2_settings_parser_parse;
t->parser_data = &t->simple.settings;
t->parser = grpc_chttp2_transport::Parser{
"settings", grpc_chttp2_settings_parser_parse, &t->simple.settings};
return absl::OkStatus();
}
@ -715,15 +787,24 @@ static grpc_error_handle parse_frame_slice(grpc_chttp2_transport* t,
const grpc_slice& slice,
int is_last) {
grpc_chttp2_stream* s = t->incoming_stream;
grpc_error_handle err = t->parser(t->parser_data, t, s, slice, is_last);
if (grpc_http_trace.enabled()) {
gpr_log(GPR_DEBUG,
"INCOMING[%p;%p]: Parse %" PRIdPTR "b %sframe fragment with %s", t,
s, GRPC_SLICE_LENGTH(slice), is_last ? "last " : "",
t->parser.name);
}
grpc_error_handle err =
t->parser.parser(t->parser.user_data, t, s, slice, is_last);
intptr_t unused;
if (GPR_LIKELY(err.ok())) {
return err;
} else if (grpc_error_get_int(err, grpc_core::StatusIntProperty::kStreamId,
&unused)) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
gpr_log(GPR_ERROR, "%s", grpc_core::StatusToString(err).c_str());
}
}
if (grpc_http_trace.enabled()) {
gpr_log(GPR_ERROR, "INCOMING[%p;%p]: Parse failed with %s", t, s,
err.ToString().c_str());
}
if (grpc_error_get_int(err, grpc_core::StatusIntProperty::kStreamId,
&unused)) {
grpc_chttp2_parsing_become_skip_parser(t);
if (s) {
s->forced_close_error = err;

@ -37,6 +37,7 @@
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/surface/call_trace.h"
#include "src/core/lib/surface/channel_stack_type.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/transport.h"
@ -53,12 +54,24 @@ absl::StatusOr<RefCountedPtr<grpc_channel_stack>>
ChannelStackBuilderImpl::Build() {
std::vector<const grpc_channel_filter*> stack;
const bool is_promising = IsPromising();
const bool is_client =
grpc_channel_stack_type_is_client(channel_stack_type());
const bool client_promise_tracing =
is_client && is_promising && grpc_call_trace.enabled();
const bool server_promise_tracing =
!is_client && is_promising && grpc_call_trace.enabled();
for (const auto* filter : this->stack()) {
if (is_promising && grpc_call_trace.enabled()) {
if (client_promise_tracing) {
stack.push_back(PromiseTracingFilterFor(filter));
}
stack.push_back(filter);
if (server_promise_tracing) {
stack.push_back(PromiseTracingFilterFor(filter));
}
}
if (server_promise_tracing) {
stack.pop_back(); // connected_channel must be last => can't be traced
}
// calculate the size of the channel stack

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -19,15 +19,13 @@
// promise-style. Most of this will be removed once the promises conversion is
// completed.
// TODO(ctiller): When removing this file, also reduce the number of *'s on the
// server initial metadata latch.
#include <grpc/support/port_platform.h>
#include <stdint.h>
#include <stdlib.h>
#include <atomic>
#include <initializer_list>
#include <memory>
#include <new>
#include <string>
@ -35,6 +33,7 @@
#include <utility>
#include "absl/container/inlined_vector.h"
#include "absl/functional/function_ref.h"
#include "absl/meta/type_traits.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
@ -60,7 +59,6 @@
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/arena_promise.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/resource_quota/arena.h"
@ -152,9 +150,27 @@ class InvalidChannelFilter : public ChannelFilter {
// Call data shared between all implementations of promise-based filters.
class BaseCallData : public Activity, private Wakeable {
public:
protected:
// Hook to allow interception of messages on the send/receive path by
// PipeSender and PipeReceiver, as appropriate according to whether we're
// client or server.
class Interceptor {
public:
virtual PipeSender<MessageHandle>* Push() = 0;
virtual PipeReceiver<MessageHandle>* Pull() = 0;
virtual PipeReceiver<MessageHandle>* original_receiver() = 0;
virtual PipeSender<MessageHandle>* original_sender() = 0;
virtual void GotPipe(PipeSender<MessageHandle>*) = 0;
virtual void GotPipe(PipeReceiver<MessageHandle>*) = 0;
virtual ~Interceptor() = default;
};
BaseCallData(grpc_call_element* elem, const grpc_call_element_args* args,
uint8_t flags);
uint8_t flags,
absl::FunctionRef<Interceptor*()> make_send_interceptor,
absl::FunctionRef<Interceptor*()> make_recv_interceptor);
public:
~BaseCallData() override;
void set_pollent(grpc_polling_entity* pollent) {
@ -270,6 +286,54 @@ class BaseCallData : public Activity, private Wakeable {
return p.release();
}
class ReceiveInterceptor final : public Interceptor {
public:
explicit ReceiveInterceptor(Arena* arena) : pipe_{arena} {}
PipeReceiver<MessageHandle>* original_receiver() override {
return &pipe_.receiver;
}
PipeSender<MessageHandle>* original_sender() override { abort(); }
void GotPipe(PipeReceiver<MessageHandle>* receiver) override {
GPR_ASSERT(receiver_ == nullptr);
receiver_ = receiver;
}
void GotPipe(PipeSender<MessageHandle>*) override { abort(); }
PipeSender<MessageHandle>* Push() override { return &pipe_.sender; }
PipeReceiver<MessageHandle>* Pull() override { return receiver_; }
private:
Pipe<MessageHandle> pipe_;
PipeReceiver<MessageHandle>* receiver_ = nullptr;
};
class SendInterceptor final : public Interceptor {
public:
explicit SendInterceptor(Arena* arena) : pipe_{arena} {}
PipeReceiver<MessageHandle>* original_receiver() override { abort(); }
PipeSender<MessageHandle>* original_sender() override {
return &pipe_.sender;
}
void GotPipe(PipeReceiver<MessageHandle>*) override { abort(); }
void GotPipe(PipeSender<MessageHandle>* sender) override {
GPR_ASSERT(sender_ == nullptr);
sender_ = sender;
}
PipeSender<MessageHandle>* Push() override { return sender_; }
PipeReceiver<MessageHandle>* Pull() override { return &pipe_.receiver; }
private:
Pipe<MessageHandle> pipe_;
PipeSender<MessageHandle>* sender_ = nullptr;
};
// State machine for sending messages: handles intercepting send_message ops
// and forwarding them through pipes to the promise, then getting the result
// down the stack.
@ -277,9 +341,11 @@ class BaseCallData : public Activity, private Wakeable {
// these members for filters that don't need to intercept sent messages.
class SendMessage {
public:
explicit SendMessage(BaseCallData* base)
: base_(base), pipe_(base->arena()) {}
PipeReceiver<MessageHandle>* outgoing_pipe() { return &pipe_.receiver; }
SendMessage(BaseCallData* base, Interceptor* interceptor)
: base_(base), interceptor_(interceptor) {}
~SendMessage() { interceptor_->~Interceptor(); }
Interceptor* interceptor() { return interceptor_; }
// Start a send_message op.
void StartOp(CapturedBatch batch);
@ -287,16 +353,19 @@ class BaseCallData : public Activity, private Wakeable {
// This happens when the promise requests to call the next filter: until
// this occurs messages can't be sent as we don't know the pipe that the
// promise expects to send on.
void GotPipe(PipeReceiver<MessageHandle>* receiver);
template <typename T>
void GotPipe(T* pipe);
// Called from client/server polling to do the send message part of the
// work.
void WakeInsideCombiner(Flusher* flusher);
void WakeInsideCombiner(Flusher* flusher, bool allow_push_to_pipe);
// Call is completed, we have trailing metadata. Close things out.
void Done(const ServerMetadata& metadata, Flusher* flusher);
// Return true if we have a batch captured (for debug logs)
bool HaveCapturedBatch() const { return batch_.is_captured(); }
// Return true if we're not actively sending a message.
bool IsIdle() const;
// Return true if we've released the message for forwarding down the stack.
bool IsForwarded() const { return state_ == State::kForwardedBatch; }
private:
enum class State : uint8_t {
@ -331,11 +400,9 @@ class BaseCallData : public Activity, private Wakeable {
BaseCallData* const base_;
State state_ = State::kInitial;
Pipe<MessageHandle> pipe_;
PipeReceiver<MessageHandle>* receiver_ = nullptr;
Interceptor* const interceptor_;
absl::optional<PipeSender<MessageHandle>::PushType> push_;
absl::optional<PipeReceiver<MessageHandle>::NextType> next_;
absl::optional<NextResult<MessageHandle>> next_result_;
absl::optional<PipeReceiverNextType<MessageHandle>> next_;
CapturedBatch batch_;
grpc_closure* intercepted_on_complete_;
grpc_closure on_complete_ =
@ -351,9 +418,11 @@ class BaseCallData : public Activity, private Wakeable {
// these members for filters that don't need to intercept sent messages.
class ReceiveMessage {
public:
explicit ReceiveMessage(BaseCallData* base)
: base_(base), pipe_(base->arena()) {}
PipeSender<MessageHandle>* incoming_pipe() { return &pipe_.sender; }
ReceiveMessage(BaseCallData* base, Interceptor* interceptor)
: base_(base), interceptor_(interceptor) {}
~ReceiveMessage() { interceptor_->~Interceptor(); }
Interceptor* interceptor() { return interceptor_; }
// Start a recv_message op.
void StartOp(CapturedBatch& batch);
@ -361,10 +430,11 @@ class BaseCallData : public Activity, private Wakeable {
// This happens when the promise requests to call the next filter: until
// this occurs messages can't be received as we don't know the pipe that the
// promise expects to forward them with.
void GotPipe(PipeSender<MessageHandle>* sender);
template <typename T>
void GotPipe(T* pipe);
// Called from client/server polling to do the receive message part of the
// work.
void WakeInsideCombiner(Flusher* flusher);
void WakeInsideCombiner(Flusher* flusher, bool allow_push_to_pipe);
// Call is completed, we have trailing metadata. Close things out.
void Done(const ServerMetadata& metadata, Flusher* flusher);
@ -408,23 +478,28 @@ class BaseCallData : public Activity, private Wakeable {
// On the next poll we'll close things out and forward on completions,
// then transition to cancelled.
kBatchCompletedButCancelled,
// Completed successfully while we're processing a recv message.
// Completed successfully while we're processing a recv message - see
// kPushedToPipe.
kCompletedWhilePushedToPipe,
// Completed successfully while we're processing a recv message - see
// kPulledFromPipe.
kCompletedWhilePulledFromPipe,
// Completed successfully while we were waiting to process
// kBatchCompleted.
kCompletedWhileBatchCompleted,
};
static const char* StateString(State);
void OnComplete(absl::Status status);
BaseCallData* const base_;
Pipe<MessageHandle> pipe_;
PipeSender<MessageHandle>* sender_;
Interceptor* const interceptor_;
State state_ = State::kInitial;
uint32_t scratch_flags_;
absl::optional<SliceBuffer>* intercepted_slice_buffer_;
uint32_t* intercepted_flags_;
absl::optional<PipeSender<MessageHandle>::PushType> push_;
absl::optional<PipeReceiver<MessageHandle>::NextType> next_;
absl::optional<PipeReceiverNextType<MessageHandle>> next_;
absl::Status completed_status_;
grpc_closure* intercepted_on_complete_;
grpc_closure on_complete_ =
@ -436,15 +511,8 @@ class BaseCallData : public Activity, private Wakeable {
CallCombiner* call_combiner() const { return call_combiner_; }
Timestamp deadline() const { return deadline_; }
grpc_call_stack* call_stack() const { return call_stack_; }
Latch<ServerMetadata*>* server_initial_metadata_latch() const {
return server_initial_metadata_latch_;
}
PipeReceiver<MessageHandle>* outgoing_messages_pipe() const {
return send_message_ == nullptr ? nullptr : send_message_->outgoing_pipe();
}
PipeSender<MessageHandle>* incoming_messages_pipe() const {
return receive_message_ == nullptr ? nullptr
: receive_message_->incoming_pipe();
Pipe<ServerMetadataHandle>* server_initial_metadata_pipe() const {
return server_initial_metadata_pipe_;
}
SendMessage* send_message() const { return send_message_; }
ReceiveMessage* receive_message() const { return receive_message_; }
@ -474,7 +542,7 @@ class BaseCallData : public Activity, private Wakeable {
CallFinalization finalization_;
grpc_call_context_element* const context_;
std::atomic<grpc_polling_entity*> pollent_{nullptr};
Latch<ServerMetadata*>* const server_initial_metadata_latch_;
Pipe<ServerMetadataHandle>* const server_initial_metadata_pipe_;
SendMessage* const send_message_;
ReceiveMessage* const receive_message_;
grpc_event_engine::experimental::EventEngine* event_engine_;
@ -626,6 +694,9 @@ class ServerCallData : public BaseCallData {
// metadata.
kQueuedBehindSendMessage,
// We saw the op, and are waiting for the promise to complete
// to forward it. First however we need to close sends.
kQueuedButHaventClosedSends,
// We saw the op, and are waiting for the promise to complete
// to forward it.
kQueued,
// We've forwarded the op to the next filter.

@ -93,7 +93,7 @@ Slice Slice::FromRefcountAndBytes(grpc_slice_refcount* r, const uint8_t* begin,
const uint8_t* end) {
grpc_slice out;
out.refcount = r;
if (r != grpc_slice_refcount::NoopRefcount()) r->Ref();
if (r != grpc_slice_refcount::NoopRefcount()) r->Ref({});
out.data.refcounted.bytes = const_cast<uint8_t*>(begin);
out.data.refcounted.length = end - begin;
return Slice(out);

@ -48,6 +48,9 @@ const char* const description_promise_based_client_call =
"(ie when all filters in a stack are promise based)";
const char* const description_free_large_allocator =
"If set, return all free bytes from a \042big\042 allocator";
const char* const description_promise_based_server_call =
"If set, use the new gRPC promise based call code when it's appropriate "
"(ie when all filters in a stack are promise based)";
const char* const description_transport_supplies_client_latency =
"If set, use the transport represented value for client latency in "
"opencensus";
@ -71,6 +74,7 @@ const ExperimentMetadata g_experiment_metadata[] = {
{"monitoring_experiment", description_monitoring_experiment, true},
{"promise_based_client_call", description_promise_based_client_call, false},
{"free_large_allocator", description_free_large_allocator, false},
{"promise_based_server_call", description_promise_based_server_call, false},
{"transport_supplies_client_latency",
description_transport_supplies_client_latency, false},
{"event_engine_listener", description_event_engine_listener, false},

@ -40,10 +40,13 @@ inline bool IsEventEngineClientEnabled() { return IsExperimentEnabled(7); }
inline bool IsMonitoringExperimentEnabled() { return IsExperimentEnabled(8); }
inline bool IsPromiseBasedClientCallEnabled() { return IsExperimentEnabled(9); }
inline bool IsFreeLargeAllocatorEnabled() { return IsExperimentEnabled(10); }
inline bool IsTransportSuppliesClientLatencyEnabled() {
inline bool IsPromiseBasedServerCallEnabled() {
return IsExperimentEnabled(11);
}
inline bool IsEventEngineListenerEnabled() { return IsExperimentEnabled(12); }
inline bool IsTransportSuppliesClientLatencyEnabled() {
return IsExperimentEnabled(12);
}
inline bool IsEventEngineListenerEnabled() { return IsExperimentEnabled(13); }
struct ExperimentMetadata {
const char* name;
@ -51,7 +54,7 @@ struct ExperimentMetadata {
bool default_value;
};
constexpr const size_t kNumExperiments = 13;
constexpr const size_t kNumExperiments = 14;
extern const ExperimentMetadata g_experiment_metadata[kNumExperiments];
} // namespace grpc_core

@ -119,6 +119,14 @@
expiry: 2023/04/01
owner: alishananda@google.com
test_tags: [resource_quota_test]
- name: promise_based_server_call
description:
If set, use the new gRPC promise based call code when it's appropriate
(ie when all filters in a stack are promise based)
default: false
expiry: 2023/06/01
owner: ctiller@google.com
test_tags: ["core_end2end_test"]
- name: transport_supplies_client_latency
description:
If set, use the transport represented value for client latency in opencensus

@ -56,9 +56,6 @@ class SourceLocation {
// No-op for non-debug builds.
// Callers can use the DEBUG_LOCATION macro in either case.
#ifndef NDEBUG
// TODO(roth): See if there's a way to automatically populate this,
// similarly to how absl::SourceLocation::current() works, so that
// callers don't need to explicitly pass DEBUG_LOCATION anywhere.
class DebugLocation {
public:
DebugLocation(const char* file = GRPC_DEFAULT_FILE,

@ -116,9 +116,9 @@ void CallCombiner::Start(grpc_closure* closure, grpc_error_handle error,
DEBUG_ARGS const char* reason) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) {
gpr_log(GPR_INFO,
"==> CallCombiner::Start() [%p] closure=%p [" DEBUG_FMT_STR
"==> CallCombiner::Start() [%p] closure=%s [" DEBUG_FMT_STR
"%s] error=%s",
this, closure DEBUG_FMT_ARGS, reason,
this, closure->DebugString().c_str() DEBUG_FMT_ARGS, reason,
StatusToString(error).c_str());
}
size_t prev_size =
@ -176,8 +176,8 @@ void CallCombiner::Stop(DEBUG_ARGS const char* reason) {
internal::StatusMoveFromHeapPtr(closure->error_data.error);
closure->error_data.error = 0;
if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) {
gpr_log(GPR_INFO, " EXECUTING FROM QUEUE: closure=%p error=%s",
closure, StatusToString(error).c_str());
gpr_log(GPR_INFO, " EXECUTING FROM QUEUE: closure=%s error=%s",
closure->DebugString().c_str(), StatusToString(error).c_str());
}
ScheduleClosure(closure, error);
break;

@ -0,0 +1,27 @@
// Copyright 2022 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/closure.h"
#include "absl/strings/str_format.h"
std::string grpc_closure::DebugString() const {
#ifdef NDEBUG
return absl::StrFormat("%p", this);
#else
return absl::StrFormat("%p|created=%s:%d", this, file_created, line_created);
#endif
}

@ -86,6 +86,8 @@ struct grpc_closure {
const char* file_initiated;
int line_initiated;
#endif
std::string DebugString() const;
};
#ifndef NDEBUG

@ -102,6 +102,10 @@ class Waker {
return wakeable_ == other.wakeable_;
}
bool operator!=(const Waker& other) const noexcept {
return wakeable_ != other.wakeable_;
}
std::string ActivityDebugTag() {
return wakeable_ == nullptr ? "<unknown>" : wakeable_->ActivityDebugTag();
}

@ -17,17 +17,24 @@
#include <grpc/support/port_platform.h>
#include <stdint.h>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/types/variant.h"
#include <grpc/support/log.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/construct_destruct.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/detail/promise_factory.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/trace.h"
namespace grpc_core {
@ -101,9 +108,21 @@ class ForEach {
ReaderResult result;
};
std::string DebugTag() {
return absl::StrCat(Activity::current()->DebugTag(), " FOR_EACH[0x",
reinterpret_cast<uintptr_t>(this), "]: ");
}
Poll<Result> PollReaderNext() {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "%s PollReaderNext", DebugTag().c_str());
}
auto r = reader_next_();
if (auto* p = absl::get_if<kPollReadyIdx>(&r)) {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "%s PollReaderNext: got has_value=%s",
DebugTag().c_str(), p->has_value() ? "true" : "false");
}
if (p->has_value()) {
Destruct(&reader_next_);
auto action = action_factory_.Make(std::move(**p));
@ -118,6 +137,9 @@ class ForEach {
}
Poll<Result> PollAction() {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "%s PollAction", DebugTag().c_str());
}
auto r = in_action_.promise();
if (auto* p = absl::get_if<kPollReadyIdx>(&r)) {
if (p->ok()) {

@ -22,6 +22,7 @@
#include "absl/status/statusor.h"
#include "absl/types/variant.h"
#include "src/core/lib/gprpp/construct_destruct.h"
#include "src/core/lib/promise/detail/promise_factory.h"
#include "src/core/lib/promise/detail/promise_like.h"
#include "src/core/lib/promise/poll.h"
@ -116,6 +117,66 @@ class If {
};
};
template <typename T, typename F>
class If<bool, T, F> {
private:
using TrueFactory = promise_detail::OncePromiseFactory<void, T>;
using FalseFactory = promise_detail::OncePromiseFactory<void, F>;
using TruePromise = typename TrueFactory::Promise;
using FalsePromise = typename FalseFactory::Promise;
using Result =
typename PollTraits<decltype(std::declval<TruePromise>()())>::Type;
public:
If(bool condition, T if_true, F if_false) : condition_(condition) {
TrueFactory true_factory(std::move(if_true));
FalseFactory false_factory(std::move(if_false));
if (condition_) {
Construct(&if_true_, true_factory.Make());
} else {
Construct(&if_false_, false_factory.Make());
}
}
~If() {
if (condition_) {
Destruct(&if_true_);
} else {
Destruct(&if_false_);
}
}
If(const If&) = delete;
If& operator=(const If&) = delete;
If(If&& other) noexcept : condition_(other.condition_) {
if (condition_) {
Construct(&if_true_, std::move(other.if_true_));
} else {
Construct(&if_false_, std::move(other.if_false_));
}
}
If& operator=(If&& other) noexcept {
if (&other == this) return *this;
Destruct(this);
Construct(this, std::move(other));
return *this;
}
Poll<Result> operator()() {
if (condition_) {
return if_true_();
} else {
return if_false_();
}
}
private:
bool condition_;
union {
TruePromise if_true_;
FalsePromise if_false_;
};
};
} // namespace promise_detail
// If promise combinator.

@ -0,0 +1,309 @@
// Copyright 2022 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_SRC_CORE_LIB_PROMISE_INTERCEPTOR_LIST_H
#define GRPC_SRC_CORE_LIB_PROMISE_INTERCEPTOR_LIST_H
#include <grpc/support/port_platform.h>
#include <stddef.h>
#include <algorithm>
#include <new>
#include <string>
#include <utility>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
#include <grpc/support/log.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/construct_destruct.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/detail/promise_factory.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/trace.h"
#include "src/core/lib/resource_quota/arena.h"
namespace grpc_core {
// Tracks a list of maps of T -> optional<T> via promises.
// When Run, runs each transformation in order, and resolves to the ulimate
// result.
// If a map resolves to nullopt, the chain is terminated and the result is
// nullopt.
// Maps can also have synchronous cleanup functions, which are guaranteed to be
// called at the termination of each run through the chain.
template <typename T>
class InterceptorList {
private:
// A map of T -> T via promises.
class Map {
public:
explicit Map(DebugLocation from) : from_(from) {}
// Construct a promise to transform x into some other value at memory.
virtual void MakePromise(T x, void* memory) = 0;
// Destroy a promise constructed at memory.
virtual void Destroy(void* memory) = 0;
// Poll a promise constructed at memory.
// Resolves to an optional<T> -- if nullopt it means terminate the chain and
// resolve.
virtual Poll<absl::optional<T>> PollOnce(void* memory) = 0;
virtual ~Map() = default;
// Update the next pointer stored with this map.
// This is only valid to call once, and only before the map is used.
void SetNext(Map* next) {
GPR_DEBUG_ASSERT(next_ == nullptr);
next_ = next;
}
// Access the creation location for this map (for debug tracing).
DebugLocation from() const { return from_; }
// Access the next map in the chain (or nullptr if this is the last map).
Map* next() const { return next_; }
private:
GPR_NO_UNIQUE_ADDRESS const DebugLocation from_;
Map* next_ = nullptr;
};
public:
// The result of Run: a promise that will execute the entire chain.
class RunPromise {
public:
RunPromise(size_t memory_required, Map* factory, absl::optional<T> value) {
if (!value.has_value() || factory == nullptr) {
is_immediately_resolved_ = true;
Construct(&result_, std::move(value));
} else {
is_immediately_resolved_ = false;
Construct(&async_resolution_, memory_required);
factory->MakePromise(std::move(*value), async_resolution_.space.get());
async_resolution_.current_factory = factory;
}
}
~RunPromise() {
if (is_immediately_resolved_) {
Destruct(&result_);
} else {
if (async_resolution_.current_factory != nullptr) {
async_resolution_.current_factory->Destroy(
async_resolution_.space.get());
}
Destruct(&async_resolution_);
}
}
RunPromise(const RunPromise&) = delete;
RunPromise& operator=(const RunPromise&) = delete;
RunPromise(RunPromise&& other) noexcept
: is_immediately_resolved_(other.is_immediately_resolved_) {
if (is_immediately_resolved_) {
Construct(&result_, std::move(other.result_));
} else {
Construct(&async_resolution_, std::move(other.async_resolution_));
}
}
RunPromise& operator=(RunPromise&& other) noexcept = delete;
Poll<absl::optional<T>> operator()() {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "InterceptorList::RunPromise: %s",
DebugString().c_str());
}
if (is_immediately_resolved_) return std::move(result_);
while (true) {
auto r = async_resolution_.current_factory->PollOnce(
async_resolution_.space.get());
if (auto* p = absl::get_if<kPollReadyIdx>(&r)) {
async_resolution_.current_factory->Destroy(
async_resolution_.space.get());
async_resolution_.current_factory =
async_resolution_.current_factory->next();
if (async_resolution_.current_factory == nullptr || !p->has_value()) {
return std::move(*p);
}
async_resolution_.current_factory->MakePromise(
std::move(**p), async_resolution_.space.get());
continue;
}
return Pending{};
}
}
private:
std::string DebugString() const {
if (is_immediately_resolved_) {
return absl::StrFormat("Result:has_value:%d", result_.has_value());
} else {
return absl::StrCat(
"Running:",
async_resolution_.current_factory == nullptr
? "END"
: ([p = async_resolution_.current_factory->from()]() {
return absl::StrCat(p.file(), ":", p.line());
})()
.c_str());
}
}
struct AsyncResolution {
explicit AsyncResolution(size_t max_size)
: space(GetContext<Arena>()->MakePooledArray<char>(max_size)) {}
AsyncResolution(const AsyncResolution&) = delete;
AsyncResolution& operator=(const AsyncResolution&) = delete;
AsyncResolution(AsyncResolution&& other) noexcept
: current_factory(std::exchange(other.current_factory, nullptr)),
space(std::move(other.space)) {}
Map* current_factory;
Arena::PoolPtr<char[]> space;
};
union {
AsyncResolution async_resolution_;
absl::optional<T> result_;
};
// If true, the result_ union is valid, otherwise async_resolution_ is.
// Indicates whether the promise resolved immediately at construction or if
// additional steps were needed.
bool is_immediately_resolved_;
};
InterceptorList() = default;
InterceptorList(const InterceptorList&) = delete;
InterceptorList& operator=(const InterceptorList&) = delete;
~InterceptorList() { DeleteFactories(); }
RunPromise Run(absl::optional<T> initial_value) {
return RunPromise(promise_memory_required_, first_map_,
std::move(initial_value));
}
// Append a new map to the end of the chain.
template <typename Fn>
void AppendMap(Fn fn, DebugLocation from) {
Append(MakeMapToAdd(
std::move(fn), [] {}, from));
}
// Prepend a new map to the beginning of the chain.
template <typename Fn>
void PrependMap(Fn fn, DebugLocation from) {
Prepend(MakeMapToAdd(
std::move(fn), [] {}, from));
}
// Append a new map to the end of the chain, with a cleanup function to be
// called at the end of run promise execution.
template <typename Fn, typename CleanupFn>
void AppendMapWithCleanup(Fn fn, CleanupFn cleanup_fn, DebugLocation from) {
Append(MakeMapToAdd(std::move(fn), std::move(cleanup_fn), from));
}
// Prepend a new map to the beginning of the chain, with a cleanup function to
// be called at the end of run promise execution.
template <typename Fn, typename CleanupFn>
void PrependMapWithCleanup(Fn fn, CleanupFn cleanup_fn, DebugLocation from) {
Prepend(MakeMapToAdd(std::move(fn), std::move(cleanup_fn), from));
}
protected:
// Clear the interceptor list
void ResetInterceptorList() {
DeleteFactories();
first_map_ = nullptr;
last_map_ = nullptr;
promise_memory_required_ = 0;
}
private:
template <typename Fn, typename CleanupFn>
class MapImpl final : public Map {
public:
using PromiseFactory = promise_detail::RepeatedPromiseFactory<T, Fn>;
using Promise = typename PromiseFactory::Promise;
explicit MapImpl(Fn fn, CleanupFn cleanup_fn, DebugLocation from)
: Map(from), fn_(std::move(fn)), cleanup_fn_(std::move(cleanup_fn)) {}
~MapImpl() override { cleanup_fn_(); }
void MakePromise(T x, void* memory) override {
new (memory) Promise(fn_.Make(std::move(x)));
}
void Destroy(void* memory) override {
static_cast<Promise*>(memory)->~Promise();
}
Poll<absl::optional<T>> PollOnce(void* memory) override {
return poll_cast<absl::optional<T>>((*static_cast<Promise*>(memory))());
}
private:
GPR_NO_UNIQUE_ADDRESS PromiseFactory fn_;
GPR_NO_UNIQUE_ADDRESS CleanupFn cleanup_fn_;
};
template <typename Fn, typename CleanupFn>
Map* MakeMapToAdd(Fn fn, CleanupFn cleanup_fn, DebugLocation from) {
using FactoryType = MapImpl<Fn, CleanupFn>;
promise_memory_required_ = std::max(promise_memory_required_,
sizeof(typename FactoryType::Promise));
return GetContext<Arena>()->New<FactoryType>(std::move(fn),
std::move(cleanup_fn), from);
}
void Append(Map* f) {
if (first_map_ == nullptr) {
first_map_ = f;
last_map_ = f;
} else {
last_map_->SetNext(f);
last_map_ = f;
}
}
void Prepend(Map* f) {
if (first_map_ == nullptr) {
first_map_ = f;
last_map_ = f;
} else {
f->SetNext(first_map_);
first_map_ = f;
}
}
void DeleteFactories() {
for (auto* f = first_map_; f != nullptr;) {
auto* next = f->next();
f->~Map();
f = next;
}
}
// The first map in the chain.
Map* first_map_ = nullptr;
// The last map in the chain.
Map* last_map_ = nullptr;
// The amount of memory required to store the largest promise in the chain.
size_t promise_memory_required_ = 0;
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_PROMISE_INTERCEPTOR_LIST_H

@ -17,6 +17,8 @@
#include <grpc/support/port_platform.h>
#include <string>
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/poll.h"
@ -40,6 +42,10 @@ class IntraActivityWaiter {
}
}
std::string DebugString() const {
return waiting_ ? "WAITING" : "NOT_WAITING";
}
private:
bool waiting_ = false;
};

@ -17,12 +17,21 @@
#include <grpc/support/port_platform.h>
#include <stdint.h>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/strings/str_cat.h"
#include <grpc/support/log.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/intra_activity_waiter.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/trace.h"
namespace grpc_core {
@ -56,9 +65,13 @@ class Latch {
#ifndef NDEBUG
has_had_waiters_ = true;
#endif
return [this]() -> Poll<T*> {
return [this]() -> Poll<T> {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%sPollWait %s", DebugTag().c_str(),
StateString().c_str());
}
if (has_value_) {
return &value_;
return std::move(value_);
} else {
return waiter_.pending();
}
@ -67,6 +80,9 @@ class Latch {
// Set the value of the latch. Can only be called once.
void Set(T value) {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%sSet %s", DebugTag().c_str(), StateString().c_str());
}
GPR_DEBUG_ASSERT(!has_value_);
value_ = std::move(value);
has_value_ = true;
@ -74,6 +90,16 @@ class Latch {
}
private:
std::string DebugTag() {
return absl::StrCat(Activity::current()->DebugTag(), " LATCH[0x",
reinterpret_cast<uintptr_t>(this), "]: ");
}
std::string StateString() {
return absl::StrCat("has_value:", has_value_ ? "true" : "false",
" waiter:", waiter_.DebugString());
}
// The value stored (if has_value_ is true), otherwise some random value, we
// don't care.
// Why not absl::optional<>? Writing things this way lets us compress

@ -19,10 +19,15 @@
#include "absl/status/status.h"
#include <grpc/support/log.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/promise/detail/promise_factory.h"
#include "src/core/lib/promise/for_each.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/trace.h"
#include "src/core/lib/promise/try_seq.h"
namespace grpc_core {
@ -40,14 +45,25 @@ auto MapPipe(PipeReceiver<T> src, PipeSender<T> dst, Filter filter_factory) {
[filter_factory = promise_detail::RepeatedPromiseFactory<T, Filter>(
std::move(filter_factory)),
dst = std::move(dst)](T t) mutable {
return TrySeq(filter_factory.Make(std::move(t)), [&dst](T t) {
return Map(dst.Push(std::move(t)), [](bool successful_push) {
if (successful_push) {
return absl::OkStatus();
}
return absl::CancelledError();
});
});
return TrySeq(
[] {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "MapPipe: start map");
}
return Empty{};
},
filter_factory.Make(std::move(t)),
[&dst](T t) {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "MapPipe: start push");
}
return Map(dst.Push(std::move(t)), [](bool successful_push) {
if (successful_push) {
return absl::OkStatus();
}
return absl::CancelledError();
});
});
});
}

@ -18,10 +18,15 @@
#include <grpc/support/port_platform.h>
#include <stdint.h>
#include <stdlib.h>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
@ -29,14 +34,19 @@
#include <grpc/support/log.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/if.h"
#include "src/core/lib/promise/interceptor_list.h"
#include "src/core/lib/promise/intra_activity_waiter.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/seq.h"
#include "src/core/lib/promise/trace.h"
#include "src/core/lib/resource_quota/arena.h"
extern grpc_core::DebugOnlyTraceFlag grpc_trace_promise_pipe;
namespace grpc_core {
namespace pipe_detail {
@ -56,21 +66,24 @@ struct Pipe;
template <typename T>
class NextResult final {
public:
explicit NextResult(pipe_detail::Center<T>* center) : center_(center) {}
NextResult() : center_(nullptr) {}
explicit NextResult(RefCountedPtr<pipe_detail::Center<T>> center)
: center_(std::move(center)) {
GPR_ASSERT(center_ != nullptr);
}
explicit NextResult(bool cancelled)
: center_(nullptr), cancelled_(cancelled) {}
~NextResult();
NextResult(const NextResult&) = delete;
NextResult& operator=(const NextResult&) = delete;
NextResult(NextResult&& other) noexcept
: center_(std::exchange(other.center_, nullptr)) {}
NextResult& operator=(NextResult&& other) noexcept {
center_ = std::exchange(other.center_, nullptr);
return *this;
}
NextResult(NextResult&& other) noexcept = default;
NextResult& operator=(NextResult&& other) noexcept = default;
using value_type = T;
void reset();
bool has_value() const;
// Only valid if has_value()
const T& value() const {
GPR_ASSERT(has_value());
return **this;
@ -81,9 +94,12 @@ class NextResult final {
}
const T& operator*() const;
T& operator*();
// Only valid if !has_value()
bool cancelled() { return cancelled_; }
private:
pipe_detail::Center<T>* center_;
RefCountedPtr<pipe_detail::Center<T>> center_;
bool cancelled_;
};
namespace pipe_detail {
@ -96,71 +112,39 @@ class Next;
// Center sits between a sender and a receiver to provide a one-deep buffer of
// Ts
template <typename T>
class Center {
class Center : public InterceptorList<T> {
public:
// Initialize with one send ref (held by PipeSender) and one recv ref (held by
// PipeReceiver)
Center() {
send_refs_ = 1;
recv_refs_ = 1;
refs_ = 2;
value_state_ = ValueState::kEmpty;
}
// Add one ref to the send side of this object, and return this.
Center* RefSend() {
if (grpc_trace_promise_pipe.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("RefSend").c_str());
}
send_refs_++;
GPR_ASSERT(send_refs_ != 0);
return this;
}
// Add one ref to the recv side of this object, and return this.
Center* RefRecv() {
if (grpc_trace_promise_pipe.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("RefRecv").c_str());
// Add one ref to this object, and return this.
void IncrementRefCount() {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "%s", DebugOpString("IncrementRefCount").c_str());
}
recv_refs_++;
GPR_ASSERT(recv_refs_ != 0);
return this;
refs_++;
GPR_DEBUG_ASSERT(refs_ != 0);
}
// Drop a send side ref
// If no send refs remain, wake due to send closure
// If no refs remain, destroy this object
void UnrefSend() {
if (grpc_trace_promise_pipe.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("UnrefSend").c_str());
}
GPR_DEBUG_ASSERT(send_refs_ > 0);
send_refs_--;
if (0 == send_refs_) {
on_full_.Wake();
on_empty_.Wake();
if (0 == recv_refs_) {
this->~Center();
}
}
RefCountedPtr<Center> Ref() {
IncrementRefCount();
return RefCountedPtr<Center>(this);
}
// Drop a recv side ref
// If no recv refs remain, wake due to recv closure
// Drop a ref
// If no refs remain, destroy this object
void UnrefRecv() {
if (grpc_trace_promise_pipe.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("UnrefRecv").c_str());
void Unref() {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "%s", DebugOpString("Unref").c_str());
}
GPR_DEBUG_ASSERT(recv_refs_ > 0);
recv_refs_--;
if (0 == recv_refs_) {
on_full_.Wake();
on_empty_.Wake();
if (0 == send_refs_) {
this->~Center();
} else if (value_state_ == ValueState::kReady) {
ResetValue();
}
GPR_DEBUG_ASSERT(refs_ > 0);
refs_--;
if (0 == refs_) {
this->~Center();
}
}
@ -169,26 +153,45 @@ class Center {
// Return true if the value was pushed.
// Return false if the recv end is closed.
Poll<bool> Push(T* value) {
if (grpc_trace_promise_pipe.enabled()) {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("Push").c_str());
}
GPR_DEBUG_ASSERT(send_refs_ != 0);
if (recv_refs_ == 0) return false;
if (value_state_ != ValueState::kEmpty) return on_empty_.pending();
value_state_ = ValueState::kReady;
value_ = std::move(*value);
on_full_.Wake();
return true;
GPR_DEBUG_ASSERT(refs_ != 0);
switch (value_state_) {
case ValueState::kClosed:
case ValueState::kReadyClosed:
case ValueState::kCancelled:
return false;
case ValueState::kReady:
case ValueState::kAcked:
return on_empty_.pending();
case ValueState::kEmpty:
value_state_ = ValueState::kReady;
value_ = std::move(*value);
on_full_.Wake();
return true;
}
GPR_UNREACHABLE_CODE(return false);
}
Poll<bool> PollAck() {
if (grpc_trace_promise_pipe.enabled()) {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("PollAck").c_str());
}
GPR_DEBUG_ASSERT(send_refs_ != 0);
if (recv_refs_ == 0) return value_state_ == ValueState::kAcked;
if (value_state_ != ValueState::kAcked) return on_empty_.pending();
value_state_ = ValueState::kEmpty;
GPR_DEBUG_ASSERT(refs_ != 0);
switch (value_state_) {
case ValueState::kClosed:
case ValueState::kReadyClosed:
case ValueState::kCancelled:
return false;
case ValueState::kReady:
case ValueState::kEmpty:
return on_empty_.pending();
case ValueState::kAcked:
value_state_ = ValueState::kEmpty;
on_empty_.Wake();
return true;
}
return true;
}
@ -196,47 +199,107 @@ class Center {
// Return Pending if there is no value.
// Return the value if one was retrieved.
// Return nullopt if the send end is closed and no value had been pushed.
Poll<NextResult<T>> Next() {
if (grpc_trace_promise_pipe.enabled()) {
Poll<absl::optional<T>> Next() {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("Next").c_str());
}
GPR_DEBUG_ASSERT(recv_refs_ != 0);
if (value_state_ != ValueState::kReady) {
if (send_refs_ == 0) return NextResult<T>(nullptr);
return on_full_.pending();
GPR_DEBUG_ASSERT(refs_ != 0);
switch (value_state_) {
case ValueState::kEmpty:
case ValueState::kAcked:
return on_full_.pending();
case ValueState::kReadyClosed:
this->ResetInterceptorList();
value_state_ = ValueState::kClosed;
ABSL_FALLTHROUGH_INTENDED;
case ValueState::kReady:
return std::move(value_);
case ValueState::kClosed:
case ValueState::kCancelled:
return absl::nullopt;
}
return NextResult<T>(RefRecv());
GPR_UNREACHABLE_CODE(return absl::nullopt);
}
void AckNext() {
if (grpc_trace_promise_pipe.enabled()) {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("AckNext").c_str());
}
GPR_DEBUG_ASSERT(value_state_ == ValueState::kReady);
value_state_ = ValueState::kAcked;
on_empty_.Wake();
UnrefRecv();
switch (value_state_) {
case ValueState::kReady:
value_state_ = ValueState::kAcked;
on_empty_.Wake();
break;
case ValueState::kReadyClosed:
this->ResetInterceptorList();
value_state_ = ValueState::kClosed;
break;
case ValueState::kClosed:
case ValueState::kCancelled:
break;
case ValueState::kEmpty:
case ValueState::kAcked:
abort();
}
}
void MarkClosed() {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("MarkClosed").c_str());
}
switch (value_state_) {
case ValueState::kEmpty:
case ValueState::kAcked:
this->ResetInterceptorList();
value_state_ = ValueState::kClosed;
on_full_.Wake();
break;
case ValueState::kReady:
value_state_ = ValueState::kReadyClosed;
break;
case ValueState::kReadyClosed:
case ValueState::kClosed:
case ValueState::kCancelled:
break;
}
}
void MarkCancelled() {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_INFO, "%s", DebugOpString("MarkCancelled").c_str());
}
switch (value_state_) {
case ValueState::kEmpty:
case ValueState::kAcked:
case ValueState::kReady:
case ValueState::kReadyClosed:
this->ResetInterceptorList();
value_state_ = ValueState::kCancelled;
on_full_.Wake();
break;
case ValueState::kClosed:
value_state_ = ValueState::kCancelled;
break;
case ValueState::kCancelled:
break;
}
}
bool cancelled() { return value_state_ == ValueState::kCancelled; }
T& value() { return value_; }
const T& value() const { return value_; }
private:
std::string DebugTag() {
return absl::StrCat(Activity::current()->DebugTag(), "PIPE[0x",
reinterpret_cast<uintptr_t>(this), "]: ");
}
std::string DebugOpString(std::string op) {
return absl::StrCat(DebugTag(), op, " send_refs=", send_refs_,
" recv_refs=", recv_refs_,
" value_state=", ValueStateName(value_state_));
}
void ResetValue() {
// Fancy dance to move out of value in the off chance that we reclaim some
// memory earlier.
[](T) {}(std::move(value_));
value_state_ = ValueState::kEmpty;
if (auto* activity = Activity::current()) {
return absl::StrCat(activity->DebugTag(), " PIPE[0x",
reinterpret_cast<uintptr_t>(this), "]: ");
} else {
return absl::StrCat("PIPE[0x", reinterpret_cast<uintptr_t>(this), "]: ");
}
}
private:
// State of value_.
enum class ValueState : uint8_t {
// No value is set, it's possible to send.
@ -246,31 +309,52 @@ class Center {
// Value has been received and acked, we can unblock senders and transition
// to empty.
kAcked,
// Pipe is closed successfully, no more values can be sent
kClosed,
// Pipe is closed successfully, no more values can be sent
// (but one value is queued and ready to be received)
kReadyClosed,
// Pipe is closed unsuccessfully, no more values can be sent
kCancelled,
};
std::string DebugOpString(std::string op) {
return absl::StrCat(DebugTag(), op, " refs=", refs_,
" value_state=", ValueStateName(value_state_),
" on_empty=", on_empty_.DebugString().c_str(),
" on_full=", on_full_.DebugString().c_str());
}
static const char* ValueStateName(ValueState state) {
switch (state) {
case ValueState::kEmpty:
return "kEmpty";
return "Empty";
case ValueState::kReady:
return "kReady";
return "Ready";
case ValueState::kAcked:
return "kAcked";
return "Acked";
case ValueState::kClosed:
return "Closed";
case ValueState::kReadyClosed:
return "ReadyClosed";
case ValueState::kCancelled:
return "Cancelled";
}
GPR_UNREACHABLE_CODE(return "unknown");
}
T value_;
// Number of sending objects.
// 0 => send is closed.
// 1 ref each for PipeSender and Push.
uint8_t send_refs_ : 2;
// Number of receiving objects.
// 0 => recv is closed.
// 1 ref each for PipeReceiver, Next, and NextResult.
uint8_t recv_refs_ : 2;
// Number of refs
uint8_t refs_;
// Current state of the value.
ValueState value_state_ : 2;
ValueState value_state_;
IntraActivityWaiter on_empty_;
IntraActivityWaiter on_full_;
// Make failure to destruct show up in ASAN builds.
#ifndef NDEBUG
std::unique_ptr<int> asan_canary_ = absl::make_unique<int>(0);
#endif
};
} // namespace pipe_detail
@ -283,23 +367,18 @@ class PipeSender {
PipeSender(const PipeSender&) = delete;
PipeSender& operator=(const PipeSender&) = delete;
PipeSender(PipeSender&& other) noexcept : center_(other.center_) {
other.center_ = nullptr;
}
PipeSender& operator=(PipeSender&& other) noexcept {
if (center_ != nullptr) center_->UnrefSend();
center_ = other.center_;
other.center_ = nullptr;
return *this;
}
PipeSender(PipeSender&& other) noexcept = default;
PipeSender& operator=(PipeSender&& other) noexcept = default;
~PipeSender() {
if (center_ != nullptr) center_->UnrefSend();
if (center_ != nullptr) center_->MarkClosed();
}
void Close() {
if (auto* center = std::exchange(center_, nullptr)) center->UnrefSend();
if (center_ != nullptr) {
center_->MarkClosed();
center_.reset();
}
}
void Swap(PipeSender<T>* other) { std::swap(center_, other->center_); }
@ -310,32 +389,37 @@ class PipeSender {
// receiver is either closed or able to receive another message.
PushType Push(T value);
template <typename Fn>
void InterceptAndMap(Fn f, DebugLocation from = {}) {
center_->PrependMap(std::move(f), from);
}
template <typename Fn, typename OnHalfClose>
void InterceptAndMap(Fn f, OnHalfClose cleanup_fn, DebugLocation from = {}) {
center_->PrependMapWithCleanup(std::move(f), std::move(cleanup_fn), from);
}
private:
friend struct Pipe<T>;
explicit PipeSender(pipe_detail::Center<T>* center) : center_(center) {}
pipe_detail::Center<T>* center_;
RefCountedPtr<pipe_detail::Center<T>> center_;
// Make failure to destruct show up in ASAN builds.
#ifndef NDEBUG
std::unique_ptr<int> asan_canary_ = absl::make_unique<int>(0);
#endif
};
// Receive end of a Pipe.
template <typename T>
class PipeReceiver {
public:
using NextType = pipe_detail::Next<T>;
PipeReceiver(const PipeReceiver&) = delete;
PipeReceiver& operator=(const PipeReceiver&) = delete;
PipeReceiver(PipeReceiver&& other) noexcept : center_(other.center_) {
other.center_ = nullptr;
}
PipeReceiver& operator=(PipeReceiver&& other) noexcept {
if (center_ != nullptr) center_->UnrefRecv();
center_ = other.center_;
other.center_ = nullptr;
return *this;
}
PipeReceiver(PipeReceiver&& other) noexcept = default;
PipeReceiver& operator=(PipeReceiver&& other) noexcept = default;
~PipeReceiver() {
if (center_ != nullptr) center_->UnrefRecv();
if (center_ != nullptr) center_->MarkClosed();
}
void Swap(PipeReceiver<T>* other) { std::swap(center_, other->center_); }
@ -345,12 +429,28 @@ class PipeReceiver {
// message was received, or no value if the other end of the pipe was closed.
// Blocks the promise until the receiver is either closed or a message is
// available.
NextType Next();
auto Next();
template <typename Fn>
void InterceptAndMap(Fn f, DebugLocation from = {}) {
center_->AppendMap(std::move(f), from);
}
template <typename Fn, typename OnHalfClose>
void InterceptAndMapWithHalfClose(Fn f, OnHalfClose cleanup_fn,
DebugLocation from = {}) {
center_->AppendMapWithCleanup(std::move(f), std::move(cleanup_fn), from);
}
private:
friend struct Pipe<T>;
explicit PipeReceiver(pipe_detail::Center<T>* center) : center_(center) {}
pipe_detail::Center<T>* center_;
RefCountedPtr<pipe_detail::Center<T>> center_;
// Make failure to destruct show up in ASAN builds.
#ifndef NDEBUG
std::unique_ptr<int> asan_canary_ = absl::make_unique<int>(0);
#endif
};
namespace pipe_detail {
@ -361,42 +461,33 @@ class Push {
public:
Push(const Push&) = delete;
Push& operator=(const Push&) = delete;
Push(Push&& other) noexcept
: center_(other.center_), push_(std::move(other.push_)) {
other.center_ = nullptr;
}
Push& operator=(Push&& other) noexcept {
if (center_ != nullptr) center_->UnrefSend();
center_ = other.center_;
other.center_ = nullptr;
push_ = std::move(other.push_);
return *this;
}
~Push() {
if (center_ != nullptr) center_->UnrefSend();
}
Push(Push&& other) noexcept = default;
Push& operator=(Push&& other) noexcept = default;
Poll<bool> operator()() {
if (push_.has_value()) {
auto r = center_->Push(&*push_);
if (center_ == nullptr) return false;
if (auto* p = absl::get_if<T>(&state_)) {
auto r = center_->Push(p);
if (auto* ok = absl::get_if<bool>(&r)) {
push_.reset();
state_.template emplace<AwaitingAck>();
if (!*ok) return false;
} else {
return Pending{};
}
}
GPR_DEBUG_ASSERT(!push_.has_value());
GPR_DEBUG_ASSERT(absl::holds_alternative<AwaitingAck>(state_));
return center_->PollAck();
}
private:
struct AwaitingAck {};
friend class PipeSender<T>;
explicit Push(pipe_detail::Center<T>* center, T push)
: center_(center), push_(std::move(push)) {}
Center<T>* center_;
absl::optional<T> push_;
explicit Push(RefCountedPtr<pipe_detail::Center<T>> center, T push)
: center_(std::move(center)), state_(std::move(push)) {}
RefCountedPtr<Center<T>> center_;
absl::variant<T, AwaitingAck> state_;
};
// Implementation of PipeReceiver::Next promise.
@ -405,46 +496,56 @@ class Next {
public:
Next(const Next&) = delete;
Next& operator=(const Next&) = delete;
Next(Next&& other) noexcept : center_(other.center_) {
other.center_ = nullptr;
}
Next& operator=(Next&& other) noexcept {
if (center_ != nullptr) center_->UnrefRecv();
center_ = other.center_;
other.center_ = nullptr;
return *this;
}
Next(Next&& other) noexcept = default;
Next& operator=(Next&& other) noexcept = default;
~Next() {
if (center_ != nullptr) center_->UnrefRecv();
}
Poll<NextResult<T>> operator()() {
auto r = center_->Next();
if (!absl::holds_alternative<Pending>(r)) {
std::exchange(center_, nullptr)->UnrefRecv();
}
return r;
}
Poll<absl::optional<T>> operator()() { return center_->Next(); }
private:
friend class PipeReceiver<T>;
explicit Next(pipe_detail::Center<T>* center) : center_(center) {}
Center<T>* center_;
explicit Next(RefCountedPtr<Center<T>> center) : center_(std::move(center)) {}
RefCountedPtr<Center<T>> center_;
};
} // namespace pipe_detail
template <typename T>
pipe_detail::Push<T> PipeSender<T>::Push(T value) {
return pipe_detail::Push<T>(center_->RefSend(), std::move(value));
return pipe_detail::Push<T>(center_ == nullptr ? nullptr : center_->Ref(),
std::move(value));
}
template <typename T>
pipe_detail::Next<T> PipeReceiver<T>::Next() {
return pipe_detail::Next<T>(center_->RefRecv());
auto PipeReceiver<T>::Next() {
return Seq(
pipe_detail::Next<T>(center_->Ref()),
[center = center_->Ref()](absl::optional<T> value) {
bool open = value.has_value();
bool cancelled = center->cancelled();
return If(
open,
[center = std::move(center), value = std::move(value)]() mutable {
auto run_interceptors = center->Run(std::move(value));
return Map(std::move(run_interceptors),
[center = std::move(center)](
absl::optional<T> value) mutable {
if (value.has_value()) {
center->value() = std::move(*value);
return NextResult<T>(std::move(center));
} else {
center->MarkCancelled();
return NextResult<T>(true);
}
});
},
[cancelled]() { return NextResult<T>(cancelled); });
});
}
template <typename T>
using PipeReceiverNextType = decltype(std::declval<PipeReceiver<T>>().Next());
template <typename T>
bool NextResult<T>::has_value() const {
return center_ != nullptr;
@ -467,7 +568,10 @@ NextResult<T>::~NextResult() {
template <typename T>
void NextResult<T>::reset() {
if (auto* p = std::exchange(center_, nullptr)) p->AckNext();
if (center_ != nullptr) {
center_->AckNext();
center_.reset();
}
}
// A Pipe is an intra-Activity communications channel that transmits T's from

@ -14,6 +14,7 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/trace.h"
grpc_core::DebugOnlyTraceFlag grpc_trace_promise_pipe(false, "promise_pipe");
grpc_core::DebugOnlyTraceFlag grpc_trace_promise_primitives(
false, "promise_primitives");

@ -0,0 +1,24 @@
// Copyright 2022 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_SRC_CORE_LIB_PROMISE_TRACE_H
#define GRPC_SRC_CORE_LIB_PROMISE_TRACE_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/debug/trace.h"
extern grpc_core::DebugOnlyTraceFlag grpc_trace_promise_primitives;
#endif // GRPC_SRC_CORE_LIB_PROMISE_TRACE_H

@ -20,17 +20,22 @@
#include <stddef.h>
#include <cstdint>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/strings/str_cat.h"
#include "absl/types/variant.h"
#include <grpc/support/log.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/construct_destruct.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/detail/promise_like.h"
#include "src/core/lib/promise/detail/status.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/trace.h"
namespace grpc_core {
@ -185,9 +190,18 @@ class TryConcurrently {
typename PollTraits<decltype(std::declval<PromiseLike<Main>>()())>::Type;
Poll<Result> operator()() {
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "%sBEGIN POLL: done_bits=%x necessary_bits=%x",
DebugTag().c_str(), done_bits_, NecessaryBits());
}
auto r = pre_main_.template Run<Result, 1>(done_bits_);
if (auto* status = absl::get_if<Result>(&r)) {
GPR_DEBUG_ASSERT(!IsStatusOk(*status));
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG,
"%sFAIL POLL PRE-MAIN: done_bits=%x necessary_bits=%x",
DebugTag().c_str(), done_bits_, NecessaryBits());
}
return std::move(*status);
}
if ((done_bits_ & 1) == 0) {
@ -201,8 +215,17 @@ class TryConcurrently {
r = post_main_.template Run<Result, 1 + PreMain::Size()>(done_bits_);
if (auto* status = absl::get_if<Result>(&r)) {
GPR_DEBUG_ASSERT(!IsStatusOk(*status));
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG,
"%sFAIL POLL POST-MAIN: done_bits=%x necessary_bits=%x",
DebugTag().c_str(), done_bits_, NecessaryBits());
}
return std::move(*status);
}
if (grpc_trace_promise_primitives.enabled()) {
gpr_log(GPR_DEBUG, "%sEND POLL: done_bits=%x necessary_bits=%x",
DebugTag().c_str(), done_bits_, NecessaryBits());
}
if ((done_bits_ & NecessaryBits()) == NecessaryBits()) {
return std::move(result_);
}
@ -234,6 +257,11 @@ class TryConcurrently {
// that is all promises that are not the main one.
constexpr uint8_t HelperBits() { return AllBits() ^ 1; }
std::string DebugTag() {
return absl::StrCat(Activity::current()->DebugTag(), " TRY_CONCURRENTLY[0x",
reinterpret_cast<uintptr_t>(this), "]: ");
}
// done_bits signifies which operations have completed.
// Bit 0 is set if main_ has completed.
// The next higher bits correspond one per pre-main promise.

@ -30,6 +30,7 @@
#include <stddef.h>
#include <atomic>
#include <limits>
#include <memory>
#include <new>
#include <utility>
@ -48,6 +49,11 @@ namespace grpc_core {
namespace arena_detail {
struct PoolAndSize {
size_t alloc_size;
size_t pool_index;
};
template <typename Void, size_t kIndex, size_t kObjectSize,
size_t... kBucketSize>
struct PoolIndexForSize;
@ -81,10 +87,37 @@ constexpr size_t AllocationSizeFromObjectSize(
return PoolIndexForSize<void, 0, kObjectSize, kBucketSizes...>::kSize;
}
template <size_t kIndex, size_t... kBucketSizes>
struct ChoosePoolForAllocationSizeImpl;
template <size_t kIndex, size_t kBucketSize, size_t... kBucketSizes>
struct ChoosePoolForAllocationSizeImpl<kIndex, kBucketSize, kBucketSizes...> {
static PoolAndSize Fn(size_t n) {
if (n <= kBucketSize) return {kBucketSize, kIndex};
return ChoosePoolForAllocationSizeImpl<kIndex + 1, kBucketSizes...>::Fn(n);
}
};
template <size_t kIndex>
struct ChoosePoolForAllocationSizeImpl<kIndex> {
static PoolAndSize Fn(size_t n) {
return PoolAndSize{n, std::numeric_limits<size_t>::max()};
}
};
template <size_t... kBucketSizes>
PoolAndSize ChoosePoolForAllocationSize(
size_t n, absl::integer_sequence<size_t, kBucketSizes...>) {
return ChoosePoolForAllocationSizeImpl<0, kBucketSizes...>::Fn(n);
}
} // namespace arena_detail
class Arena {
using PoolSizes = absl::integer_sequence<size_t, 256, 512, 768>;
struct FreePoolNode {
FreePoolNode* next;
};
public:
// Create an arena, with \a initial_size bytes in the first allocated buffer.
@ -133,7 +166,8 @@ class Arena {
class PooledDeleter {
public:
explicit PooledDeleter(Arena* arena) : arena_(arena) {}
explicit PooledDeleter(std::atomic<FreePoolNode*>* free_list)
: free_list_(free_list) {}
PooledDeleter() = default;
template <typename T>
void operator()(T* p) {
@ -142,24 +176,57 @@ class Arena {
// by setting the arena to nullptr.
// This is a transitional hack and should be removed once promise based
// filter is removed.
if (arena_ != nullptr) arena_->DeletePooled(p);
if (free_list_ != nullptr) {
p->~T();
FreePooled(p, free_list_);
}
}
bool has_freelist() const { return free_list_ != nullptr; }
private:
Arena* arena_;
std::atomic<FreePoolNode*>* free_list_;
};
template <typename T>
using PoolPtr = std::unique_ptr<T, PooledDeleter>;
// Make a unique_ptr to T that is allocated from the arena.
// When the pointer is released, the memory may be reused for other
// MakePooled(.*) calls.
// CAUTION: The amount of memory allocated is rounded up to the nearest
// value in Arena::PoolSizes, and so this may pessimize total
// arena size.
template <typename T, typename... Args>
PoolPtr<T> MakePooled(Args&&... args) {
auto* free_list =
&pools_[arena_detail::PoolFromObjectSize<sizeof(T)>(PoolSizes())];
return PoolPtr<T>(
new (AllocPooled(
arena_detail::AllocationSizeFromObjectSize<sizeof(T)>(PoolSizes()),
&pools_[arena_detail::PoolFromObjectSize<sizeof(T)>(PoolSizes())]))
T(std::forward<Args>(args)...),
PooledDeleter(this));
free_list)) T(std::forward<Args>(args)...),
PooledDeleter(free_list));
}
// Make a unique_ptr to an array of T that is allocated from the arena.
// When the pointer is released, the memory may be reused for other
// MakePooled(.*) calls.
// One can use MakePooledArray<char> to allocate a buffer of bytes.
// CAUTION: The amount of memory allocated is rounded up to the nearest
// value in Arena::PoolSizes, and so this may pessimize total
// arena size.
template <typename T>
PoolPtr<T[]> MakePooledArray(size_t n) {
auto where =
arena_detail::ChoosePoolForAllocationSize(n * sizeof(T), PoolSizes());
if (where.pool_index == std::numeric_limits<size_t>::max()) {
return PoolPtr<T[]>(new (Alloc(where.alloc_size)) T[n],
PooledDeleter(nullptr));
} else {
return PoolPtr<T[]>(
new (AllocPooled(where.alloc_size, &pools_[where.pool_index])) T[n],
PooledDeleter(&pools_[where.pool_index]));
}
}
private:
@ -202,17 +269,6 @@ class Arena {
void* AllocZone(size_t size);
template <typename T>
void DeletePooled(T* p) {
p->~T();
FreePooled(
p, &pools_[arena_detail::PoolFromObjectSize<sizeof(T)>(PoolSizes())]);
}
struct FreePoolNode {
FreePoolNode* next;
};
void* AllocPooled(size_t alloc_size, std::atomic<FreePoolNode*>* head);
static void FreePooled(void* p, std::atomic<FreePoolNode*>* head);

@ -283,7 +283,7 @@ grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
subset = grpc_slice_sub_no_ref(source, begin, end);
// Bump the refcount
if (subset.refcount != grpc_slice_refcount::NoopRefcount()) {
subset.refcount->Ref();
subset.refcount->Ref({});
}
}
return subset;
@ -332,7 +332,7 @@ grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* source, size_t split,
tail.refcount = source->refcount;
// Bump the refcount
if (tail.refcount != grpc_slice_refcount::NoopRefcount()) {
tail.refcount->Ref();
tail.refcount->Ref({});
}
break;
}
@ -378,7 +378,7 @@ grpc_slice grpc_slice_split_head(grpc_slice* source, size_t split) {
head.refcount = source->refcount;
// Bump the refcount
if (head.refcount != grpc_slice_refcount::NoopRefcount()) {
head.refcount->Ref();
head.refcount->Ref({});
}
// Point into the source array
head.data.refcounted.bytes = source->data.refcounted.bytes;

@ -31,6 +31,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_refcount.h"
@ -54,16 +55,17 @@
namespace grpc_core {
inline const grpc_slice& CSliceRef(const grpc_slice& slice) {
inline const grpc_slice& CSliceRef(const grpc_slice& slice,
DebugLocation loc = {}) {
if (reinterpret_cast<uintptr_t>(slice.refcount) > 1) {
slice.refcount->Ref();
slice.refcount->Ref(loc);
}
return slice;
}
inline void CSliceUnref(const grpc_slice& slice) {
inline void CSliceUnref(const grpc_slice& slice, DebugLocation loc = {}) {
if (reinterpret_cast<uintptr_t>(slice.refcount) > 1) {
slice.refcount->Unref();
slice.refcount->Unref(loc);
}
}
@ -391,10 +393,11 @@ class GPR_MSVC_EMPTY_BASE_CLASS_WORKAROUND Slice
Slice Copy() const { return Slice(grpc_slice_copy(c_slice())); }
static Slice FromRefcountAndBytes(grpc_slice_refcount* r,
const uint8_t* begin, const uint8_t* end) {
const uint8_t* begin, const uint8_t* end,
DebugLocation location = {}) {
grpc_slice out;
out.refcount = r;
if (r != grpc_slice_refcount::NoopRefcount()) r->Ref();
if (r != grpc_slice_refcount::NoopRefcount()) r->Ref(location);
out.data.refcounted.bytes = const_cast<uint8_t*>(begin);
out.data.refcounted.length = end - begin;
return Slice(out);

@ -20,8 +20,11 @@
#include <stdint.h>
#include <string.h>
#include <memory>
#include <string>
#include "absl/memory/memory.h"
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
@ -151,6 +154,11 @@ class SliceBuffer {
private:
/// The backing raw slice buffer.
grpc_slice_buffer slice_buffer_;
// Make failure to destruct show up in ASAN builds.
#ifndef NDEBUG
std::unique_ptr<int> asan_canary_ = absl::make_unique<int>(0);
#endif
};
} // namespace grpc_core

@ -0,0 +1,20 @@
// 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/slice/slice_refcount.h"
grpc_core::DebugOnlyTraceFlag grpc_slice_refcount_trace(false,
"slice_refcount");

@ -17,10 +17,18 @@
#include <grpc/support/port_platform.h>
#include <inttypes.h>
#include <stddef.h>
#include <atomic>
#include <grpc/support/log.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/debug_location.h"
extern grpc_core::DebugOnlyTraceFlag grpc_slice_refcount_trace;
// grpc_slice_refcount : A reference count for grpc_slice.
struct grpc_slice_refcount {
public:
@ -40,9 +48,21 @@ struct grpc_slice_refcount {
explicit grpc_slice_refcount(DestroyerFn destroyer_fn)
: destroyer_fn_(destroyer_fn) {}
void Ref() { ref_.fetch_add(1, std::memory_order_relaxed); }
void Unref() {
if (ref_.fetch_sub(1, std::memory_order_acq_rel) == 1) {
void Ref(grpc_core::DebugLocation location) {
auto prev_refs = ref_.fetch_add(1, std::memory_order_relaxed);
if (grpc_slice_refcount_trace.enabled()) {
gpr_log(location.file(), location.line(), GPR_LOG_SEVERITY_INFO,
"REF %p %" PRIdPTR "->%" PRIdPTR, this, prev_refs, prev_refs + 1);
}
}
void Unref(grpc_core::DebugLocation location) {
auto prev_refs = ref_.fetch_sub(1, std::memory_order_acq_rel);
if (grpc_slice_refcount_trace.enabled()) {
gpr_log(location.file(), location.line(), GPR_LOG_SEVERITY_INFO,
"UNREF %p %" PRIdPTR "->%" PRIdPTR, this, prev_refs,
prev_refs - 1);
}
if (prev_refs == 1) {
destroyer_fn_(this);
}
}

File diff suppressed because it is too large Load Diff

@ -25,6 +25,7 @@
#include <stdint.h>
#include "absl/functional/any_invocable.h"
#include "absl/functional/function_ref.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
@ -43,12 +44,14 @@
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/iomgr_fwd.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/promise/arena_promise.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/transport.h"
typedef void (*grpc_ioreq_completion_func)(grpc_call* call, int success,
void* user_data);
@ -74,6 +77,28 @@ typedef struct grpc_call_create_args {
namespace grpc_core {
class PromiseBasedCall;
class ServerPromiseBasedCall;
class ServerCallContext {
public:
ServerCallContext(ServerPromiseBasedCall* call,
const void* server_stream_data)
: call_(call), server_stream_data_(server_stream_data) {}
ArenaPromise<ServerMetadataHandle> MakeTopOfServerCallPromise(
CallArgs call_args, grpc_completion_queue* cq,
grpc_metadata_array* publish_initial_metadata,
absl::FunctionRef<void(grpc_call* call)> publish);
// Server stream data as supplied by the transport (so we can link the
// transport stream up with the call again).
// TODO(ctiller): legacy API - once we move transports to promises we'll
// create the promise directly and not need to pass around this token.
const void* server_stream_data() { return server_stream_data_; }
private:
ServerPromiseBasedCall* const call_;
const void* const server_stream_data_;
};
// TODO(ctiller): move more call things into this type
class CallContext {
@ -98,6 +123,8 @@ class CallContext {
gpr_atm* peer_string_atm_ptr();
grpc_polling_entity* polling_entity() { return &pollent_; }
ServerCallContext* server_call_context();
private:
friend class PromiseBasedCall;
// Call final info.
@ -112,6 +139,7 @@ class CallContext {
template <>
struct ContextType<CallContext> {};
} // namespace grpc_core
// Create a new call based on \a args.

@ -25,6 +25,7 @@
#include "absl/container/flat_hash_map.h"
#include "absl/meta/type_traits.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/types/variant.h"
#include <grpc/support/log.h>
@ -45,7 +46,8 @@ const grpc_channel_filter* PromiseTracingFilterFor(
struct DerivedFilter : public grpc_channel_filter {
explicit DerivedFilter(const grpc_channel_filter* filter)
: grpc_channel_filter{
/* start_transport_stream_op_batch: */ grpc_call_next_op,
// start_transport_stream_op_batch:
grpc_call_next_op,
// make_call_promise:
[](grpc_channel_element* elem, CallArgs call_args,
NextPromiseFactory next_promise_factory)
@ -54,22 +56,22 @@ const grpc_channel_filter* PromiseTracingFilterFor(
static_cast<const DerivedFilter*>(elem->filter)->filter;
gpr_log(
GPR_DEBUG,
"%sCreateCallPromise[%s]: client_initial_metadata=%s",
"%s[%s] CreateCallPromise: client_initial_metadata=%s",
Activity::current()->DebugTag().c_str(),
source_filter->name,
call_args.client_initial_metadata->DebugString().c_str());
return [source_filter, child = next_promise_factory(
std::move(call_args))]() mutable {
gpr_log(GPR_DEBUG, "%sPollCallPromise[%s]: begin",
gpr_log(GPR_DEBUG, "%s[%s] PollCallPromise: begin",
Activity::current()->DebugTag().c_str(),
source_filter->name);
auto r = child();
if (auto* p = absl::get_if<ServerMetadataHandle>(&r)) {
gpr_log(GPR_DEBUG, "%sPollCallPromise[%s]: done: %s",
gpr_log(GPR_DEBUG, "%s[%s] PollCallPromise: done: %s",
Activity::current()->DebugTag().c_str(),
source_filter->name, (*p)->DebugString().c_str());
} else {
gpr_log(GPR_DEBUG, "%sPollCallPromise[%s]: <<pending>",
gpr_log(GPR_DEBUG, "%s[%s] PollCallPromise: <<pending>>",
Activity::current()->DebugTag().c_str(),
source_filter->name);
}
@ -85,16 +87,24 @@ const grpc_channel_filter* PromiseTracingFilterFor(
// destroy_call_elem:
[](grpc_call_element*, const grpc_call_final_info*,
grpc_closure*) {},
/* sizeof_channel_data: */ 0, // init_channel_elem:
// sizeof_channel_data:
0,
// init_channel_elem:
[](grpc_channel_element*, grpc_channel_element_args*) {
return absl::OkStatus();
},
// post_init_channel_elem:
[](grpc_channel_stack*, grpc_channel_element*) {},
/* destroy_channel_elem: */ [](grpc_channel_element*) {},
grpc_channel_next_get_info, filter->name},
filter(filter) {}
// destroy_channel_elem:
[](grpc_channel_element*) {}, grpc_channel_next_get_info,
// name:
nullptr},
filter(filter),
name_str(absl::StrCat(filter->name, ".trace")) {
this->name = name_str.c_str();
}
const grpc_channel_filter* const filter;
const std::string name_str;
};
struct Globals {
Mutex mu;

@ -76,7 +76,9 @@ ArenaPromise<ServerMetadataHandle> LameClientFilter::MakeCallPromise(
CallArgs args, NextPromiseFactory) {
// TODO(ctiller): remove if check once promise_based_filter is removed (Close
// is still needed)
if (args.incoming_messages != nullptr) args.incoming_messages->Close();
if (args.server_to_client_messages != nullptr) {
args.server_to_client_messages->Close();
}
return Immediate(ServerMetadataFromStatus(error_));
}

@ -24,14 +24,19 @@
#include <algorithm>
#include <atomic>
#include <initializer_list>
#include <list>
#include <new>
#include <queue>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include "absl/cleanup/cleanup.h"
#include "absl/status/status.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
#include <grpc/byte_buffer.h>
#include <grpc/impl/connectivity_state.h>
@ -44,13 +49,26 @@
#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/experiments/experiments.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/match.h"
#include "src/core/lib/gprpp/mpscq.h"
#include "src/core/lib/gprpp/status_helper.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/detail/basic_join.h"
#include "src/core/lib/promise/detail/basic_seq.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/promise/try_join.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/slice/slice_buffer.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@ -177,6 +195,20 @@ class Server::RequestMatcherInterface {
virtual void RequestCallWithPossiblePublish(size_t request_queue_index,
RequestedCall* call) = 0;
struct MatchResult {
size_t cq_idx;
RequestedCall* requested_call;
};
// This function is invoked on an incoming promise based RPC.
// The RequestMatcher will try to match it against an application-requested
// RPC if possible or will place it in the pending queue otherwise. To enable
// some measure of fairness between server CQs, the match is done starting at
// the start_request_queue_index parameter in a cyclic order rather than
// always starting at 0.
virtual ArenaPromise<absl::StatusOr<MatchResult>> MatchRequest(
size_t start_request_queue_index) = 0;
// This function is invoked on an incoming RPC, represented by the calld
// object. The RequestMatcher will try to match it against an
// application-requested RPC if possible or will place it in the pending queue
@ -208,9 +240,15 @@ class Server::RealRequestMatcher : public RequestMatcherInterface {
void ZombifyPending() override {
while (!pending_.empty()) {
CallData* calld = pending_.front();
calld->SetState(CallData::CallState::ZOMBIED);
calld->KillZombie();
Match(
pending_.front(),
[](CallData* calld) {
calld->SetState(CallData::CallState::ZOMBIED);
calld->KillZombie();
},
[](const std::shared_ptr<ActivityWaiter>& w) {
w->Finish(absl::InternalError("Server closed"));
});
pending_.pop();
}
}
@ -234,19 +272,19 @@ class Server::RealRequestMatcher : public RequestMatcherInterface {
if (requests_per_cq_[request_queue_index].Push(&call->mpscq_node)) {
// this was the first queued request: we need to lock and start
// matching calls
struct PendingCall {
struct NextPendingCall {
RequestedCall* rc = nullptr;
CallData* calld;
PendingCall pending;
};
auto pop_next_pending = [this, request_queue_index] {
PendingCall pending_call;
NextPendingCall pending_call;
{
MutexLock lock(&server_->mu_call_);
if (!pending_.empty()) {
pending_call.rc = reinterpret_cast<RequestedCall*>(
requests_per_cq_[request_queue_index].Pop());
if (pending_call.rc != nullptr) {
pending_call.calld = pending_.front();
pending_call.pending = std::move(pending_.front());
pending_.pop();
}
}
@ -254,14 +292,20 @@ class Server::RealRequestMatcher : public RequestMatcherInterface {
return pending_call;
};
while (true) {
PendingCall next_pending = pop_next_pending();
NextPendingCall next_pending = pop_next_pending();
if (next_pending.rc == nullptr) break;
if (!next_pending.calld->MaybeActivate()) {
// Zombied Call
next_pending.calld->KillZombie();
} else {
next_pending.calld->Publish(request_queue_index, next_pending.rc);
}
auto mr = MatchResult{request_queue_index, next_pending.rc};
Match(
next_pending.pending,
[mr](CallData* calld) {
if (!calld->MaybeActivate()) {
// Zombied Call
calld->KillZombie();
} else {
calld->Publish(mr.cq_idx, mr.requested_call);
}
},
[mr](const std::shared_ptr<ActivityWaiter>& w) { w->Finish(mr); });
}
}
}
@ -306,11 +350,66 @@ class Server::RealRequestMatcher : public RequestMatcherInterface {
calld->Publish(cq_idx, rc);
}
ArenaPromise<absl::StatusOr<MatchResult>> MatchRequest(
size_t start_request_queue_index) override {
for (size_t i = 0; i < requests_per_cq_.size(); i++) {
size_t cq_idx = (start_request_queue_index + i) % requests_per_cq_.size();
RequestedCall* rc =
reinterpret_cast<RequestedCall*>(requests_per_cq_[cq_idx].TryPop());
if (rc != nullptr) {
return Immediate(MatchResult{cq_idx, rc});
}
}
// No cq to take the request found; queue it on the slow list.
// We need to ensure that all the queues are empty. We do this under
// the server mu_call_ lock to ensure that if something is added to
// an empty request queue, it will block until the call is actually
// added to the pending list.
RequestedCall* rc = nullptr;
size_t cq_idx = 0;
size_t loop_count;
{
MutexLock lock(&server_->mu_call_);
for (loop_count = 0; loop_count < requests_per_cq_.size(); loop_count++) {
cq_idx =
(start_request_queue_index + loop_count) % requests_per_cq_.size();
rc = reinterpret_cast<RequestedCall*>(requests_per_cq_[cq_idx].Pop());
if (rc != nullptr) {
break;
}
}
if (rc == nullptr) {
auto w = std::make_shared<ActivityWaiter>(
Activity::current()->MakeNonOwningWaker());
pending_.push(w);
return [w]() -> Poll<absl::StatusOr<MatchResult>> {
std::unique_ptr<absl::StatusOr<MatchResult>> r(
w->result.exchange(nullptr, std::memory_order_acq_rel));
if (r == nullptr) return Pending{};
return std::move(*r);
};
}
}
return Immediate(MatchResult{cq_idx, rc});
}
Server* server() const override { return server_; }
private:
Server* const server_;
std::queue<CallData*> pending_;
struct ActivityWaiter {
explicit ActivityWaiter(Waker waker) : waker(std::move(waker)) {}
~ActivityWaiter() { delete result.load(std::memory_order_acquire); }
void Finish(absl::StatusOr<MatchResult> r) {
result.store(new absl::StatusOr<MatchResult>(std::move(r)),
std::memory_order_release);
waker.Wakeup();
}
Waker waker;
std::atomic<absl::StatusOr<MatchResult>*> result{nullptr};
};
using PendingCall = absl::variant<CallData*, std::shared_ptr<ActivityWaiter>>;
std::queue<PendingCall> pending_;
std::vector<LockedMultiProducerSingleConsumerQueue> requests_per_cq_;
};
@ -371,7 +470,10 @@ class Server::AllocatingRequestMatcherBatch
void MatchOrQueue(size_t /*start_request_queue_index*/,
CallData* calld) override {
if (server()->ShutdownRefOnRequest()) {
const bool still_running = server()->ShutdownRefOnRequest();
auto cleanup_ref =
absl::MakeCleanup([this] { server()->ShutdownUnrefOnRequest(); });
if (still_running) {
BatchCallAllocation call_info = allocator_();
GPR_ASSERT(server()->ValidateServerRequest(
cq(), static_cast<void*>(call_info.tag), nullptr,
@ -384,7 +486,25 @@ class Server::AllocatingRequestMatcherBatch
} else {
calld->FailCallCreation();
}
server()->ShutdownUnrefOnRequest();
}
ArenaPromise<absl::StatusOr<MatchResult>> MatchRequest(
size_t /*start_request_queue_index*/) override {
const bool still_running = server()->ShutdownRefOnRequest();
auto cleanup_ref =
absl::MakeCleanup([this] { server()->ShutdownUnrefOnRequest(); });
if (still_running) {
BatchCallAllocation call_info = allocator_();
GPR_ASSERT(server()->ValidateServerRequest(
cq(), static_cast<void*>(call_info.tag), nullptr,
nullptr) == GRPC_CALL_OK);
RequestedCall* rc = new RequestedCall(
static_cast<void*>(call_info.tag), call_info.cq, call_info.call,
call_info.initial_metadata, call_info.details);
return Immediate(MatchResult{cq_idx(), rc});
} else {
return Immediate(absl::InternalError("Server shutdown"));
}
}
private:
@ -404,6 +524,8 @@ class Server::AllocatingRequestMatcherRegistered
void MatchOrQueue(size_t /*start_request_queue_index*/,
CallData* calld) override {
auto cleanup_ref =
absl::MakeCleanup([this] { server()->ShutdownUnrefOnRequest(); });
if (server()->ShutdownRefOnRequest()) {
RegisteredCallAllocation call_info = allocator_();
GPR_ASSERT(server()->ValidateServerRequest(
@ -418,7 +540,26 @@ class Server::AllocatingRequestMatcherRegistered
} else {
calld->FailCallCreation();
}
server()->ShutdownUnrefOnRequest();
}
ArenaPromise<absl::StatusOr<MatchResult>> MatchRequest(
size_t /*start_request_queue_index*/) override {
const bool still_running = server()->ShutdownRefOnRequest();
auto cleanup_ref =
absl::MakeCleanup([this] { server()->ShutdownUnrefOnRequest(); });
if (still_running) {
RegisteredCallAllocation call_info = allocator_();
GPR_ASSERT(server()->ValidateServerRequest(
cq(), call_info.tag, call_info.optional_payload,
registered_method_) == GRPC_CALL_OK);
RequestedCall* rc =
new RequestedCall(call_info.tag, call_info.cq, call_info.call,
call_info.initial_metadata, registered_method_,
call_info.deadline, call_info.optional_payload);
return Immediate(MatchResult{cq_idx(), rc});
} else {
return Immediate(absl::InternalError("Server shutdown"));
}
}
private:
@ -493,7 +634,7 @@ class ChannelBroadcaster {
const grpc_channel_filter Server::kServerTopFilter = {
Server::CallData::StartTransportStreamOpBatch,
nullptr,
Server::ChannelData::MakeCallPromise,
grpc_channel_next_op,
sizeof(Server::CallData),
Server::CallData::InitCallElement,
@ -1100,14 +1241,119 @@ void Server::ChannelData::AcceptStream(void* arg, grpc_transport* /*transport*/,
args.send_deadline = Timestamp::InfFuture();
grpc_call* call;
grpc_error_handle error = grpc_call_create(&args, &call);
grpc_call_element* elem =
grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
auto* calld = static_cast<Server::CallData*>(elem->call_data);
if (!error.ok()) {
calld->FailCallCreation();
grpc_call_stack* call_stack = grpc_call_get_call_stack(call);
if (call_stack == nullptr) { // Promise based calls do not have a call stack
GPR_ASSERT(error.ok());
GPR_ASSERT(IsPromiseBasedServerCallEnabled());
return;
}
calld->Start(elem);
} else {
grpc_call_element* elem = grpc_call_stack_element(call_stack, 0);
auto* calld = static_cast<Server::CallData*>(elem->call_data);
if (!error.ok()) {
calld->FailCallCreation();
return;
}
calld->Start(elem);
}
}
ArenaPromise<ServerMetadataHandle> Server::ChannelData::MakeCallPromise(
grpc_channel_element* elem, CallArgs call_args, NextPromiseFactory) {
auto* chand = static_cast<Server::ChannelData*>(elem->channel_data);
auto* server = chand->server_.get();
if (server->ShutdownCalled()) {
return [] {
return ServerMetadataFromStatus(absl::InternalError("Server shutdown"));
};
}
absl::optional<Slice> path =
call_args.client_initial_metadata->Take(HttpPathMetadata());
if (!path.has_value()) {
return [] {
return ServerMetadataFromStatus(
absl::InternalError("Missing :path header"));
};
}
auto host_ptr =
call_args.client_initial_metadata->get_pointer(HttpAuthorityMetadata());
if (host_ptr == nullptr) {
return [] {
return ServerMetadataFromStatus(
absl::InternalError("Missing :authority header"));
};
}
// TODO(ctiller): deadline handling
Timestamp deadline = Timestamp::InfFuture();
// Find request matcher.
RequestMatcherInterface* matcher;
ChannelRegisteredMethod* rm =
chand->GetRegisteredMethod(host_ptr->c_slice(), path->c_slice());
ArenaPromise<absl::StatusOr<NextResult<MessageHandle>>>
maybe_read_first_message([] { return NextResult<MessageHandle>(); });
if (rm != nullptr) {
matcher = rm->server_registered_method->matcher.get();
switch (rm->server_registered_method->payload_handling) {
case GRPC_SRM_PAYLOAD_NONE:
break;
case GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER:
maybe_read_first_message =
Map(call_args.client_to_server_messages->Next(),
[](NextResult<MessageHandle> msg)
-> absl::StatusOr<NextResult<MessageHandle>> {
return std::move(msg);
});
}
} else {
matcher = server->unregistered_request_matcher_.get();
}
return TrySeq(
TryJoin(matcher->MatchRequest(chand->cq_idx()),
std::move(maybe_read_first_message)),
[path = std::move(*path), host = std::move(*host_ptr), deadline, server,
call_args = std::move(call_args)](
std::tuple<RequestMatcherInterface::MatchResult,
NextResult<MessageHandle>>
match_result_and_payload) mutable {
auto& mr = std::get<0>(match_result_and_payload);
auto& payload = std::get<1>(match_result_and_payload);
auto* rc = mr.requested_call;
auto* cq_for_new_request = server->cqs_[mr.cq_idx];
switch (rc->type) {
case RequestedCall::Type::BATCH_CALL:
GPR_ASSERT(!payload.has_value());
rc->data.batch.details->host = CSliceRef(host.c_slice());
rc->data.batch.details->method = CSliceRef(path.c_slice());
rc->data.batch.details->deadline =
deadline.as_timespec(GPR_CLOCK_MONOTONIC);
break;
case RequestedCall::Type::REGISTERED_CALL:
*rc->data.registered.deadline =
deadline.as_timespec(GPR_CLOCK_MONOTONIC);
if (rc->data.registered.optional_payload != nullptr) {
if (payload.has_value()) {
auto* sb = payload.value()->payload()->c_slice_buffer();
*rc->data.registered.optional_payload =
grpc_raw_byte_buffer_create(sb->slices, sb->count);
} else {
*rc->data.registered.optional_payload = nullptr;
}
}
break;
default:
GPR_UNREACHABLE_CODE(abort());
}
return GetContext<CallContext>()
->server_call_context()
->MakeTopOfServerCallPromise(
std::move(call_args), rc->cq_bound_to_call,
rc->initial_metadata,
[rc, cq_for_new_request](grpc_call* call) {
*rc->call = call;
grpc_cq_end_op(cq_for_new_request, rc->tag, absl::OkStatus(),
Server::DoneRequestEvent, rc, &rc->completion,
true);
});
});
}
void Server::ChannelData::FinishDestroy(void* arg,
@ -1273,6 +1519,7 @@ void Server::CallData::KillZombie() {
ExecCtx::Run(DEBUG_LOCATION, &kill_zombie_closure_, absl::OkStatus());
}
// If this changes, change MakeCallPromise too.
void Server::CallData::StartNewRpc(grpc_call_element* elem) {
auto* chand = static_cast<ChannelData*>(elem->channel_data);
if (server_->ShutdownCalled()) {

@ -56,6 +56,7 @@
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/iomgr_fwd.h"
#include "src/core/lib/promise/arena_promise.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/completion_queue.h"
@ -236,6 +237,8 @@ class Server : public InternallyRefCounted<Server>,
static grpc_error_handle InitChannelElement(
grpc_channel_element* elem, grpc_channel_element_args* args);
static void DestroyChannelElement(grpc_channel_element* elem);
static ArenaPromise<ServerMetadataHandle> MakeCallPromise(
grpc_channel_element* elem, CallArgs call_args, NextPromiseFactory);
private:
class ConnectivityWatcher;

@ -32,7 +32,6 @@
#include "src/core/lib/event_engine/default_event_engine.h"
#include "src/core/lib/gpr/alloc.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/transport/transport_impl.h"
@ -269,9 +268,9 @@ grpc_transport_stream_op_batch* grpc_make_transport_stream_op(
namespace grpc_core {
ServerMetadataHandle ServerMetadataFromStatus(const absl::Status& status) {
auto hdl =
GetContext<Arena>()->MakePooled<ServerMetadata>(GetContext<Arena>());
ServerMetadataHandle ServerMetadataFromStatus(const absl::Status& status,
Arena* arena) {
auto hdl = arena->MakePooled<ServerMetadata>(arena);
hdl->Set(GrpcStatusMetadata(), static_cast<grpc_status_code>(status.code()));
if (!status.ok()) {
hdl->Set(GrpcMessageMetadata(), Slice::FromCopiedString(status.message()));

@ -52,8 +52,8 @@
#include "src/core/lib/iomgr/iomgr_fwd.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/promise/arena_promise.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/detail/status.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice_buffer.h"
@ -120,7 +120,8 @@ inline bool IsStatusOk(const ServerMetadataHandle& m) {
GRPC_STATUS_OK;
}
ServerMetadataHandle ServerMetadataFromStatus(const absl::Status& status);
ServerMetadataHandle ServerMetadataFromStatus(
const absl::Status& status, Arena* arena = GetContext<Arena>());
template <>
struct StatusCastImpl<ServerMetadataHandle, absl::Status> {
@ -136,6 +137,13 @@ struct StatusCastImpl<ServerMetadataHandle, const absl::Status&> {
}
};
template <>
struct StatusCastImpl<ServerMetadataHandle, absl::Status&> {
static ServerMetadataHandle Cast(const absl::Status& m) {
return ServerMetadataFromStatus(m);
}
};
struct CallArgs {
// Initial metadata from the client to the server.
// During promise setup this can be manipulated by filters (and then
@ -145,11 +153,11 @@ struct CallArgs {
// Set once when it's available.
// During promise setup filters can substitute their own latch for this
// and consequently intercept the sent value and mutate/observe it.
Latch<ServerMetadata*>* server_initial_metadata;
PipeSender<ServerMetadataHandle>* server_initial_metadata;
// Messages travelling from the application to the transport.
PipeReceiver<MessageHandle>* outgoing_messages;
PipeReceiver<MessageHandle>* client_to_server_messages;
// Messages travelling from the transport to the application.
PipeSender<MessageHandle>* incoming_messages;
PipeSender<MessageHandle>* server_to_client_messages;
};
using NextPromiseFactory =

@ -55,7 +55,6 @@ grpc_cc_library(
],
external_deps = [
"absl/random",
"absl/status",
"absl/status:statusor",
"absl/strings",
"absl/types:optional",
@ -74,22 +73,18 @@ grpc_cc_library(
"//:grpc_base",
"//:grpc_client_channel",
"//:grpc_resolver",
"//:promise",
"//:uri_parser",
"//src/core:arena",
"//src/core:arena_promise",
"//src/core:basic_seq",
"//src/core:cancel_callback",
"//src/core:channel_args",
"//src/core:channel_fwd",
"//src/core:channel_stack_type",
"//src/core:context",
"//src/core:for_each",
"//src/core:latch",
"//src/core:promise_like",
"//src/core:seq",
"//src/core:map",
"//src/core:pipe",
"//src/core:poll",
"//src/core:slice",
"//src/core:slice_buffer",
"//src/core:try_concurrently",
],
)

@ -34,7 +34,6 @@
#include <vector>
#include "absl/random/random.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
@ -58,14 +57,9 @@
#include "src/core/lib/promise/arena_promise.h"
#include "src/core/lib/promise/cancel_callback.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/detail/basic_seq.h"
#include "src/core/lib/promise/detail/promise_like.h"
#include "src/core/lib/promise/for_each.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/map_pipe.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/promise/seq.h"
#include "src/core/lib/promise/try_concurrently.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/resolver/resolver_registry.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
@ -365,52 +359,28 @@ class ClientLoggingFilter final : public grpc_core::ChannelFilter {
}
calld->LogClientHeader(/*is_client=*/true,
call_args.client_initial_metadata);
auto* server_initial_metadata = call_args.server_initial_metadata;
auto incoming_mapper =
grpc_core::PipeMapper<grpc_core::MessageHandle>::Intercept(
*call_args.incoming_messages);
grpc_core::PipeMapper<grpc_core::MessageHandle> outgoing_mapper =
grpc_core::PipeMapper<grpc_core::MessageHandle>::Intercept(
*call_args.outgoing_messages);
call_args.server_initial_metadata->InterceptAndMap(
[calld](grpc_core::ServerMetadataHandle metadata) {
calld->LogServerHeader(/*is_client=*/true, metadata.get());
return metadata;
});
call_args.client_to_server_messages->InterceptAndMapWithHalfClose(
[calld](grpc_core::MessageHandle message) {
calld->LogClientMessage(/*is_client=*/true, message->payload());
return message;
},
[calld] { calld->LogClientHalfClose(/*is_client=*/true); });
call_args.server_to_client_messages->InterceptAndMap(
[calld](grpc_core::MessageHandle message) {
calld->LogServerMessage(/*is_client=*/true, message->payload());
return message;
});
return grpc_core::OnCancel(
grpc_core::TryConcurrently(
grpc_core::Seq(
next_promise_factory(std::move(call_args)),
[calld](grpc_core::ServerMetadataHandle metadata) mutable
-> grpc_core::ServerMetadataHandle {
calld->LogServerTrailer(/*is_client=*/true, metadata.get());
return metadata;
}))
.NecessaryPull(grpc_core::Seq(
server_initial_metadata->Wait(),
[calld](
grpc_core::ServerMetadata** server_initial_metadata) mutable
-> grpc_core::ArenaPromise<absl::Status> {
if (server_initial_metadata != nullptr) {
calld->LogServerHeader(/*is_client=*/true,
*server_initial_metadata);
}
return grpc_core::ImmediateOkStatus();
}))
.NecessaryPull(incoming_mapper.TakeAndRun(
[calld](grpc_core::MessageHandle message)
-> absl::StatusOr<grpc_core::MessageHandle> {
calld->LogServerMessage(/*is_client=*/true,
message->payload());
return message;
}))
.NecessaryPush(grpc_core::Seq(
outgoing_mapper.TakeAndRun(
[calld](grpc_core::MessageHandle message)
-> absl::StatusOr<grpc_core::MessageHandle> {
calld->LogClientMessage(/*is_client=*/true,
message->payload());
return message;
}),
[calld]() mutable -> grpc_core::ArenaPromise<absl::Status> {
calld->LogClientHalfClose(/*is_client=*/true);
return grpc_core::ImmediateOkStatus();
})),
Map(next_promise_factory(std::move(call_args)),
[calld](grpc_core::ServerMetadataHandle md) {
calld->LogServerTrailer(/*is_client=*/true, md.get());
return md;
}),
[calld]() { calld->LogCancel(/*is_client=*/true); });
}
@ -449,50 +419,28 @@ class ServerLoggingFilter final : public grpc_core::ChannelFilter {
}
calld->LogClientHeader(/*is_client=*/false,
call_args.client_initial_metadata);
auto* server_initial_metadata = call_args.server_initial_metadata;
auto incoming_mapper =
grpc_core::PipeMapper<grpc_core::MessageHandle>::Intercept(
*call_args.incoming_messages);
grpc_core::PipeMapper<grpc_core::MessageHandle> outgoing_mapper =
grpc_core::PipeMapper<grpc_core::MessageHandle>::Intercept(
*call_args.outgoing_messages);
call_args.server_initial_metadata->InterceptAndMap(
[calld](grpc_core::ServerMetadataHandle metadata) {
calld->LogServerHeader(/*is_client=*/false, metadata.get());
return metadata;
});
call_args.client_to_server_messages->InterceptAndMapWithHalfClose(
[calld](grpc_core::MessageHandle message) {
calld->LogClientMessage(/*is_client=*/false, message->payload());
return message;
},
[calld] { calld->LogClientHalfClose(/*is_client=*/false); });
call_args.server_to_client_messages->InterceptAndMap(
[calld](grpc_core::MessageHandle message) {
calld->LogServerMessage(/*is_client=*/false, message->payload());
return message;
});
return grpc_core::OnCancel(
grpc_core::TryConcurrently(
grpc_core::Seq(
next_promise_factory(std::move(call_args)),
[calld](grpc_core::ServerMetadataHandle metadata) mutable
-> grpc_core::ServerMetadataHandle {
calld->LogServerTrailer(/*is_client=*/false, metadata.get());
return metadata;
}))
.Push(grpc_core::Seq(
server_initial_metadata->Wait(),
[calld](
grpc_core::ServerMetadata** server_initial_metadata) mutable
-> grpc_core::ArenaPromise<absl::Status> {
calld->LogServerHeader(/*is_client=*/false,
*server_initial_metadata);
return grpc_core::ImmediateOkStatus();
}))
.Push(outgoing_mapper.TakeAndRun(
[calld](grpc_core::MessageHandle message)
-> absl::StatusOr<grpc_core::MessageHandle> {
calld->LogServerMessage(/*is_client=*/false,
message->payload());
return message;
}))
.NecessaryPull(grpc_core::Seq(
incoming_mapper.TakeAndRun(
[calld](grpc_core::MessageHandle message)
-> absl::StatusOr<grpc_core::MessageHandle> {
calld->LogClientMessage(/*is_client=*/false,
message->payload());
return message;
}),
[calld]() mutable -> grpc_core::ArenaPromise<absl::Status> {
calld->LogClientHalfClose(/*is_client=*/false);
return grpc_core::ImmediateOkStatus();
})),
Map(next_promise_factory(std::move(call_args)),
[calld](grpc_core::ServerMetadataHandle md) {
calld->LogServerTrailer(/*is_client=*/false, md.get());
return md;
}),
[calld]() { calld->LogCancel(/*is_client=*/false); });
}
};

@ -573,6 +573,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/buffer_list.cc',
'src/core/lib/iomgr/call_combiner.cc',
'src/core/lib/iomgr/cfstream_handle.cc',
'src/core/lib/iomgr/closure.cc',
'src/core/lib/iomgr/combiner.cc',
'src/core/lib/iomgr/dualstack_socket_posix.cc',
'src/core/lib/iomgr/endpoint.cc',
@ -654,8 +655,8 @@ CORE_SOURCE_FILES = [
'src/core/lib/load_balancing/lb_policy_registry.cc',
'src/core/lib/matchers/matchers.cc',
'src/core/lib/promise/activity.cc',
'src/core/lib/promise/pipe.cc',
'src/core/lib/promise/sleep.cc',
'src/core/lib/promise/trace.cc',
'src/core/lib/resolver/resolver.cc',
'src/core/lib/resolver/resolver_registry.cc',
'src/core/lib/resolver/server_address.cc',
@ -733,6 +734,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_refcount.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
'src/core/lib/surface/builtins.cc',

@ -130,15 +130,16 @@ static void chttp2_init_server_socketpair(
auto* fixture_data = static_cast<custom_fixture_data*>(f->fixture_data);
grpc_transport* transport;
GPR_ASSERT(!f->server);
f->server = grpc_server_create(server_args, nullptr);
f->server = grpc_server_create(grpc_core::ChannelArgs::FromC(server_args)
.Set(GRPC_ARG_MINIMAL_STACK, true)
.ToC()
.get(),
nullptr);
grpc_server_register_completion_queue(f->server, f->cq, nullptr);
grpc_server_start(f->server);
auto final_server_args = grpc_core::CoreConfiguration::Get()
.channel_args_preconditioning()
.PreconditionChannelArgs(server_args)
.Set(GRPC_ARG_MINIMAL_STACK, true);
transport = grpc_create_chttp2_transport(final_server_args,
fixture_data->ep.server, false);
transport = grpc_create_chttp2_transport(
grpc_core::Server::FromC(f->server)->channel_args(),
fixture_data->ep.server, false);
server_setup_transport(f, transport);
}

@ -261,7 +261,7 @@ END2END_TESTS = {
exclude_inproc = True,
exclude_minstack = True,
),
"max_connection_age": _test_options(exclude_inproc = True),
"max_connection_age": _test_options(exclude_minstack = True, exclude_inproc = True),
"max_connection_idle": _test_options(needs_fullstack = True, proxyable = False),
"max_message_length": _test_options(exclude_minstack = True),
"negative_deadline": _test_options(exclude_minstack = True),

@ -19,6 +19,8 @@
#include <stdint.h>
#include <string.h>
#include <string>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/impl/propagation_bits.h>
@ -44,6 +46,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s", std::string(80, '*').c_str());
gpr_log(GPR_INFO, "Running test: %s/%s/%s/%s", test_name, config.name,
mode.name, use_service_config ? "service_config" : "client_api");
f = config.create_fixture(client_args, server_args);

@ -48,6 +48,7 @@ static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "%s", std::string(80, '*').c_str());
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);

@ -596,6 +596,9 @@ static void test_max_receive_message_length_on_compressed_request(
nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
// WARNING!!
// It's believed the following line (and the associated batch) is the only
// test we have for failing a receive operation in a batch.
cqv.Expect(tag(102), false);
cqv.Expect(tag(103), true);
cqv.Expect(tag(1), true);

@ -33,6 +33,7 @@
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/lib/gprpp/env.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/end2end_tests.h"
#include "test/core/util/test_config.h"
@ -284,6 +285,7 @@ static void test_no_logging_in_one_request(grpc_end2end_test_config config) {
}
void no_logging(grpc_end2end_test_config config) {
grpc_core::SetEnv("GRPC_TRACE", "");
gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
grpc_tracer_set_enabled("all", 0);
gpr_set_log_function(log_dispatcher_func);

@ -20,6 +20,7 @@
#include <string.h>
#include <memory>
#include <string>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
@ -38,9 +39,11 @@ static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_channel_args* server_args,
int num_messages) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
gpr_log(GPR_INFO, "%s\nRunning test: %s/%s/%d", std::string(100, '*').c_str(),
test_name, config.name, num_messages);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
@ -94,8 +97,8 @@ static void end_test(grpc_end2end_test_fixture* f) {
// writing, and expects to get the status after the messages.
static void test_server_streaming(grpc_end2end_test_config config,
int num_messages) {
grpc_end2end_test_fixture f =
begin_test(config, "test_server_streaming", nullptr, nullptr);
grpc_end2end_test_fixture f = begin_test(config, "test_server_streaming",
nullptr, nullptr, num_messages);
grpc_call* c;
grpc_call* s;
auto cqv = std::make_unique<grpc_core::CqVerifier>(f.cq);

@ -66,7 +66,7 @@
#include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/arena_promise.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/latch.h"
#include "src/core/lib/promise/pipe.h"
#include "src/core/lib/promise/poll.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/resource_quota/memory_quota.h"
@ -436,10 +436,12 @@ class MainLoop {
CallArgs call_args, NextPromiseFactory) override {
Call* call = static_cast<Call*>(Activity::current());
if (call->server_initial_metadata_) {
call_args.server_initial_metadata->Set(
call->server_initial_metadata_.get());
call->server_initial_metadata_push_promise_.emplace(
call_args.server_initial_metadata->Push(
ServerMetadataHandle(call->server_initial_metadata_.get(),
Arena::PooledDeleter(nullptr))));
} else {
call->unset_incoming_server_initial_metadata_latch_ =
call->unpushed_incoming_server_initial_metadata_pipe_ =
call_args.server_initial_metadata;
}
return [call]() -> Poll<ServerMetadataHandle> {
@ -472,10 +474,10 @@ class MainLoop {
const filter_fuzzer::Metadata& client_initial_metadata, bool is_client)
: main_loop_(main_loop), id_(id) {
ScopedContext context(this);
auto* server_initial_metadata = arena_->New<Latch<ServerMetadata*>>();
auto* server_initial_metadata = arena_->New<Pipe<ServerMetadataHandle>>();
CallArgs call_args{std::move(*LoadMetadata(client_initial_metadata,
&client_initial_metadata_)),
server_initial_metadata, nullptr, nullptr};
&server_initial_metadata->sender, nullptr, nullptr};
if (is_client) {
promise_ = main_loop_->channel_stack_->MakeClientCallPromise(
std::move(call_args));
@ -532,10 +534,12 @@ class MainLoop {
void RecvInitialMetadata(const filter_fuzzer::Metadata& metadata) {
if (server_initial_metadata_ == nullptr) {
LoadMetadata(metadata, &server_initial_metadata_);
if (auto* latch = std::exchange(
unset_incoming_server_initial_metadata_latch_, nullptr)) {
if (auto* pipe = std::exchange(
unpushed_incoming_server_initial_metadata_pipe_, nullptr)) {
ScopedContext context(this);
latch->Set(server_initial_metadata_.get());
server_initial_metadata_push_promise_.emplace(
pipe->Push(ServerMetadataHandle(server_initial_metadata_.get(),
Arena::PooledDeleter(nullptr))));
}
}
}
@ -625,8 +629,10 @@ class MainLoop {
std::unique_ptr<filter_fuzzer::FinalInfo> final_info_;
std::unique_ptr<ClientMetadata> client_initial_metadata_;
std::unique_ptr<ServerMetadata> server_initial_metadata_;
Latch<ServerMetadata*>* unset_incoming_server_initial_metadata_latch_ =
nullptr;
PipeSender<ServerMetadataHandle>*
unpushed_incoming_server_initial_metadata_pipe_ = nullptr;
absl::optional<PipeSender<ServerMetadataHandle>::PushType>
server_initial_metadata_push_promise_;
std::unique_ptr<ServerMetadata> server_trailing_metadata_;
Waker server_trailing_metadata_waker_;
CallFinalization finalization_;

@ -45,6 +45,24 @@ grpc_cc_test(
deps = ["//src/core:poll"],
)
grpc_cc_test(
name = "interceptor_list_test",
srcs = ["interceptor_list_test.cc"],
external_deps = ["gtest"],
language = "c++",
uses_event_engine = False,
uses_polling = False,
deps = [
"test_context",
"//:ref_counted_ptr",
"//src/core:arena",
"//src/core:event_engine_memory_allocator",
"//src/core:interceptor_list",
"//src/core:memory_quota",
"//src/core:resource_quota",
],
)
grpc_cc_test(
name = "context_test",
srcs = ["context_test.cc"],
@ -378,7 +396,7 @@ grpc_cc_test(
uses_polling = False,
deps = [
"test_wakeup_schedulers",
"//:gpr",
"//:grpc",
"//:ref_counted_ptr",
"//src/core:activity",
"//src/core:basic_join",

@ -128,12 +128,12 @@ TEST(ActivityTest, DropImmediately) {
}
template <typename B>
class BarrierTest : public testing::Test {
class BarrierTest : public ::testing::Test {
public:
using Type = B;
};
using BarrierTestTypes = testing::Types<Barrier, SingleBarrier>;
using BarrierTestTypes = ::testing::Types<Barrier, SingleBarrier>;
TYPED_TEST_SUITE(BarrierTest, BarrierTestTypes);
TYPED_TEST(BarrierTest, Barrier) {

@ -16,6 +16,7 @@
#include <stdint.h>
#include <initializer_list>
#include <memory>
#include "gmock/gmock.h"

@ -52,6 +52,18 @@ TEST(IfTest, ChooseFailure) {
Poll<absl::StatusOr<int>>(absl::StatusOr<int>()));
}
TEST(IfTest, ImmediateChooseTrue) {
EXPECT_EQ(If(
true, []() { return 1; }, []() { return 2; })(),
Poll<int>(1));
}
TEST(IfTest, ImmediateChooseFalse) {
EXPECT_EQ(If(
false, []() { return 1; }, []() { return 2; })(),
Poll<int>(2));
}
} // namespace grpc_core
int main(int argc, char** argv) {

@ -0,0 +1,144 @@
// Copyright 2022 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/promise/interceptor_list.h"
#include <initializer_list>
#include <memory>
#include "gtest/gtest.h"
#include <grpc/event_engine/memory_allocator.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/resource_quota/memory_quota.h"
#include "src/core/lib/resource_quota/resource_quota.h"
#include "test/core/promise/test_context.h"
namespace grpc_core {
namespace {
class InterceptorListTest : public ::testing::Test {
protected:
MemoryAllocator memory_allocator_ = MemoryAllocator(
ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator("test"));
ScopedArenaPtr arena_ = MakeScopedArena(1024, &memory_allocator_);
TestContext<Arena> arena_ctx_{arena_.get()};
};
TEST_F(InterceptorListTest, NoOp) { InterceptorList<std::string>(); }
TEST_F(InterceptorListTest, CanRunOne) {
InterceptorList<std::string> list;
list.AppendMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloa"));
}
TEST_F(InterceptorListTest, CanRunTwo) {
InterceptorList<std::string> list;
list.AppendMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
list.AppendMap([](std::string s) { return s + "b"; }, DEBUG_LOCATION);
EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloab"));
}
TEST_F(InterceptorListTest, CanRunTwoTwice) {
InterceptorList<std::string> list;
list.AppendMap([](std::string s) { return s + s; }, DEBUG_LOCATION);
list.AppendMap([](std::string s) { return s + s + s; }, DEBUG_LOCATION);
EXPECT_EQ(absl::get<kPollReadyIdx>(list.Run(std::string(10, 'a'))()).value(),
std::string(60, 'a'));
EXPECT_EQ(absl::get<kPollReadyIdx>(list.Run(std::string(100, 'b'))()).value(),
std::string(600, 'b'));
}
TEST_F(InterceptorListTest, CanRunManyWithCaptures) {
InterceptorList<std::string> list;
for (size_t i = 0; i < 26 * 1000; i++) {
list.AppendMap(
[i = std::make_shared<size_t>(i)](std::string s) {
return s + static_cast<char>((*i % 26) + 'a');
},
DEBUG_LOCATION);
}
std::string expected;
for (size_t i = 0; i < 1000; i++) {
expected += "abcdefghijklmnopqrstuvwxyz";
}
EXPECT_EQ(absl::get<kPollReadyIdx>(list.Run("")()).value(), expected);
}
TEST_F(InterceptorListTest, CanRunOnePrepended) {
InterceptorList<std::string> list;
list.PrependMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloa"));
}
TEST_F(InterceptorListTest, CanRunTwoPrepended) {
InterceptorList<std::string> list;
list.PrependMap([](std::string s) { return s + "a"; }, DEBUG_LOCATION);
list.PrependMap([](std::string s) { return s + "b"; }, DEBUG_LOCATION);
EXPECT_EQ(list.Run("hello")(), Poll<absl::optional<std::string>>("helloba"));
}
TEST_F(InterceptorListTest, CanRunManyWithCapturesPrepended) {
InterceptorList<std::string> list;
for (size_t i = 0; i < 26 * 1000; i++) {
list.PrependMap(
[i = std::make_shared<size_t>(i)](std::string s) {
return s + static_cast<char>((*i % 26) + 'a');
},
DEBUG_LOCATION);
}
std::string expected;
for (size_t i = 0; i < 1000; i++) {
expected += "zyxwvutsrqponmlkjihgfedcba";
}
EXPECT_EQ(absl::get<kPollReadyIdx>(list.Run("")()).value(), expected);
}
TEST_F(InterceptorListTest, CanRunManyWithCapturesThatDelay) {
InterceptorList<std::string> list;
for (size_t i = 0; i < 26 * 1000; i++) {
list.AppendMap(
[i = std::make_shared<size_t>(i)](std::string s) {
return
[x = false, i, s]() mutable -> Poll<absl::optional<std::string>> {
if (!x) {
x = true;
return Pending{};
}
return s + static_cast<char>((*i % 26) + 'a');
};
},
DEBUG_LOCATION);
}
auto promise = list.Run("");
for (size_t i = 0; i < 26 * 1000; i++) {
EXPECT_TRUE(absl::holds_alternative<Pending>(promise())) << i;
}
std::string expected;
for (size_t i = 0; i < 1000; i++) {
expected += "abcdefghijklmnopqrstuvwxyz";
}
EXPECT_EQ(absl::get<kPollReadyIdx>(promise()).value(), expected);
}
} // namespace
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -43,8 +43,8 @@ TEST(LatchTest, Works) {
latch.Set(42);
return true;
}),
[](std::tuple<int*, bool> result) {
EXPECT_EQ(*std::get<0>(result), 42);
[](std::tuple<int, bool> result) {
EXPECT_EQ(std::get<0>(result), 42);
return absl::OkStatus();
});
},

@ -16,6 +16,7 @@
#include <stdint.h>
#include <initializer_list>
#include <memory>
#include <utility>

@ -14,9 +14,9 @@
#include "src/core/lib/promise/pipe.h"
#include <initializer_list>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include "absl/status/status.h"
@ -24,7 +24,7 @@
#include "gtest/gtest.h"
#include <grpc/event_engine/memory_allocator.h>
#include <grpc/support/log.h>
#include <grpc/grpc.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/promise/activity.h"
@ -52,11 +52,11 @@ TEST_F(PipeTest, CanSendAndReceive) {
EXPECT_CALL(on_done, Call(absl::OkStatus()));
MakeActivity(
[] {
Pipe<int> pipe;
auto* pipe = GetContext<Arena>()->ManagedNew<Pipe<int>>();
return Seq(
// Concurrently: send 42 into the pipe, and receive from the pipe.
Join(pipe.sender.Push(42),
Map(pipe.receiver.Next(),
Join(pipe->sender.Push(42),
Map(pipe->receiver.Next(),
[](NextResult<int> r) { return r.value(); })),
// Once complete, verify successful sending and the received value
// is 42.
@ -71,17 +71,103 @@ TEST_F(PipeTest, CanSendAndReceive) {
MakeScopedArena(1024, &memory_allocator_));
}
TEST_F(PipeTest, CanInterceptAndMapAtSender) {
StrictMock<MockFunction<void(absl::Status)>> on_done;
EXPECT_CALL(on_done, Call(absl::OkStatus()));
MakeActivity(
[] {
auto* pipe = GetContext<Arena>()->ManagedNew<Pipe<int>>();
pipe->sender.InterceptAndMap([](int value) { return value / 2; });
return Seq(
// Concurrently: send 42 into the pipe, and receive from the pipe.
Join(pipe->sender.Push(42),
Map(pipe->receiver.Next(),
[](NextResult<int> r) { return r.value(); })),
// Once complete, verify successful sending and the received value
// is 21.
[](std::tuple<bool, int> result) {
EXPECT_TRUE(std::get<0>(result));
EXPECT_EQ(21, std::get<1>(result));
return absl::OkStatus();
});
},
NoWakeupScheduler(),
[&on_done](absl::Status status) { on_done.Call(std::move(status)); },
MakeScopedArena(1024, &memory_allocator_));
}
TEST_F(PipeTest, CanInterceptAndMapAtReceiver) {
StrictMock<MockFunction<void(absl::Status)>> on_done;
EXPECT_CALL(on_done, Call(absl::OkStatus()));
MakeActivity(
[] {
auto* pipe = GetContext<Arena>()->ManagedNew<Pipe<int>>();
pipe->receiver.InterceptAndMap([](int value) { return value / 2; });
return Seq(
// Concurrently: send 42 into the pipe, and receive from the pipe.
Join(pipe->sender.Push(42),
Map(pipe->receiver.Next(),
[](NextResult<int> r) { return r.value(); })),
// Once complete, verify successful sending and the received value
// is 21.
[](std::tuple<bool, int> result) {
EXPECT_TRUE(std::get<0>(result));
EXPECT_EQ(21, std::get<1>(result));
return absl::OkStatus();
});
},
NoWakeupScheduler(),
[&on_done](absl::Status status) { on_done.Call(std::move(status)); },
MakeScopedArena(1024, &memory_allocator_));
}
TEST_F(PipeTest, InterceptionOrderingIsCorrect) {
StrictMock<MockFunction<void(absl::Status)>> on_done;
EXPECT_CALL(on_done, Call(absl::OkStatus()));
MakeActivity(
[] {
auto* pipe = GetContext<Arena>()->ManagedNew<Pipe<std::string>>();
auto appender = [](char c) {
return [c](std::string value) {
value += c;
return value;
};
};
// Interception get added outwardly from the center, and run from sender
// to receiver, so the following should result in append "abcd".
pipe->receiver.InterceptAndMap(appender('c'));
pipe->sender.InterceptAndMap(appender('b'));
pipe->receiver.InterceptAndMap(appender('d'));
pipe->sender.InterceptAndMap(appender('a'));
return Seq(
// Concurrently: send "" into the pipe, and receive from the pipe.
Join(pipe->sender.Push(""),
Map(pipe->receiver.Next(),
[](NextResult<std::string> r) { return r.value(); })),
// Once complete, verify successful sending and the received value
// is 21.
[](std::tuple<bool, std::string> result) {
EXPECT_TRUE(std::get<0>(result));
EXPECT_EQ("abcd", std::get<1>(result));
return absl::OkStatus();
});
},
NoWakeupScheduler(),
[&on_done](absl::Status status) { on_done.Call(std::move(status)); },
MakeScopedArena(1024, &memory_allocator_));
}
TEST_F(PipeTest, CanReceiveAndSend) {
StrictMock<MockFunction<void(absl::Status)>> on_done;
EXPECT_CALL(on_done, Call(absl::OkStatus()));
MakeActivity(
[] {
Pipe<int> pipe;
auto* pipe = GetContext<Arena>()->ManagedNew<Pipe<int>>();
return Seq(
// Concurrently: receive from the pipe, and send 42 into the pipe.
Join(Map(pipe.receiver.Next(),
Join(Map(pipe->receiver.Next(),
[](NextResult<int> r) { return r.value(); }),
pipe.sender.Push(42)),
pipe->sender.Push(42)),
// Once complete, verify the received value is 42 and successful
// sending.
[](std::tuple<int, bool> result) {
@ -157,6 +243,95 @@ TEST_F(PipeTest, CanSeeClosedOnReceive) {
MakeScopedArena(1024, &memory_allocator_));
}
TEST_F(PipeTest, CanCloseSend) {
StrictMock<MockFunction<void(absl::Status)>> on_done;
EXPECT_CALL(on_done, Call(absl::OkStatus()));
MakeActivity(
[] {
auto* pipe = GetContext<Arena>()->ManagedNew<Pipe<int>>();
return Seq(
// Concurrently:
// - wait for a received value (will stall forever since we push
// nothing into the queue)
// - close the sender, which will signal the receiver to return an
// end-of-stream.
Join(pipe->receiver.Next(),
[pipe]() mutable {
pipe->sender.Close();
return absl::OkStatus();
}),
// Verify we received end-of-stream and closed the sender.
[](std::tuple<NextResult<int>, absl::Status> result) {
EXPECT_FALSE(std::get<0>(result).has_value());
EXPECT_FALSE(std::get<0>(result).cancelled());
EXPECT_EQ(std::get<1>(result), absl::OkStatus());
return absl::OkStatus();
});
},
NoWakeupScheduler(),
[&on_done](absl::Status status) { on_done.Call(std::move(status)); },
MakeScopedArena(1024, &memory_allocator_));
}
TEST_F(PipeTest, CanCloseSendWithInterceptor) {
StrictMock<MockFunction<void(absl::Status)>> on_done;
EXPECT_CALL(on_done, Call(absl::OkStatus()));
MakeActivity(
[] {
auto* pipe = GetContext<Arena>()->ManagedNew<Pipe<int>>();
pipe->sender.InterceptAndMap([](int value) { return value + 1; });
return Seq(
// Concurrently:
// - wait for a received value (will stall forever since we push
// nothing into the queue)
// - close the sender, which will signal the receiver to return an
// end-of-stream.
Join(pipe->receiver.Next(),
[pipe]() mutable {
pipe->sender.Close();
return absl::OkStatus();
}),
// Verify we received end-of-stream and closed the sender.
[](std::tuple<NextResult<int>, absl::Status> result) {
EXPECT_FALSE(std::get<0>(result).has_value());
EXPECT_FALSE(std::get<0>(result).cancelled());
EXPECT_EQ(std::get<1>(result), absl::OkStatus());
return absl::OkStatus();
});
},
NoWakeupScheduler(),
[&on_done](absl::Status status) { on_done.Call(std::move(status)); },
MakeScopedArena(1024, &memory_allocator_));
}
TEST_F(PipeTest, CanCancelSendWithInterceptor) {
StrictMock<MockFunction<void(absl::Status)>> on_done;
EXPECT_CALL(on_done, Call(absl::OkStatus()));
MakeActivity(
[] {
auto* pipe = GetContext<Arena>()->ManagedNew<Pipe<int>>();
pipe->sender.InterceptAndMap([](int) { return absl::nullopt; });
return Seq(
// Concurrently:
// - wait for a received value (will stall forever since we push
// nothing into the queue)
// - close the sender, which will signal the receiver to return an
// end-of-stream.
Join(pipe->receiver.Next(), pipe->sender.Push(3)),
// Verify we received end-of-stream with cancellation and sent
// successfully.
[](std::tuple<NextResult<int>, bool> result) {
EXPECT_FALSE(std::get<0>(result).has_value());
EXPECT_TRUE(std::get<0>(result).cancelled());
EXPECT_FALSE(std::get<1>(result));
return absl::OkStatus();
});
},
NoWakeupScheduler(),
[&on_done](absl::Status status) { on_done.Call(std::move(status)); },
MakeScopedArena(1024, &memory_allocator_));
}
TEST_F(PipeTest, CanFlowControlThroughManyStages) {
StrictMock<MockFunction<void(absl::Status)>> on_done;
EXPECT_CALL(on_done, Call(absl::OkStatus()));
@ -167,39 +342,38 @@ TEST_F(PipeTest, CanFlowControlThroughManyStages) {
// completes.
MakeActivity(
[done] {
Pipe<int> pipe1;
Pipe<int> pipe2;
Pipe<int> pipe3;
auto sender1 = std::move(pipe1.sender);
auto receiver1 = std::move(pipe1.receiver);
auto sender2 = std::move(pipe2.sender);
auto receiver2 = std::move(pipe2.receiver);
auto sender3 = std::move(pipe3.sender);
auto receiver3 = std::move(pipe3.receiver);
return Seq(
Join(Seq(sender1.Push(1),
[done] {
*done = true;
return 1;
}),
Seq(receiver1.Next(),
[sender2 = std::move(sender2)](NextResult<int> r) mutable {
return sender2.Push(r.value());
}),
Seq(receiver2.Next(),
[sender3 = std::move(sender3)](NextResult<int> r) mutable {
return sender3.Push(r.value());
}),
Seq(receiver3.Next(),
[done](NextResult<int> r) {
EXPECT_EQ(r.value(), 1);
EXPECT_FALSE(*done);
return 2;
})),
[](std::tuple<int, bool, bool, int> result) {
EXPECT_EQ(result, std::make_tuple(1, true, true, 2));
return absl::OkStatus();
});
auto* pipe1 = GetContext<Arena>()->ManagedNew<Pipe<int>>();
auto* pipe2 = GetContext<Arena>()->ManagedNew<Pipe<int>>();
auto* pipe3 = GetContext<Arena>()->ManagedNew<Pipe<int>>();
auto* sender1 = &pipe1->sender;
auto* receiver1 = &pipe1->receiver;
auto* sender2 = &pipe2->sender;
auto* receiver2 = &pipe2->receiver;
auto* sender3 = &pipe3->sender;
auto* receiver3 = &pipe3->receiver;
return Seq(Join(Seq(sender1->Push(1),
[done] {
*done = true;
return 1;
}),
Seq(receiver1->Next(),
[sender2](NextResult<int> r) mutable {
return sender2->Push(r.value());
}),
Seq(receiver2->Next(),
[sender3](NextResult<int> r) mutable {
return sender3->Push(r.value());
}),
Seq(receiver3->Next(),
[done](NextResult<int> r) {
EXPECT_EQ(r.value(), 1);
EXPECT_FALSE(*done);
return 2;
})),
[](std::tuple<int, bool, bool, int> result) {
EXPECT_EQ(result, std::make_tuple(1, true, true, 2));
return absl::OkStatus();
});
},
NoWakeupScheduler(),
[&on_done](absl::Status status) { on_done.Call(std::move(status)); },
@ -210,7 +384,9 @@ TEST_F(PipeTest, CanFlowControlThroughManyStages) {
} // namespace grpc_core
int main(int argc, char** argv) {
gpr_log_verbosity_init();
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
grpc_init();
int r = RUN_ALL_TESTS();
grpc_shutdown();
return r;
}

@ -22,6 +22,7 @@
#include <string.h>
#include <algorithm>
#include <memory>
#include <ostream>
#include <string>
#include <vector>
@ -174,6 +175,21 @@ TEST_F(ArenaTest, ConcurrentManagedNew) {
args.arena->Destroy();
}
template <typename Int>
void Scribble(Int* ints, int n, int offset) {
for (int i = 0; i < n; i++) {
ints[i] = static_cast<Int>(i + offset);
}
}
template <typename Int>
bool IsScribbled(Int* ints, int n, int offset) {
for (int i = 0; i < n; i++) {
if (ints[i] != static_cast<Int>(i + offset)) return false;
}
return true;
}
TEST_F(ArenaTest, PooledObjectsArePooled) {
struct TestObj {
char a[100];
@ -181,10 +197,15 @@ TEST_F(ArenaTest, PooledObjectsArePooled) {
auto arena = MakeScopedArena(1024, &memory_allocator_);
auto obj = arena->MakePooled<TestObj>();
Scribble(obj->a, 100, 1);
EXPECT_TRUE(IsScribbled(obj->a, 100, 1));
void* p = obj.get();
obj.reset();
obj = arena->MakePooled<TestObj>();
EXPECT_FALSE(IsScribbled(obj->a, 100, 1));
EXPECT_EQ(p, obj.get());
Scribble(obj->a, 100, 2);
EXPECT_TRUE(IsScribbled(obj->a, 100, 2));
}
TEST_F(ArenaTest, CreateManyObjects) {
@ -196,9 +217,33 @@ TEST_F(ArenaTest, CreateManyObjects) {
objs.reserve(1000);
for (int i = 0; i < 1000; i++) {
objs.emplace_back(arena->MakePooled<TestObj>());
Scribble(objs.back()->a, 100, i);
}
for (int i = 0; i < 1000; i++) {
EXPECT_TRUE(IsScribbled(objs[i]->a, 100, i));
}
}
TEST_F(ArenaTest, CreateManyObjectsWithDestructors) {
using TestObj = std::unique_ptr<int>;
auto arena = MakeScopedArena(1024, &memory_allocator_);
std::vector<Arena::PoolPtr<TestObj>> objs;
objs.reserve(1000);
for (int i = 0; i < 1000; i++) {
objs.emplace_back(arena->MakePooled<TestObj>(new int(i)));
}
}
TEST_F(ArenaTest, CreatePoolArray) {
auto arena = MakeScopedArena(1024, &memory_allocator_);
auto p = arena->MakePooledArray<int>(1024);
EXPECT_FALSE(p.get_deleter().has_freelist());
p = arena->MakePooledArray<int>(5);
EXPECT_TRUE(p.get_deleter().has_freelist());
Scribble(p.get(), 5, 1);
EXPECT_TRUE(IsScribbled(p.get(), 5, 1));
}
} // namespace grpc_core
int main(int argc, char* argv[]) {

@ -347,7 +347,7 @@ INSTANTIATE_TEST_SUITE_P(SliceSizedTest, SliceSizedTest,
}
return out;
}()),
[](const testing::TestParamInfo<size_t>& info) {
[](const ::testing::TestParamInfo<size_t>& info) {
return std::to_string(info.param);
});

@ -147,7 +147,7 @@ class LoggingTest : public ::testing::Test {
std::unique_ptr<EchoTestService::Stub> stub_;
};
TEST_F(LoggingTest, DISABLED_SimpleRpc) {
TEST_F(LoggingTest, SimpleRpc) {
g_test_logging_sink->SetConfig(
grpc::internal::LoggingSink::Config(4096, 4096));
EchoRequest request;
@ -304,7 +304,7 @@ TEST_F(LoggingTest, DISABLED_SimpleRpc) {
"server-trailer-value")))))));
}
TEST_F(LoggingTest, DISABLED_LoggingDisabled) {
TEST_F(LoggingTest, LoggingDisabled) {
g_test_logging_sink->SetConfig(grpc::internal::LoggingSink::Config());
EchoRequest request;
request.set_message("foo");
@ -316,7 +316,7 @@ TEST_F(LoggingTest, DISABLED_LoggingDisabled) {
EXPECT_TRUE(g_test_logging_sink->entries().empty());
}
TEST_F(LoggingTest, DISABLED_MetadataTruncated) {
TEST_F(LoggingTest, MetadataTruncated) {
g_test_logging_sink->SetConfig(grpc::internal::LoggingSink::Config(
40 /* expect truncated metadata*/, 4096));
EchoRequest request;
@ -474,7 +474,7 @@ TEST_F(LoggingTest, DISABLED_MetadataTruncated) {
"server-trailer-value")))))));
}
TEST_F(LoggingTest, DISABLED_PayloadTruncated) {
TEST_F(LoggingTest, PayloadTruncated) {
g_test_logging_sink->SetConfig(grpc::internal::LoggingSink::Config(4096, 10));
EchoRequest request;
// The following message should get truncated
@ -635,7 +635,7 @@ TEST_F(LoggingTest, DISABLED_PayloadTruncated) {
"server-trailer-value")))))));
}
TEST_F(LoggingTest, DISABLED_CancelledRpc) {
TEST_F(LoggingTest, CancelledRpc) {
g_test_logging_sink->SetConfig(
grpc::internal::LoggingSink::Config(4096, 4096));
EchoRequest request;

@ -2224,6 +2224,7 @@ src/core/lib/iomgr/call_combiner.cc \
src/core/lib/iomgr/call_combiner.h \
src/core/lib/iomgr/cfstream_handle.cc \
src/core/lib/iomgr/cfstream_handle.h \
src/core/lib/iomgr/closure.cc \
src/core/lib/iomgr/closure.h \
src/core/lib/iomgr/combiner.cc \
src/core/lib/iomgr/combiner.h \
@ -2379,19 +2380,19 @@ src/core/lib/promise/activity.cc \
src/core/lib/promise/activity.h \
src/core/lib/promise/arena_promise.h \
src/core/lib/promise/context.h \
src/core/lib/promise/detail/basic_join.h \
src/core/lib/promise/detail/basic_seq.h \
src/core/lib/promise/detail/promise_factory.h \
src/core/lib/promise/detail/promise_like.h \
src/core/lib/promise/detail/status.h \
src/core/lib/promise/detail/switch.h \
src/core/lib/promise/exec_ctx_wakeup_scheduler.h \
src/core/lib/promise/for_each.h \
src/core/lib/promise/if.h \
src/core/lib/promise/interceptor_list.h \
src/core/lib/promise/intra_activity_waiter.h \
src/core/lib/promise/latch.h \
src/core/lib/promise/loop.h \
src/core/lib/promise/map.h \
src/core/lib/promise/map_pipe.h \
src/core/lib/promise/pipe.cc \
src/core/lib/promise/pipe.h \
src/core/lib/promise/poll.h \
src/core/lib/promise/promise.h \
@ -2399,7 +2400,9 @@ src/core/lib/promise/race.h \
src/core/lib/promise/seq.h \
src/core/lib/promise/sleep.cc \
src/core/lib/promise/sleep.h \
src/core/lib/promise/try_concurrently.h \
src/core/lib/promise/trace.cc \
src/core/lib/promise/trace.h \
src/core/lib/promise/try_join.h \
src/core/lib/promise/try_seq.h \
src/core/lib/resolver/resolver.cc \
src/core/lib/resolver/resolver.h \
@ -2554,6 +2557,7 @@ src/core/lib/slice/slice.h \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_buffer.h \
src/core/lib/slice/slice_internal.h \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_refcount.h \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/slice/slice_string_helpers.h \

@ -2006,6 +2006,7 @@ src/core/lib/iomgr/call_combiner.cc \
src/core/lib/iomgr/call_combiner.h \
src/core/lib/iomgr/cfstream_handle.cc \
src/core/lib/iomgr/cfstream_handle.h \
src/core/lib/iomgr/closure.cc \
src/core/lib/iomgr/closure.h \
src/core/lib/iomgr/combiner.cc \
src/core/lib/iomgr/combiner.h \
@ -2161,19 +2162,19 @@ src/core/lib/promise/activity.cc \
src/core/lib/promise/activity.h \
src/core/lib/promise/arena_promise.h \
src/core/lib/promise/context.h \
src/core/lib/promise/detail/basic_join.h \
src/core/lib/promise/detail/basic_seq.h \
src/core/lib/promise/detail/promise_factory.h \
src/core/lib/promise/detail/promise_like.h \
src/core/lib/promise/detail/status.h \
src/core/lib/promise/detail/switch.h \
src/core/lib/promise/exec_ctx_wakeup_scheduler.h \
src/core/lib/promise/for_each.h \
src/core/lib/promise/if.h \
src/core/lib/promise/interceptor_list.h \
src/core/lib/promise/intra_activity_waiter.h \
src/core/lib/promise/latch.h \
src/core/lib/promise/loop.h \
src/core/lib/promise/map.h \
src/core/lib/promise/map_pipe.h \
src/core/lib/promise/pipe.cc \
src/core/lib/promise/pipe.h \
src/core/lib/promise/poll.h \
src/core/lib/promise/promise.h \
@ -2181,7 +2182,9 @@ src/core/lib/promise/race.h \
src/core/lib/promise/seq.h \
src/core/lib/promise/sleep.cc \
src/core/lib/promise/sleep.h \
src/core/lib/promise/try_concurrently.h \
src/core/lib/promise/trace.cc \
src/core/lib/promise/trace.h \
src/core/lib/promise/try_join.h \
src/core/lib/promise/try_seq.h \
src/core/lib/resolver/resolver.cc \
src/core/lib/resolver/resolver.h \
@ -2336,6 +2339,7 @@ src/core/lib/slice/slice.h \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_buffer.h \
src/core/lib/slice/slice_internal.h \
src/core/lib/slice/slice_refcount.cc \
src/core/lib/slice/slice_refcount.h \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/slice/slice_string_helpers.h \

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

Loading…
Cancel
Save