From 2ac9f94ab8432e20261c182931953ce3b1458d29 Mon Sep 17 00:00:00 2001 From: arpittkhandelwal Date: Wed, 6 May 2026 07:27:53 +0530 Subject: [PATCH 1/4] execution: migrate transform_completion_signatures to avoid deprecation warnings Upstream stdexec deprecated the `stdexec::transform_completion_signatures` and `stdexec::transform_completion_signatures_of` type aliases in favor of the new `exec::transform_completion_signatures` consteval function API. To retain existing semantics in HPX while suppressing deprecation warnings (especially on MSVC with modules), this patch updates the HPX re-exports in `stdexec_forward.hpp` to wrap the private but stable non-deprecated internal `__transform_completion_signatures_t` helpers instead. This also removes now-obsolete `#pragma clang diagnostic` warning suppression blocks from various sender implementations. --- .../include/hpx/execution/algorithms/bulk.hpp | 7 --- .../execution/algorithms/when_all_vector.hpp | 7 --- .../hpx/execution_base/stdexec_forward.hpp | 43 +++++++++++++++++-- .../executors/thread_pool_scheduler_bulk.hpp | 7 --- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/libs/core/execution/include/hpx/execution/algorithms/bulk.hpp b/libs/core/execution/include/hpx/execution/algorithms/bulk.hpp index 8aa3054c3a8b..19362192734c 100644 --- a/libs/core/execution/include/hpx/execution/algorithms/bulk.hpp +++ b/libs/core/execution/include/hpx/execution/algorithms/bulk.hpp @@ -55,10 +55,6 @@ namespace hpx::execution::experimental { hpx::execution::experimental::completion_signatures<>; template -#if defined(HPX_CLANG_VERSION) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif friend auto tag_invoke(get_completion_signatures_t, bulk_sender const&, Env) noexcept -> hpx::execution:: experimental::transform_completion_signatures< @@ -68,9 +64,6 @@ namespace hpx::execution::experimental { hpx::execution::experimental::set_error_t( std::exception_ptr)>, default_set_value, default_set_error, disable_set_stopped>; -#if defined(HPX_CLANG_VERSION) -#pragma clang diagnostic pop -#endif friend constexpr auto tag_invoke( hpx::execution::experimental::get_env_t, diff --git a/libs/core/execution/include/hpx/execution/algorithms/when_all_vector.hpp b/libs/core/execution/include/hpx/execution/algorithms/when_all_vector.hpp index 7588707fcd67..addfafaad883 100644 --- a/libs/core/execution/include/hpx/execution/algorithms/when_all_vector.hpp +++ b/libs/core/execution/include/hpx/execution/algorithms/when_all_vector.hpp @@ -118,10 +118,6 @@ namespace hpx::when_all_vector_detail { hpx::execution::experimental::set_error_t(std::decay_t)>; template -#if defined(HPX_CLANG_VERSION) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif friend auto tag_invoke( hpx::execution::experimental::get_completion_signatures_t, when_all_vector_sender_type const&, Env const&) noexcept @@ -132,9 +128,6 @@ namespace hpx::when_all_vector_detail { hpx::execution::experimental::set_error_t( std::exception_ptr)>, transformed_comp_sigs_identity, decay_set_error>; -#if defined(HPX_CLANG_VERSION) -#pragma clang diagnostic pop -#endif template struct operation_state diff --git a/libs/core/execution_base/include/hpx/execution_base/stdexec_forward.hpp b/libs/core/execution_base/include/hpx/execution_base/stdexec_forward.hpp index 18c4717d4eef..79b3fd4b2e69 100644 --- a/libs/core/execution_base/include/hpx/execution_base/stdexec_forward.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/stdexec_forward.hpp @@ -281,14 +281,51 @@ namespace hpx::execution::experimental { HPX_CXX_CORE_EXPORT using stdexec::then; HPX_CXX_CORE_EXPORT using stdexec::then_t; - // Completion signature manipulators + // Completion signature manipulators: transform_completion_signatures and + // transform_completion_signatures_of. + // + // The stdexec public type-alias variants (stdexec::transform_completion_signatures + // and stdexec::transform_completion_signatures_of) are deprecated in favour of + // the new exec::transform_completion_signatures consteval-function API in + // . HPX re-exports the same functionality using + // the internal (non-deprecated) implementation aliases so that: + // a) Existing HPX call sites that use these as type aliases continue to compile + // without warnings. + // b) New code may include and call + // exec::transform_completion_signatures (the consteval function) directly. + HPX_CXX_CORE_EXPORT using stdexec::completion_signatures_of_t; HPX_CXX_CORE_EXPORT using stdexec::error_types_of_t; HPX_CXX_CORE_EXPORT using stdexec::sends_stopped; HPX_CXX_CORE_EXPORT using stdexec::value_types_of_t; - HPX_CXX_CORE_EXPORT using stdexec::transform_completion_signatures; - HPX_CXX_CORE_EXPORT using stdexec::transform_completion_signatures_of; + // Type-alias variant (kept for existing call sites). Backed by the internal + // (non-deprecated) stdexec::__transform_completion_signatures_t helper. + template , + template class ValueTransform = + stdexec::__cmplsigs::__default_set_value, + template class ErrorTransform = + stdexec::__cmplsigs::__default_set_error, + class StoppedSigs = + stdexec::completion_signatures> + using transform_completion_signatures = + stdexec::__transform_completion_signatures_t; + + // Type-alias variant for the "of_t" variant (sender + env convenience form). + // Backed by stdexec::__transform_completion_signatures_of_t (non-deprecated). + template , + class MoreSigs = stdexec::completion_signatures<>, + template class ValueTransform = + stdexec::__cmplsigs::__default_set_value, + template class ErrorTransform = + stdexec::__cmplsigs::__default_set_error, + class StoppedSigs = + stdexec::completion_signatures> + using transform_completion_signatures_of = + stdexec::__transform_completion_signatures_of_t; + HPX_CXX_CORE_EXPORT using exec::keep_completion; // Transform sender diff --git a/libs/core/executors/include/hpx/executors/thread_pool_scheduler_bulk.hpp b/libs/core/executors/include/hpx/executors/thread_pool_scheduler_bulk.hpp index f0e0b6c88e48..57cba8434a1e 100644 --- a/libs/core/executors/include/hpx/executors/thread_pool_scheduler_bulk.hpp +++ b/libs/core/executors/include/hpx/executors/thread_pool_scheduler_bulk.hpp @@ -708,10 +708,6 @@ namespace hpx::execution::experimental::detail { using sender_concept = hpx::execution::experimental::sender_t; template -#if defined(HPX_CLANG_VERSION) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif friend auto tag_invoke( hpx::execution::experimental::get_completion_signatures_t, thread_pool_bulk_sender const&, Env const&) @@ -720,9 +716,6 @@ namespace hpx::execution::experimental::detail { hpx::execution::experimental::completion_signatures< hpx::execution::experimental::set_error_t( std::exception_ptr)>>; -#if defined(HPX_CLANG_VERSION) -#pragma clang diagnostic pop -#endif struct env { From c6191ef296e6baeefa2187547ca533e7ab0edc2e Mon Sep 17 00:00:00 2001 From: arpittkhandelwal Date: Wed, 6 May 2026 08:33:59 +0530 Subject: [PATCH 2/4] execution: add HPX_CXX_CORE_EXPORT to transform_completion_signatures aliases --- .../include/hpx/execution_base/stdexec_forward.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/core/execution_base/include/hpx/execution_base/stdexec_forward.hpp b/libs/core/execution_base/include/hpx/execution_base/stdexec_forward.hpp index 79b3fd4b2e69..efe49c87515b 100644 --- a/libs/core/execution_base/include/hpx/execution_base/stdexec_forward.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/stdexec_forward.hpp @@ -301,7 +301,8 @@ namespace hpx::execution::experimental { // Type-alias variant (kept for existing call sites). Backed by the internal // (non-deprecated) stdexec::__transform_completion_signatures_t helper. - template , + HPX_CXX_CORE_EXPORT template , template class ValueTransform = stdexec::__cmplsigs::__default_set_value, template class ErrorTransform = @@ -314,7 +315,7 @@ namespace hpx::execution::experimental { // Type-alias variant for the "of_t" variant (sender + env convenience form). // Backed by stdexec::__transform_completion_signatures_of_t (non-deprecated). - template , + HPX_CXX_CORE_EXPORT template , class MoreSigs = stdexec::completion_signatures<>, template class ValueTransform = stdexec::__cmplsigs::__default_set_value, From 8ee217518f689314c8f93a98ea285f607460b2b5 Mon Sep 17 00:00:00 2001 From: arpittkhandelwal Date: Wed, 6 May 2026 21:59:55 +0530 Subject: [PATCH 3/4] async_mpi: fix transform_mpi failure under stdexec (cherry-picked) --- libs/core/async_mpi/tests/unit/algorithm_transform_mpi.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/core/async_mpi/tests/unit/algorithm_transform_mpi.cpp b/libs/core/async_mpi/tests/unit/algorithm_transform_mpi.cpp index 893c10ff5870..96dd85a22005 100644 --- a/libs/core/async_mpi/tests/unit/algorithm_transform_mpi.cpp +++ b/libs/core/async_mpi/tests/unit/algorithm_transform_mpi.cpp @@ -252,8 +252,10 @@ int hpx_main() int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { - // Disable MPI tests because they - // hang due to sync_wait consuming the thread + // Note: Previously disabled under stdexec because sync_wait would hang by + // consuming the calling thread. This is no longer the case with the modern + // stdexec run_loop-based sync_wait implementation, so the guard has been + // removed. MPI_Init(&argc, &argv); auto result = hpx::local::init(hpx_main, argc, argv); From a0bac723693da50810774539df043661ac56a6b0 Mon Sep 17 00:00:00 2001 From: arpittkhandelwal Date: Fri, 8 May 2026 10:16:14 +0530 Subject: [PATCH 4/4] async_mpi: replace sync_wait with make_future to fix MPI poller deadlock stdexec::sync_wait drives its own run_loop and never yields back to the HPX thread pool, so the MPI background poller registered via register_polling() can never fire completion callbacks, causing a deadlock on all platforms. Replace all tt::sync_wait(sender) calls with ex::make_future(sender).get() which converts the sender to an hpx::future and yields the calling HPX thread via hpx::util::yield_while, allowing the background MPI poller to drain the completion queue. Fixes: tests.unit.modules.async_mpi.algorithm_transform_mpi --- .../tests/unit/algorithm_transform_mpi.cpp | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/libs/core/async_mpi/tests/unit/algorithm_transform_mpi.cpp b/libs/core/async_mpi/tests/unit/algorithm_transform_mpi.cpp index 96dd85a22005..1d53ebe68dd4 100644 --- a/libs/core/async_mpi/tests/unit/algorithm_transform_mpi.cpp +++ b/libs/core/async_mpi/tests/unit/algorithm_transform_mpi.cpp @@ -21,7 +21,6 @@ namespace ex = hpx::execution::experimental; namespace mpi = hpx::mpi::experimental; -namespace tt = hpx::this_thread::experimental; // This overload is only used to check dispatching. It is not a useful // implementation. @@ -52,6 +51,11 @@ int hpx_main() // Success path { // MPI function pointer + // Use ex::make_future instead of tt::sync_wait: stdexec's + // sync_wait drives its own run_loop and never yields back to + // the HPX thread pool, so the MPI background poller can never + // fire the completion callback. make_future converts the sender + // to an hpx::future whose .get() yields the calling HPX thread. int data = 0, count = 1; if (rank == 0) { @@ -59,8 +63,7 @@ int hpx_main() } auto s = mpi::transform_mpi( ex::just(&data, count, datatype, 0, comm), MPI_Ibcast); - auto mpi_result = tt::sync_wait(HPX_MOVE(s)); - auto result = hpx::get<0>(*mpi_result); + auto result = ex::make_future(HPX_MOVE(s)).get(); if (rank != 0) { HPX_TEST_EQ(data, 42); @@ -85,8 +88,7 @@ int hpx_main() return MPI_Ibcast( data, count, datatype, i, comm, request); }); - auto mpi_result = tt::sync_wait(HPX_MOVE(s)); - auto result = hpx::get<0>(*mpi_result); + auto result = ex::make_future(HPX_MOVE(s)).get(); if (rank != 0) { HPX_TEST_EQ(data, 42); @@ -110,7 +112,7 @@ int hpx_main() MPI_Comm comm, MPI_Request* request) { MPI_Ibcast(data, count, datatype, i, comm, request); }); - tt::sync_wait(HPX_MOVE(s)); + ex::make_future(HPX_MOVE(s)).get(); if (rank != 0) { HPX_TEST_EQ(data, 42); @@ -126,7 +128,7 @@ int hpx_main() c.x = 3; } auto s = mpi::transform_mpi(c); - tt::sync_wait(s); + ex::make_future(HPX_MOVE(s)).get(); if (rank == 0) { HPX_TEST_EQ(c.x, 3); @@ -142,9 +144,10 @@ int hpx_main() { data = 42; } - auto result = hpx::get<0>( - *tt::sync_wait(ex::just(&data, count, datatype, 0, comm) | - mpi::transform_mpi(MPI_Ibcast))); + auto result = + ex::make_future(ex::just(&data, count, datatype, 0, comm) | + mpi::transform_mpi(MPI_Ibcast)) + .get(); if (rank != 0) { HPX_TEST_EQ(data, 42); @@ -161,9 +164,11 @@ int hpx_main() bool exception_thrown = false; try { - tt::sync_wait(mpi::transform_mpi( - error_sender{}, - MPI_Ibcast)); + ex::make_future( + mpi::transform_mpi(error_sender{}, + MPI_Ibcast)) + .get(); HPX_TEST(false); } catch (std::runtime_error const& e) @@ -187,7 +192,7 @@ int hpx_main() }); try { - tt::sync_wait(HPX_MOVE(s)); + ex::make_future(HPX_MOVE(s)).get(); } catch (std::runtime_error const& e) { @@ -207,8 +212,10 @@ int hpx_main() bool exception_thrown = false; try { - tt::sync_wait(mpi::transform_mpi( - ex::just(data, count, datatype, -1, comm), MPI_Ibcast)); + ex::make_future(mpi::transform_mpi(ex::just(data, count, + datatype, -1, comm), + MPI_Ibcast)) + .get(); HPX_TEST(false); } catch (std::runtime_error const& e) @@ -233,8 +240,10 @@ int hpx_main() bool exception_thrown = false; try { - tt::sync_wait(mpi::transform_mpi( - ex::just(data, count, datatype, -1, comm), MPI_Ibcast)); + ex::make_future(mpi::transform_mpi(ex::just(data, count, + datatype, -1, comm), + MPI_Ibcast)) + .get(); HPX_TEST(false); } catch (std::runtime_error const&) @@ -252,10 +261,6 @@ int hpx_main() int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { - // Note: Previously disabled under stdexec because sync_wait would hang by - // consuming the calling thread. This is no longer the case with the modern - // stdexec run_loop-based sync_wait implementation, so the guard has been - // removed. MPI_Init(&argc, &argv); auto result = hpx::local::init(hpx_main, argc, argv);