fix(execution): correct sends_stopped in bulk and schedule_from completion signatures#7236
Open
arpittkhandelwal wants to merge 1 commit intoTheHPXProject:masterfrom
Conversation
…etion signatures
bulk_sender and schedule_from_sender hard-coded sends_stopped = false in their
generate_completion_signatures struct, even though their internal receivers
unconditionally propagate set_stopped from the upstream sender to the downstream
receiver.
This breaks the Sender/Receiver contract (P2300): a downstream algorithm that
trusts sends_stopped=false may not install a stop handler, causing set_stopped
to arrive on an unprepared receiver — potential undefined behaviour.
Fix bulk_sender to inherit sends_stopped from the upstream:
static constexpr bool sends_stopped = sends_stopped_of_v<Sender, Env>;
Fix schedule_from_sender to reflect that cancellation can arrive from either
the predecessor sender or the scheduler sender:
static constexpr bool sends_stopped =
sends_stopped_of_v<Sender, Env> ||
sends_stopped_of_v<scheduler_sender_type, Env>;
Note: as_sender and keep_future correctly retain sends_stopped=false because
HPX futures have no cancellation mechanism — their receivers never call
set_stopped, so the existing value is accurate and is not changed.
Add tests to algorithm_bulk.cpp that verify:
- bulk over a non-stopping upstream still reports sends_stopped=false
- bulk over a stopped_sender_with_value_type now reports sends_stopped=true
- Chained bulk layers correctly propagate sends_stopped=true
- At runtime, set_stopped is delivered to the downstream receiver
Up to standards ✅🟢 Issues
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes incorrect completion signature contracts in HPX std::execution-style algorithms by ensuring bulk and schedule_from correctly advertise sends_stopped when they can propagate set_stopped at runtime, aligning the static sender contract with actual behavior and avoiding undefined behavior.
Changes:
- Update
bulk_sendercompletion signatures to propagatesends_stoppedfrom the upstream sender. - Update
schedule_from_sendercompletion signatures to propagatesends_stoppedfrom both the predecessor sender and the scheduler’sschedule()sender. - Add unit coverage in
algorithm_bulk.cppto validatebulk’s correctedsends_stoppedbehavior (static checks + runtime stopped delivery).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| libs/core/execution/include/hpx/execution/algorithms/bulk.hpp | Fix bulk_sender completion signatures to reflect upstream sends_stopped. |
| libs/core/execution/include/hpx/execution/algorithms/schedule_from.hpp | Fix schedule_from_sender completion signatures to reflect stopped propagation from predecessor and scheduler sender. |
| libs/core/execution/tests/unit/algorithm_bulk.cpp | Add tests verifying bulk now correctly advertises and forwards set_stopped (non-stdexec path). |
Comment on lines
+64
to
+66
| static constexpr bool sends_stopped = | ||
| sends_stopped_of_v<Sender, Env> || | ||
| sends_stopped_of_v<scheduler_sender_type, Env>; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem Summary
bulk_sender and schedule_from_sender incorrectly hard-coded:
However, both internally propagate cancellation (set_stopped)
from upstream senders to downstream receivers.
This creates a mismatch between the static contract (completion signatures)
and runtime behavior, violating the P2300 std::execution specification
and leading to undefined behavior.
Why This Matters
Completion signatures define what signals a sender may emit.
If sends_stopped is declared false:
=> Undefined behavior
Fix: bulk.hpp
bulk should transparently propagate stopping behavior
from its upstream sender.
BEFORE:
static constexpr bool sends_stopped = false;
AFTER:
static constexpr bool sends_stopped =
sends_stopped_of_v<Sender, Env>;
Fix: schedule_from.hpp
schedule_from can receive cancellation from:
So it must reflect both.
BEFORE:
static constexpr bool sends_stopped = false;
AFTER:
static constexpr bool sends_stopped =
sends_stopped_of_v<Sender, Env> ||
sends_stopped_of_v<scheduler_sender_type, Env>;
Not Changed
as_sender, keep_future:
These wrap HPX futures, which:
So this remains correct:
static constexpr bool sends_stopped = false;
Tests Added
File:
libs/core/execution/tests/unit/algorithm_bulk.cpp
--- Static Tests ---
Non-stopping upstream -> remains false
static_assert(
!check_sends_stopped<
bulk(just(42), {})
Stopping upstream -> propagates true
static_assert(
check_sends_stopped<
bulk(stopped_sender_with_value_type{}, {})
Chained bulk layers propagate correctly
static_assert(
check_sends_stopped<
bulk(
bulk(
stopped_sender_with_value_type{},
{}
),
{}
)
--- Runtime Test ---
Ensure set_stopped is actually delivered
{
auto sender =
bulk(
stopped_sender_with_value_type{},
{}
);
}
Key Insight
Senders must NEVER lie in their completion signatures.
If set_stopped can happen at runtime,
sends_stopped MUST be true at compile time.
bulk and schedule_from are transparent propagators,
so their sends_stopped must reflect upstream behavior.