From 487e6dabd8c30545e494be07cae6f2ab891b64e7 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Tue, 11 Aug 2026 01:51:16 +0200 Subject: [PATCH 1/2] Fix nvexec upon_stopped completions --- include/nvexec/stream/upon_stopped.cuh | 19 +++++---- test/nvexec/upon_stopped.cpp | 53 ++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/include/nvexec/stream/upon_stopped.cuh b/include/nvexec/stream/upon_stopped.cuh index cb7668c59..d4bc55478 100644 --- a/include/nvexec/stream/upon_stopped.cuh +++ b/include/nvexec/stream/upon_stopped.cuh @@ -106,7 +106,7 @@ namespace nv::execution::_strm status == cudaSuccess) { opstate_.defer_temp_storage_destruction(d_result); - opstate_.propagate_completion_signal(STDEXEC::set_value, *d_result); + opstate_.propagate_completion_signal(STDEXEC::set_value, std::move(*d_result)); } else { @@ -131,19 +131,24 @@ namespace nv::execution::_strm struct upon_stopped_sender : stream_sender_base { using sender_concept = STDEXEC::sender_tag; - using _set_error_t = completion_signatures; template using receiver_t = _upon_stopped::receiver; + template + using __error_completions_t = + __minvoke_q<__concat_completion_signatures_t, + __with_error_invoke_t<__mbind_front_q<__callable_error_t, upon_stopped_t>, + set_stopped_t, + Fun, + __copy_cvref_t, + Env...>, + completion_signatures>; + template using completion_signatures = __transform_completion_signatures_t< __completion_signatures_of_t<__copy_cvref_t, Env...>, - __with_error_invoke_t<__mbind_front_q<__callable_error_t, upon_stopped_t>, - set_stopped_t, - Fun, - __copy_cvref_t, - Env...>, + __error_completions_t, __cmplsigs::__default_set_value, __cmplsigs::__default_set_error, __set_value_from_t>; diff --git a/test/nvexec/upon_stopped.cpp b/test/nvexec/upon_stopped.cpp index 09fca2890..dad905ba9 100644 --- a/test/nvexec/upon_stopped.cpp +++ b/test/nvexec/upon_stopped.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include "common.cuh" #include "nvexec/stream_context.cuh" @@ -10,6 +12,45 @@ using nvexec::is_on_gpu; namespace { + struct move_only_result + { + STDEXEC_ATTRIBUTE(host, device) + explicit move_only_result(int value) noexcept + : value_(value) + {} + + STDEXEC_ATTRIBUTE(host, device) + move_only_result(move_only_result&& other) noexcept + : value_(other.value_) + { + other.value_ = 0; + } + + move_only_result(move_only_result const &) = delete; + + STDEXEC_ATTRIBUTE(host, device) + ~move_only_result() = default; + + STDEXEC_ATTRIBUTE(host, device) + auto value() const noexcept -> int + { + return value_; + } + + private: + int value_; + }; + + TEST_CASE("nvexec upon_stopped advertises CUDA launch errors", + "[cuda][stream][adaptors][upon_stopped]") + { + auto fun = []() noexcept {}; + using sender_t = nvexec::_strm::upon_stopped_sender, + decltype(fun)>; + sender_t snd{a_sender_of{}, std::move(fun)}; + + check_err_types>(snd); + } TEST_CASE("nvexec upon_stopped returns a sender", "[cuda][stream][adaptors][upon_stopped]") { @@ -41,4 +82,16 @@ namespace REQUIRE(flags_storage.all_set_once()); } + + TEST_CASE("nvexec upon_stopped moves its result", "[cuda][stream][adaptors][upon_stopped]") + { + nvexec::stream_context stream_ctx{}; + + auto snd = ex::just_stopped() | ex::continues_on(stream_ctx.get_scheduler()) + | ex::upon_stopped([] { return move_only_result{42}; }); + + auto [result] = STDEXEC::sync_wait(std::move(snd)).value(); + + REQUIRE(result.value() == 42); + } } // namespace From 7bf023a929d32abc185c0428526e6c8c86708b6f Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Thu, 13 Aug 2026 09:59:21 -0700 Subject: [PATCH 2/2] clang-format --- test/nvexec/upon_stopped.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/nvexec/upon_stopped.cpp b/test/nvexec/upon_stopped.cpp index dad905ba9..1b7438f8b 100644 --- a/test/nvexec/upon_stopped.cpp +++ b/test/nvexec/upon_stopped.cpp @@ -45,8 +45,8 @@ namespace "[cuda][stream][adaptors][upon_stopped]") { auto fun = []() noexcept {}; - using sender_t = nvexec::_strm::upon_stopped_sender, - decltype(fun)>; + using sender_t = + nvexec::_strm::upon_stopped_sender, decltype(fun)>; sender_t snd{a_sender_of{}, std::move(fun)}; check_err_types>(snd);