You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Clarify completion scheduler semantics for timed scheduler fallbacks #2165
PR #2164 restores get_completion_scheduler<set_value_t> on the lazy fallbacks for schedule_at and schedule_after.
The implementation can inspect the type of the completion scheduler returned by the native timed sender, but then returns the scheduler passed into the fallback. This is correct if timed_scheduler requires native timed operations to complete on that exact scheduler value. However, timed_scheduler currently only requires schedule_at and schedule_after to return senders.
For example, a scheduler S{context_a} could return a sender whose completion scheduler is S{context_b}. The types match, but the execution resources do not. The fallback would advertise context_a even though the native sender completes on context_b.
There is also a cv/ref question. The native sender type is probed using _Scheduler, but the actual call happens later from a non-mutable lambda and sees the captured scheduler as const S&. Ref-qualified overloads can therefore produce a different native sender type from the one inspected by the fallback.
Could we clarify the intended contract?
If schedule_at and schedule_after must complete on the supplied scheduler value, should timed_scheduler document or require that?
If not, should the fallback omit the completion-scheduler query unless equality can be established?
Should the fallback also preserve completion-scheduler queries that depend on the receiver environment, or is that out of scope?
The fallback must keep now() lazy. Issue #847 explains why computing the native sender eagerly is not equivalent.
Read the current fallback in include/exec/timed_scheduler.hpp (main at 653aca1).
On the three questions:
On documenting vs requiring: I think putting the requirement on the scheduler itself is the right move, because it is what makes the fallback's static check sound. timed_scheduler today only requires the CPOs to return senders. If the concept instead required that the completion scheduler for set_value_t compare equal to the argument scheduler (where the scheduler type is equality-comparable), the fallback's check becomes verifiable, and schedulers that can't compare equal simply don't advertise a completion scheduler through the fallback.
On omitting the query unless equality can be established: I would strengthen rather than omit. Add a value comparison to __completion_scheduler_matches -- query the native sender env, compare against the stored scheduler with == when the type supports it, and drop the claim when the comparison fails or isn't available. Omitting entirely would also take the claim away from correctly-implementing schedulers, and today nothing in the check distinguishes the S{context_a} / S{context_b} same-type case.
On preserving receiver-environment-dependent completion-scheduler queries: that seems out of scope for the fallback. The native sender is constructed inside a let_value lambda at subscribe time, so a receiver-dependent answer isn't knowable statically. Reads to me as a documented limitation rather than something to engineer around.
The cv/ref mismatch is real and probably fixable on its own: the fallback probes the native sender type with __call_result_t<__schedule_at_base_t, _Scheduler, ...> using the value category deduced at the call site, but the lambda always invokes the native CPO through a const capture (the lambdas aren't mutable), so for a ref-qualified schedule_at, schedule_after(pool.get_scheduler(), d) probes through S&& while the actual subscription goes through const S&. Probing through the same const-qualified lvalue the lambda captures would make the probe and the actual call agree. Happy to send that as a small separate PR if useful, independent of the concept question.
Activity
alwaysprince05 commentedon Oct 26, 2026
Read the current fallback in
include/exec/timed_scheduler.hpp(main at 653aca1).On the three questions:
On documenting vs requiring: I think putting the requirement on the scheduler itself is the right move, because it is what makes the fallback's static check sound.
timed_schedulertoday only requires the CPOs to return senders. If the concept instead required that the completion scheduler forset_value_tcompare equal to the argument scheduler (where the scheduler type is equality-comparable), the fallback's check becomes verifiable, and schedulers that can't compare equal simply don't advertise a completion scheduler through the fallback.On omitting the query unless equality can be established: I would strengthen rather than omit. Add a value comparison to
__completion_scheduler_matches-- query the native sender env, compare against the stored scheduler with==when the type supports it, and drop the claim when the comparison fails or isn't available. Omitting entirely would also take the claim away from correctly-implementing schedulers, and today nothing in the check distinguishes the S{context_a} / S{context_b} same-type case.On preserving receiver-environment-dependent completion-scheduler queries: that seems out of scope for the fallback. The native sender is constructed inside a let_value lambda at subscribe time, so a receiver-dependent answer isn't knowable statically. Reads to me as a documented limitation rather than something to engineer around.
The cv/ref mismatch is real and probably fixable on its own: the fallback probes the native sender type with
__call_result_t<__schedule_at_base_t, _Scheduler, ...>using the value category deduced at the call site, but the lambda always invokes the native CPO through a const capture (the lambdas aren't mutable), so for a ref-qualifiedschedule_at,schedule_after(pool.get_scheduler(), d)probes throughS&&while the actual subscription goes throughconst S&. Probing through the same const-qualified lvalue the lambda captures would make the probe and the actual call agree. Happy to send that as a small separate PR if useful, independent of the concept question.fix(exec): probe timed scheduler fallback through the const-lvalue sc…