From e3e8fc0f3b310b2abe4ea8eda59d0ff0ecf197c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Ondru=C5=A1ek?= Date: Wed, 7 Jun 2023 14:00:48 -0700 Subject: [PATCH] forward receiver queries in `debug_async_scope` --- include/unifex/detail/debug_async_scope.hpp | 8 +++++ test/debug_async_scope_test.cpp | 37 +++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/unifex/detail/debug_async_scope.hpp b/include/unifex/detail/debug_async_scope.hpp index ffde6d429..0c1a5e16d 100644 --- a/include/unifex/detail/debug_async_scope.hpp +++ b/include/unifex/detail/debug_async_scope.hpp @@ -144,6 +144,14 @@ struct _receiver::type final { } void set_done() noexcept { op_->complete(unifex::set_done); } + + template(typename CPO) // + (requires is_receiver_query_cpo_v) // + friend auto tag_invoke(CPO cpo, const type& r) noexcept( + is_nothrow_callable_v) + -> callable_result_t { + return std::move(cpo)(std::as_const(r.op_->receiver_)); + } }; template diff --git a/test/debug_async_scope_test.cpp b/test/debug_async_scope_test.cpp index e3eb1dc21..7ee11c953 100644 --- a/test/debug_async_scope_test.cpp +++ b/test/debug_async_scope_test.cpp @@ -13,10 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include #include #include #include +#include #include #include #include @@ -53,6 +55,41 @@ TEST(Debug, DISABLED_SyncWaitDeadlockV1Meth) { })); } +TEST(Debug, DISABLED_SyncWaitDeadlockV1TooLate) { + single_thread_context ctx; + v1::debug_async_scope scope; + async_manual_reset_event evt; + std::atomic_bool scheduled{false}; + + // wait for evt to be set on a background thread; note that the `async_wait()` + // _Sender_ is unstoppable + auto fut = scope.spawn_on( + ctx.get_scheduler(), + sequence( + just_from([&scheduled]() noexcept { scheduled = true; }), + evt.async_wait())); + + // wait for the scheduled op to be started + while (!scheduled) { + continue; + } + // send a stop request to all the Senders spawned within the scope; this will + // trigger the future to cancel itself, but not the unstoppable `async_wait()` + scope.request_stop(); + + // with the scope joined, pending futures should all immediately + // complete with done. result has no value. + auto result = sync_wait(std::move(fut)); + ASSERT_FALSE(result.has_value()); + + // but the scope itself won't complete until the spawned work is actually + // done so we will be stuck waiting for the event to be signaled + sync_wait(scope.cleanup()); + + // it's too late. this should be called before `scope.cleanup()` + evt.set(); +} + TEST(Debug, DISABLED_SyncWaitDeadlockV2) { v2::debug_async_scope scope; spawn_detached(