make_future: take run_loop& directly, removing the __loop_ access entirely#7248
Conversation
|
Can one of the admins verify this patch? |
Up to standards ✅🟢 Issues
|
There was a problem hiding this comment.
Pull request overview
Refactors hpx::execution::experimental::make_future so the run-loop-backed path takes an explicit run_loop& instead of recovering the loop from a run_loop::scheduler, simplifying the implementation around sender-to-future bridging in the execution layer.
Changes:
- Replaces the scheduler-based run-loop extraction path in
make_futurewith directrun_loop&plumbing. - Adds a dedicated
inject_run_looppartial adapter somake_future(loop)can still be used in pipe form. - Updates run-loop unit tests from
make_future(sched, ...)tomake_future(loop, ...).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
libs/core/execution/include/hpx/execution/algorithms/make_future.hpp |
Reworks make_future overloads and shared-state construction to take run_loop& directly. |
libs/core/execution/include/hpx/execution/algorithms/detail/inject_scheduler.hpp |
Adds the new inject_run_loop partial adapter used by make_future(loop). |
libs/core/execution/tests/unit/algorithm_run_loop.cpp |
Updates run-loop make_future call sites and adds basic pipe-form coverage for the new loop overload. |
| hpx::execution::experimental::run_loop& loop, Sender&& sender, | ||
| Allocator const& allocator = Allocator{}) | ||
| { | ||
| return detail::make_future_with_run_loop( | ||
| sched, HPX_FORWARD(Sender, sender), allocator); | ||
| loop, HPX_FORWARD(Sender, sender), allocator); |
There was a problem hiding this comment.
i removed the scheduler-based binary tag_invoke overload, the tag_override_invoke constraint is_completion_scheduler_tag_invocable_v<set_value_t, Sender, make_future_t, Allocator> evaluates to false for run-loop-backed senders, so make_future(transfer_just(sched, ...)) falls to detail::make_future which never drives the loop → hang.
| friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke(make_future_t, | ||
| hpx::execution::experimental::run_loop& loop, | ||
| Allocator const& allocator = Allocator{}) | ||
| { | ||
| return hpx::execution::experimental::detail::inject_run_loop< | ||
| make_future_t, Allocator>{loop, allocator}; |
There was a problem hiding this comment.
inject_scheduler partial was returned by make_future(scheduler) but had nothing to dispatch to (no binary tag_invoke(make_future_t, scheduler, sender, alloc) overload exists for any scheduler type after this PR: there only ever was one for run_loop::scheduler, which was replaced)
| [[maybe_unused]] auto sched = loop.get_scheduler(); | ||
|
|
||
| auto f = ex::just(3) | ex::make_future(sched); | ||
| auto f = ex::just(3) | ex::make_future(loop); |
|
@hkaiser cmake -G "Visual Studio 17 2022" is failing with "could not find any instance of Visual Studio" on the Windows runner. Affects windows_release_2022.yml and windows_clang_release.yml. |
| hpx::execution::experimental::run_loop& loop, Sender&& sender, | ||
| Allocator const& allocator = Allocator{}) | ||
| { | ||
| return detail::make_future_with_run_loop( | ||
| sched, HPX_FORWARD(Sender, sender), allocator); | ||
| loop, HPX_FORWARD(Sender, sender), allocator); |
| friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke(make_future_t, | ||
| hpx::execution::experimental::run_loop& loop, | ||
| Allocator const& allocator = Allocator{}) | ||
| { | ||
| return hpx::execution::experimental::detail::inject_run_loop< | ||
| make_future_t, Allocator>{loop, allocator}; |
| // was removed when the `make_future` API moved to taking `run_loop&` | ||
| // explicitly: there was no longer any binary | ||
| // `tag_invoke(Tag, scheduler, sender, alloc)` overload for the partial | ||
| // to dispatch to.) |
There was a problem hiding this comment.
I think we should leave the old inject_scheduler in place as it may be used in other places. The inject_run_loop could be simply added on top of the existing functionalities.
| friend auto tag_invoke(make_future_t, | ||
| decltype(std::declval<hpx::execution::experimental::run_loop>() | ||
| .get_scheduler()) const& sched, | ||
| Sender&& sender, Allocator const& allocator = Allocator{}) | ||
| hpx::execution::experimental::run_loop& loop, Sender&& sender, | ||
| Allocator const& allocator = Allocator{}) | ||
| { | ||
| return detail::make_future_with_run_loop( | ||
| sched, HPX_FORWARD(Sender, sender), allocator); | ||
| loop, HPX_FORWARD(Sender, sender), allocator); |
| friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke(make_future_t, | ||
| hpx::execution::experimental::run_loop& loop, | ||
| Allocator const& allocator = Allocator{}) | ||
| { | ||
| return hpx::execution::experimental::detail::inject_run_loop< | ||
| make_future_t, Allocator>{loop, allocator}; |
| [[maybe_unused]] auto sched = loop.get_scheduler(); | ||
|
|
||
| auto f = ex::transfer_just(sched, 3) | ex::make_future(); | ||
| auto f = ex::transfer_just(sched, 3) | ex::make_future(loop); |
Please rebase onto master, this has been fixed there. |
Signed-off-by: guptapratykshh <pratykshgupta9999@gmail.com>
… explicitly in implicit-extraction tests, strengthen pipe coverage
…eparate driver thread
d9f4481 to
1fc1401
Compare
| @@ -421,6 +387,24 @@ namespace hpx::execution::experimental { | |||
| HPX_FORWARD(Scheduler, scheduler), allocator}; | |||
| } | |||
|
|
|||
| // Sibling of `inject_scheduler` that holds a reference to a `run_loop` | ||
| // instead of a scheduler. Used so that `make_future(loop)` yields a | ||
| // pipe-able adapter which, when piped with a sender, dispatches | ||
| // `tag_invoke(Tag, run_loop&, sender, ...)`. | ||
| HPX_CXX_CORE_EXPORT template <typename Tag, typename... Ts> | ||
| struct inject_run_loop | ||
| : partial_algorithm_base<Tag, hpx::util::make_index_pack_t<sizeof...(Ts)>, | ||
| Ts...> | ||
| { | ||
| private: | ||
| // Stored as a pointer because the partial may be moved and references | ||
| // can't be re-bound; the `run_loop&` lifetime is the caller's | ||
| // responsibility (the same as the `scheduler` case). | ||
| hpx::execution::experimental::run_loop* loop_; | ||
|
|
…ll site, add explicit run_loop include in inject_scheduler.hpp
…defaulted template arg on friend)
| friend constexpr auto tag_fallback_invoke(make_future_t, | ||
| typename hpx::execution::experimental::run_loop::scheduler const&) = | ||
| delete; | ||
|
|
||
| // clang-format off | ||
| template <typename Allocator, | ||
| HPX_CONCEPT_REQUIRES_( | ||
| hpx::traits::is_allocator_v<Allocator> | ||
| )> | ||
| // clang-format on | ||
| friend constexpr auto tag_fallback_invoke(make_future_t, | ||
| typename hpx::execution::experimental::run_loop::scheduler const&, | ||
| Allocator const&) = delete; |
| friend constexpr HPX_FORCEINLINE auto operator|( | ||
| U&& u, inject_run_loop p) | ||
| { | ||
| return HPX_MOVE(p).invoke(*p.loop_, HPX_FORWARD(U, u)); |
…aulted template args reject = delete on friends)
…, add NOLINT for use-after-move in inject_run_loop
| template <typename Sender, | ||
| typename Allocator = hpx::util::internal_allocator<>, | ||
| HPX_CONCEPT_REQUIRES_( | ||
| hpx::execution::experimental::is_sender_v<Sender> | ||
| )> | ||
| // clang-format on | ||
| friend auto tag_invoke(make_future_t, | ||
| decltype(std::declval<hpx::execution::experimental::run_loop>() | ||
| .get_scheduler()) const& sched, | ||
| Sender&& sender, Allocator const& allocator = Allocator{}) | ||
| hpx::execution::experimental::run_loop& loop, Sender&& sender, | ||
| Allocator const& allocator = Allocator{}) | ||
| { |
| // `make_future(loop.get_scheduler())` is intentionally rejected at | ||
| // the call site: the run-loop-backed binary | ||
| // `tag_invoke(make_future_t, run_loop::scheduler, sender, alloc)` | ||
| // overload is gone (replaced by the `run_loop&` overload above). | ||
| // Without these deletes, the generic scheduler partial above would | ||
| // accept the call, return an `inject_scheduler`, and fail with a | ||
| // confusing substitution error only when the partial is later piped | ||
| // with a sender. Use `make_future(loop, sender)` / | ||
| // `sender | make_future(loop)` instead. |
Proposed Changes
hpx::execution::experimental::make_futureto accept arun_loop&directly instead of recovering it from arun_loop::scheduler. Thetag_invoke(make_future_t, ...)overload now takesrun_loop&as its first argument; a newtag_fallback_invokeoverload makesmake_future(loop)pipe-able with a sender via a smallinject_run_looppartial-algorithm adapter (sibling of the existinginject_scheduler).detail::get_run_loop_from_schedulerhelper introduced in make_future: isolate __loop_ private-member access in single detail helper #7247 — it's no longer needed since the loop is now passed explicitly.algorithm_run_loopunit test's threemake_future(sched, ...)callsites tomake_future(loop, ...).Any background context you want to provide?
Checklist
Not all points below apply to all pull requests.