From 8cd4f2ed4dc072b578e56f4939b1a00392980330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 15 Mar 2026 20:33:33 +0000 Subject: [PATCH 1/2] rebase the P3941 wording on P3826r3 - add get_completion_domain in the quoted synopsis - change SCHED-ENV to use get_start_scheduler instead of get_scheduler - remove the write_env use from on (should have been done by P3826r3) - change on to use get_start_scheduler instead of get_scheduler - update the sentence for make-sender(affine_on...) - change affine_on to use continues_on instead of schedule_from - update the reference paragraph numbers in [exec.run.loop.types] --- docs/P3941-affinity.md | 142 +++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 78 deletions(-) diff --git a/docs/P3941-affinity.md b/docs/P3941-affinity.md index 69d175f..128f52d 100644 --- a/docs/P3941-affinity.md +++ b/docs/P3941-affinity.md @@ -1,7 +1,7 @@ --- title: Scheduler Affinity -document: P3941R2 -date: 2026-02-23 +document: D3941R3 +date: 2026-03-14 audience: - Concurrency Working Group (SG1) - Library Evolution Working Group (LEWG) @@ -31,6 +31,10 @@ meet its objective at run-time. # Change History +## R3 + +- rebase changes on the customization changes [P3826r3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3826r3.html) + ## R2 - added requirement on `get_scheduler`/`get_start_scheduler` @@ -549,6 +553,13 @@ algorithm a better name. # Wording Changes +::: ednote +This wording is relative to [N5032](https://wg21.link/N5032) with +the changes from +[P3826r3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3826r3.html) +applied. +::: + ::: ednote If `get_start_scheduler` is introduced add it to the synopsis in [execution.syn] after `get_scheduler` as follows: @@ -565,6 +576,8 @@ namespace std::execution { struct get_forward_progress_guarantee_t { @_unspecified_@ }; template struct get_completion_scheduler_t { @_unspecified_@ }; + template + struct get_completion_domain_t { @_unspecified_@ }; struct get_await_completion_adaptor_t { @_unspecified_@ }; inline constexpr get_domain_t get_domain{}; @@ -575,6 +588,8 @@ namespace std::execution { inline constexpr get_forward_progress_guarantee_t get_forward_progress_guarantee{}; template constexpr get_completion_scheduler_t get_completion_scheduler{}; + template + constexpr get_completion_domain_t get_completion_domain{}; inline constexpr get_await_completion_adaptor_t get_await_completion_adaptor{}; ... } @@ -609,13 +624,30 @@ expression `get_start_scheduler(get_env(rcvr))` is well-formed, an operation state that is the result of calling `connect(sndr, rcvr)` shall, if it is started, be started on an execution agent associated with the scheduler `get_start_scheduler(get_env(rcvr))`. +::: + +::: ednote + +If `get_start_scheduler` is introduced change +[[exec.snd.expos](https://wg21.link/exec.snd.expos)] paragraph 8 to have SCHED-ENV +use `get_start_scheduler` instead of `get_scheduler`: ::: +[8]{.pnum} SCHED-ENV(sch) is an expression `o2` whose type +satisfies queryable such that `o2.query(@[get_scheduler]{.rm}@@[get_start_scheduler]{.add}@)` +is a prvalue with the same type and value as `sch`, and such that +`o2.query(get_domain)` is expression-equivalent to `sch.query(get_domain)`. + + ::: ednote -If `get_start_scheduler` is introduced change how `on` gets its -scheduler in [exec.on], i.e., change the use from `get_scheduler` -to use `get_start_scheduler`: +The specification of `on` [[exec.on](https://wg21.link/exec.on)] shouldn't use `write_env` as it does, +i.e., this change removes these (not removing them was an oversight +in +[P3826](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3826r3.html)). +In addition, if `get_start_scheduler` is introduced change how `on` +gets its scheduler in [[exec.on](https://wg21.link/exec.on)], i.e., change the use from +`get_scheduler` to use `get_start_scheduler`: :::

@@ -623,41 +655,31 @@ to use `get_start_scheduler`:

-The expression `on.transform_sender(out_sndr, env)` has effects equivalent to: +[8]{.pnum} Otherwise, the expression `on.transform_sender(set_value, out_sndr, env)` has effects equivalent to:

``` auto&& [_, data, child] = out_sndr; if constexpr (scheduler) { auto orig_sch = - @_query-with-default_@(get_@[start_]{.add}@scheduler, env, @_not-a-scheduler_@()); - - if constexpr (same_as) { - return @_not-a-sender_@{}; - } else { - return continues_on( - starts_on(std::forward_like(data), std::forward_like(child)), - std::move(orig_sch)); - } + call-with-default(@[get_scheduler]{.rm}@@[get_start_scheduler]{.add}@, @_not-a-scheduler_@(), env); + + return continues_on( + starts_on(std::forward_like(data), std::forward_like(child)), + std::move(orig_sch)); } else { auto& [sch, closure] = data; - auto orig_sch = @_query-with-default_@( - get_completion_scheduler, - get_env(child), - @_query-with-default_@(get_@[start_]{.add}@scheduler, env, @_not-a-scheduler_@())); - - if constexpr (same_as) { - return @_not-a-sender_@{}; - } else { - return write_env( - continues_on( - std::forward_like(closure)( - continues_on( - write_env(std::forward_like(child), @_SCHED-ENV_@(orig_sch)), - sch)), - orig_sch), - @_SCHED-ENV_@(sch)); - } + auto orig_sch = @_call-with-default_@( + get_completion_scheduler, @_not-a-scheduler_@(), get_env(child), env); + + return continues_on( + @[write_env(]{.rm}@ + std::forward_like(closure)( + continues_on( + @[write_env(]{.rm}@std::forward_like(child)@[,]{.rm}@ @[_SCHED-ENV_(orig_sch))]{.rm}@, + sch)), + @[_SCHED-ENV_(sch)),]{.rm}@ + orig_sch); } ```

@@ -770,26 +792,8 @@ satisfy sender, affine_on(sndr[, sch]{.rm}) is ill-formed. [3]{.pnum} Otherwise, the expression affine_on(sndr[, sch]{.rm}) -is expression-equivalent to: -transform_sender(_get-domain-early_(sndr), _make-sender_(affine_on, -[sch]{.rm}[env<>()]{.add}, sndr)) except that `sndr` -is evaluated only once. - -[4]{.pnum} -The exposition-only class template _impls-for_ -([exec.snd.expos]) is specialized for `affine_on_t` as follows: - -```c++ -namespace std::execution { - template<> - struct impls-for : default-impls { - static constexpr auto get-attrs = - [](const auto&@[ data]{.rm}]@, const auto& child) noexcept -> decltype(auto) { - return @[_JOIN-ENV_(_SCHED-ATTRS_(data),_FWD-ENV_(]{.rm}@get_env(child)@[))]{.rm}@; - }; - }; -} -``` +is expression-equivalent to +`@_make-sender_@(affine_on, @[sch]{.rm}@@[env<>()]{.add}@, sndr)`. :::{.add} [?]{.pnum} @@ -806,13 +810,13 @@ if constexpr (requires(const child_tag_t& t){ t.affine_on(child, ev); }) return t.affine_on(child, ev); else return write_env( - schedule_from(get_start_scheduler(get_env(ev)), write_env(std::move(child), ev)), + continues_on(write_env(std::move(child), ev), get_start_scheduler(get_env(ev))), JOIN-ENV(env{prop{get_stop_token, never_stop_token()}}, ev) ); ``` [Note 1: This causes the `affine_on(sndr)` sender to become -`schedule_from(sch, sndr)` when it is connected with a receiver +`continues_on(sdnr, sch)` when it is connected with a receiver `rcvr` whose execution domain does not customize `affine_on`, for which `get_start_scheduler(get_env(rcvr))` is `sch`, and `affine_on` isn't specialized for the child sender. @@ -875,26 +879,8 @@ satisfy sender, affine_on(sndr[, sch]{.rm}) is ill-formed. [3]{.pnum} Otherwise, the expression affine_on(sndr[, sch]{.rm}) -is expression-equivalent to: -transform_sender(_get-domain-early_(sndr), _make-sender_(affine_on, -[sch]{.rm}[env<>()]{.add}, sndr)) except that `sndr` -is evaluated only once. - -[4]{.pnum} -The exposition-only class template _impls-for_ -([exec.snd.expos]) is specialized for `affine_on_t` as follows: - -```c++ -namespace std::execution { - template<> - struct impls-for : default-impls { - static constexpr auto get-attrs = - [](const auto&@[ data]{.rm}]@, const auto& child) noexcept -> decltype(auto) { - return @[_JOIN-ENV_(_SCHED-ATTRS_(data),_FWD-ENV_(]{.rm}@get_env(child)@[))]{.rm}@; - }; - }; -} -``` +is expression-equivalent to +`@_make-sender_@(affine_on, @[sch]{.rm}@@[env<>()]{.add}@, sndr)`. :::{.add} [?]{.pnum} @@ -911,13 +897,13 @@ if constexpr (requires(const child_tag_t& t){ t.affine_on(child, ev); }) return t.affine_on(child, ev); else return write_env( - schedule_from(get_scheduler(get_env(ev)), write_env(std::move(child), ev)), + continues_on(write_env(std::move(child), ev), get_scheduler(get_env(ev))), JOIN-ENV(env{prop{get_stop_token, never_stop_token()}}, ev) ); ``` [Note 1: This causes the `affine_on(sndr)` sender to become -`schedule_from(sch, sndr)` when it is connected with a receiver +`continues_on(sndr, sch)` when it is connected with a receiver `rcvr` whose execution domain does not customize `affine_on`, for which `get_scheduler(get_env(rcvr))` is `sch`, and `affine_on` isn't specialized for the child sender. @@ -1128,7 +1114,7 @@ In [exec.run.loop.types] change the paragraph defining the completion signatures class run-loop-sender; ``` -[5]{.pnum} +[6]{.pnum} run-loop-sender is an exposition-only type that satisfies `sender`. [Let `E` be the type of an environment. If `unstoppable_token()))>` is `true`, then ]{.add} completion_signatures_of_t<run-loop-sender[, E]{.add}> is @@ -1149,7 +1135,7 @@ Otherwise it is ``` ::: -[6]{.pnum} An instance of run-loop-sender remains +[7]{.pnum} An instance of run-loop-sender remains valid until the end of the lifetime of its associated `run_loop` instance. From df3b3397b11fadeac011685c501c4d81980709fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Sun, 15 Mar 2026 21:26:21 +0000 Subject: [PATCH 2/2] fixed typos noted by the AI (the other changes AI comments on are intentional) --- docs/P3941-affinity.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/P3941-affinity.md b/docs/P3941-affinity.md index 128f52d..d3efe2d 100644 --- a/docs/P3941-affinity.md +++ b/docs/P3941-affinity.md @@ -662,7 +662,7 @@ gets its scheduler in [[exec.on](https://wg21.link/exec.on)], i.e., change the u auto&& [_, data, child] = out_sndr; if constexpr (scheduler) { auto orig_sch = - call-with-default(@[get_scheduler]{.rm}@@[get_start_scheduler]{.add}@, @_not-a-scheduler_@(), env); + @_call-with-default_@(@[get_scheduler]{.rm}@@[get_start_scheduler]{.add}@, @_not-a-scheduler_@(), env); return continues_on( starts_on(std::forward_like(data), std::forward_like(child)), @@ -816,7 +816,7 @@ else ``` [Note 1: This causes the `affine_on(sndr)` sender to become -`continues_on(sdnr, sch)` when it is connected with a receiver +`continues_on(sndr, sch)` when it is connected with a receiver `rcvr` whose execution domain does not customize `affine_on`, for which `get_start_scheduler(get_env(rcvr))` is `sch`, and `affine_on` isn't specialized for the child sender.