From d8f4922b167cfb62fc956378b30ed207040390d9 Mon Sep 17 00:00:00 2001 From: ericniebler Date: Mon, 18 Mar 2024 22:51:19 +0000 Subject: [PATCH] Publish: Merge pull request #204 from cplusplus/fix-start-detached feedback from LWG wording review Mar 18: `start_detached` 273aedb7a7c2e5da38ed9687358eac525bc9bada --- execution.html | 224 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 165 insertions(+), 59 deletions(-) diff --git a/execution.html b/execution.html index 0e26404..2b657fc 100644 --- a/execution.html +++ b/execution.html @@ -2347,7 +2347,7 @@

D2300R9
std::execution

-

Draft Proposal,

+

Draft Proposal,

Authors: @@ -3780,7 +3780,7 @@

2.2.

Make it valid to pass non-variadic templates to the exposition-only alias template gather-signatures, fixing the definitions of value_types_of_t, error_types_of_t, and the exposition-only alias -template sync-wait-type.

+template sync-wait-result-type.

  • Removed the query forwarding from receiver_adaptor that was inadvertantly left over from a previous edit.

    @@ -6083,6 +6083,20 @@

  • For function types F1 and F2 denoting R1(Args1...) and R2(Args2...) respectively, MATCHING-SIG(F1, F2) is true if and only if same_as<R1(Args&&...), R2(Args2&&...)> is true.

    +
  • +

    For a subexpression err, let Err be decltype((err)) and let AS-EXCEPT-PTR(err) be:

    +
      +
    1. +

      err if decay_t<Err> denotes the type exception_ptr.

      +
        +
      • +

        Mandates: err != exception_ptr() is true

        +
      +
    2. +

      Otherwise, make_exception_ptr(system_error(err)) if decay_t<Err> denotes the type error_code,

      +
    3. +

      Otherwise, make_exception_ptr(err).

      +

    11.2. Queries and queryables [exec.queryable]

    @@ -6637,9 +6651,9 @@

    struct sync-wait-env; // exposition only template<class Sndr> requires sender_in<Sndr, sync-wait-env> - using sync-wait-type = see below; // exposition only + using sync-wait-result-type = see below; // exposition only template<class Sndr> - using sync-wait-with-variant-type = see below; // exposition only + using sync-wait-with-variant-result-type = see below; // exposition only struct sync_wait_t; struct sync_wait_with_variant_t; @@ -9094,7 +9108,7 @@
    stopped_as_optional denotes a customization point object. For some subexpression sndr, let Sndr be decltype((sndr)). The expression stopped_as_optional(sndr) is expression-equivalent to:

    transform_sender(
    -  get-sender-domain(sndr),
    +  get-domain-early(sndr),
       make-sender(stopped_as_optional, {}, sndr))
     
  • @@ -9118,7 +9132,7 @@
    stopped_as_error denotes a customization point object. For some subexpressions sndr and err, let Sndr be decltype((sndr)) and let Err be decltype((err)). If the type Sndr does not satisfy sender or if the type Err doesn’t satisfy movable-value, stopped_as_error(sndr, err) is ill-formed. Otherwise, the expression stopped_as_error(sndr, err) is expression-equivalent to:

    transform_sender(
    -  get-sender-domain(sndr),
    +  get-domain-early(sndr),
       make-sender(stopped_as_error, err, sndr))
     
  • @@ -9139,12 +9153,13 @@
    start_detached denotes a customization point object. For some subexpression sndr, let Sndr be decltype((sndr)). If sender_in<Sndr, empty_env> is false, start_detached is ill-formed. -Otherwise, the expression start_detached(sndr) is expression-equivalent to:

    -
    apply_sender(get-sender-domain(sndr), start_detached, sndr)
    +Otherwise, the expression start_detached(sndr) is expression-equivalent to
    +the following except that sndr is evaluated only once:

    +
    apply_sender(get-domain-early(sndr), start_detached, sndr)
     
    • -

      Mandates: The type of the expression above is void.

      +

      Mandates: same_as<decltype(e), void> is true where e is the expression above.

    If the expression above does not eagerly start the sender sndr after connecting it with a receiver that ignores value and stopped completion @@ -9160,7 +9175,7 @@

    sender_to<Sndr, detached-receiver> is false, the expression start_detached.apply_sender(sndr) is ill-formed; otherwise, it is -expression-equivalent to start(*new detached-operation(sndr)).

    +expression-equivalent to start((new detached-operation(sndr))->op).

    11.9.11.2. this_thread::sync_wait [exec.sync.wait]
    1. this_thread::sync_wait and this_thread::sync_wait_with_variant are used -to block a current thread until a sender passed into it as an argument has -completed, and to obtain the values (if any) it completed with. sync_wait requires that the input sender has exactly one value completion signature.

      -
    2. -

      For any receiver rcvr created by an implementation of sync_wait and sync_wait_with_variant, the expressions get_scheduler(get_env(rcvr)) and get_delegatee_scheduler(get_env(rcvr)) shall be well-formed. For a receiver -created by the default implementation of this_thread::sync_wait, these -expressions shall return a scheduler to the same thread-safe, -first-in-first-out queue of work such that tasks scheduled to the queue -execute on the thread of the caller of sync_wait. [Note: The -scheduler for an instance of run_loop that is a local variable -within sync_wait is one valid implementation. -- end note]

      -
    3. -

      The templates sync-wait-type and sync-wait-with-variant-type are used to determine the -return types of this_thread::sync_wait and this_thread::sync_wait_with_variant. Let sync-wait-env be the type of the expression get_env(rcvr) where rcvr is an instance of the -receiver created by the default implementation of sync_wait.

      +to block the current thread of execution until the specified sender +completes and to return its async result. sync_wait mandates that the +input sender has exactly one value completion signature.

      +
    4. +

      Let sync-wait-env be the following exposition-only class +type:

      +
      template<class Tag>
      +concept get-sched-query = // exposition only
      +  one-of<Tag, execution::get_scheduler_t, execution::get_delegatee_scheduler_t>;
      +
      +struct sync-wait-env {
      +  execution::run_loop* loop; // exposition only
      +
      +  friend auto tag_invoke(get-sched-query auto, sync-wait-env self) noexcept {
      +    return self.loop->get_scheduler();
      +  }
      +};
      +
      +
    5. +

      Let sync-wait-result-type and sync-wait-with-variant-result-type be exposition-only +template aliases that are defined as follows:

      template<sender_in<sync-wait-env> Sndr>
      -  using sync-wait-type =
      +  using sync-wait-result-type =
           optional<value_types_of_t<Sndr, sync-wait-env, decayed-tuple, type_identity_t>>;
       
       template<sender_in<sync-wait-env> Sndr>
      -  using sync-wait-with-variant-type = optional<into-variant-type<Sndr, sync-wait-env>>;
      +  using sync-wait-with-variant-result-type =
      +    optional<into-variant-type<Sndr, sync-wait-env>>; // see [exec.into.variant]
       
    6. -

      The name this_thread::sync_wait denotes a customization point object. For -some subexpression sndr, let Sndr be decltype((sndr)). If sender_in<Sndr, sync-wait-env> is false, -or if the type completion_signatures_of_t<Sndr, sync-wait-env, type-list, type_identity_t> is ill-formed, this_thread::sync_wait(sndr) is ill-formed. -Otherwise, this_thread::sync_wait(sndr) is expression-equivalent to:

      +

      The name this_thread::sync_wait denotes a customization point object. For a +subexpression sndr, let Sndr be decltype((sndr)). If sender_in<Sndr, sync-wait-env> is false, the +expression this_thread::sync_wait(sndr) is ill-formed. Otherwise, it is +expression-equivalent to the following, except that sndr is evaluated only +once:

      apply_sender(get-domain-early(sndr), sync_wait, sndr)
       
      +

      Mandates:

      • -

        Mandates: The type of the expression above is sync-wait-type<Sndr, sync-wait-env>.

        +

        The type sync-wait-result-type<Sndr> is well-formed.

        +
      • +

        same_as<decltype(e), sync-wait-result-type<Sndr>> is true, where e is the expression above.

    7. -

      Let sync-wait-receiver be a class type that satisfies receiver, let rcvr be an xvalue of that type, -and let crcvr be a const lvalue referring to rcvr such that get_env(crcvr) has type sync-wait-env. -If sender_in<Sndr, sync-wait-env> is false, or if the type completion_signatures_of_t<Sndr, sync-wait-env, type-list, type_identity_t> is ill-formed, -the expression sync_wait_t().apply_sender(sndr) is ill-formed; otherwise it has the following effects:

      +

      Let sync-wait-receiver be the following exposition-only class template:

      +
      template<class Sndr>
      +struct sync-wait-state {
      +  run_loop loop;
      +  exception_ptr error;
      +  sync-wait-result-type<Sndr> result;
      +};
      +
      +template<class Sndr>
      +struct sync-wait-receiver {
      +  using receiver_concept = receiver_t;
      +  sync-wait-state<Sndr>* state; // exposition only
      +
      +  template<class Tag, class... Ts>
      +  void complete(Tag, Ts&&... ts) noexcept; // exposition only
      +
      +  template<completion-tag Tag, class... Ts>
      +  friend void tag_invoke(Tag, sync-wait-receiver&& self, Ts&&... ts) noexcept {
      +    self.complete(Tag(), std::forward<Ts>(ts)...);
      +    self.state->loop.finish();
      +  }
      +
      +  friend sync-wait-env tag_invoke(get_env_t, const sync-wait-receiver& self) noexcept {
      +    return {&self.state->loop};
      +  }
      +};
      +
      +
        +
      1. +

        The member sync-wait-receiver::complete behaves as follows:

        +
          +
        1. +

          If Tag is set_value_t, evaluates:

          +
          try {
          +  state->result.emplace(std::forward<Ts>(ts)...);
          +} catch (...) {
          +  state->error = current_exception();
          +}
          +
          +
        2. +

          Otherwise, if Tag is set_error_t, evaluates:

          +
          state->error = AS-EXCEPT-PTR(std::forward(ts)...); // see [exec.general]
          +
          +
        3. +

          Otherwise, does nothing.

          +
        +
      +
    8. +

      For a subexpression sndr, let Sndr be decltype((sndr)). If sender_in<Sndr, sync-wait-env> is false, the +expression sync_wait.apply_sender(sndr) is ill-formed; otherwise, it is +equivalent to:

      +
      sync-wait-state<Sndr> state;
      +auto op = connect(sndr, sync-wait-receiver<Sndr>{&state});
      +start(op);
      +
      +state.loop.run();
      +if (state.error) {
      +  rethrow_exception(std::move(state.error));
      +}
      +return std::move(state.result);
      +
      +
    9. +

      The behavior of this_thread::sync_wait(sndr) is undefined unless:

      1. -

        Calls connect(sndr, rcvr), resulting in an operation state op_state, then calls start(op_state).

        +

        It blocks the current thread of execution with forward progress guarantee +delegation ([intro.progress]) until the specified sender completes, and

      2. -

        Blocks the current thread until a completion operation of rcvr is executed. When it is:

        +

        It returns the specified sender’s async results as follows:

        1. -

          If set_value(rcvr, ts...) has been called, returns sync-wait-type<Sndr, sync-wait-env>{decayed-tuple<decltype(ts)...>{ts...}}. If that expression exits exceptionally, the exception is propagated to the caller of sync_wait.

          +

          For a value completion, the result datums are returned +in a tuple in an engaged optional object.

        2. -

          If set_error(rcvr, err) has been called, let Err be the decayed type of err. If Err is exception_ptr, calls rethrow_exception(err). Otherwise, if the Err is error_code, throws system_error(err). Otherwise, throws err.

          +

          For an error completion, the result datum is rethrown.

        3. -

          If set_stopped(rcvr) has been called, returns sync-wait-type<Sndr, sync-wait-env>{}.

          +

          For a stopped completion, a disengaged optional object is returned.

    10. The name this_thread::sync_wait_with_variant denotes a customization point -object. For some subexpression sndr, let Sndr be the type of into_variant(sndr). If sender_in<Sndr, sync-wait-env> is false, this_thread::sync_wait_with_variant(sndr) is ill-formed. Otherwise, this_thread::sync_wait_with_variant(sndr) is expression-equivalent to:

      -
      apply_sender(get-sender-domain(sndr), sync_wait_with_variant, sndr)
      +object. For a subexpression sndr, let Sndr be the type of into_variant(sndr). If sender_in<Sndr, sync-wait-env> is false, this_thread::sync_wait_with_variant(sndr) is ill-formed. Otherwise, it is
      +expression-equivalent to the following, except sndr is evaluated only
      +once:

      +
      apply_sender(get-domain-early(sndr), sync_wait_with_variant, sndr)
       
      +

      Mandates:

      • -

        Mandates: The type of the expression above is sync-wait-with-variant-type<Sndr, sync-wait-env>.

        +

        The type sync-wait-with-variant-result-type<Sndr> is +well-formed.

        +
      • +

        same_as<decltype(e), sync-wait-with-variant-result-type<Sndr>> is true, +where e is the expression above.

    11. -

      The expression sync_wait_with_variant_t().apply_sender(sndr) is -equal to:

      -
      if (auto opt_value = sync_wait(into_variant(sndr))) {
      -  return std::move(get<0>(*opt_value));
      +     

      If sender_in<Sndr, sync-wait-env> is false, the +expression sync_wait_with_variant.apply_sender(sndr) is ill-formed. +Otherwise, it is equivalent to:

      +
      using result_type = sync-wait-with-variant-result-type<Sndr>;
      +if (auto opt_value = sync_wait(into_variant(sndr))) {
      +  return result_type(std::move(get<0>(*opt_value)));
       }
      -return nullopt;
      +return result_type(nullopt);
       
      +
    12. +

      The behavior of this_thread::sync_wait_with_variant(sndr) is undefined unless:

      +
        +
      1. +

        It blocks the current thread of execution with forward progress guarantee +delegation ([intro.progress]) until the specified sender completes, and

        +
      2. +

        It returns the specified sender’s async results as follows:

        +
          +
        1. +

          For a value completion, the result datums are returned +in a variant of tuples in an engaged optional object.

          +
        2. +

          For an error completion, the result datum is rethrown.

          +
        3. +

          For a stopped completion, a disengaged optional object is returned.

          +
        +

    11.10. execution::execute [exec.execute]

      @@ -9870,18 +9985,9 @@

      set_value(rcvr, vs...) is ill-formed.

    1. The expression set_error(rcvr, err) is equivalent to:

      -
      rcvr.result_ptr_->emplace<2>(AS-EXCEPT-PTR(err));
      +
      rcvr.result_ptr_->emplace<2>(AS-EXCEPT-PTR(err)); // see [exec.general]
       rcvr.continuation_.resume();
       
      -

      where AS-EXCEPT-PTR(err) is:

      -
        -
      1. -

        err if decay_t<Err> names the same type as exception_ptr,

        -
      2. -

        Otherwise, make_exception_ptr(system_error(err)) if decay_t<Err> names the same type as error_code,

        -
      3. -

        Otherwise, make_exception_ptr(err).

        -
    2. The expression set_stopped(rcvr) is equivalent to static_cast<coroutine_handle<>>(rcvr.continuation_.promise().unhandled_stopped()).resume().