| 175 | } |
| 176 | |
| 177 | constexpr void start() noexcept |
| 178 | { |
| 179 | // Scenario: there are no more split senders, this is the only operation state, the |
| 180 | // underlying operation has not yet been started, and the receiver's stop token is already |
| 181 | // in the "stop requested" state. Then registering the stop callback will call |
| 182 | // __local_state::operator() on *this synchronously. It may also be called asynchronously |
| 183 | // at any point after the callback is registered. Beware. We are guaranteed, however, that |
| 184 | // __local_state::operator() will not complete the operation or decrement the shared state's |
| 185 | // ref count until after *this has been added to the waiters list. |
| 186 | auto const __stok = STDEXEC::get_stop_token(STDEXEC::get_env(__rcvr_)); |
| 187 | __on_stop_.emplace(__stok, *this); |
| 188 | |
| 189 | // We haven't put __state in the waiters list yet and we are holding a ref count to |
| 190 | // __sh_state_, so nothing can happen to the __sh_state_ here. |
| 191 | |
| 192 | // Start the shared op. As an optimization, skip it if the receiver's stop token has already |
| 193 | // been signaled. |
| 194 | if (!__stok.stop_requested()) |
| 195 | { |
| 196 | __sh_state_->__try_start(); |
| 197 | if (__sh_state_->__try_add_waiter(this, __stok)) |
| 198 | { |
| 199 | // successfully added the waiter |
| 200 | return; |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | // Otherwise, failed to add the waiter because of a stop-request. |
| 205 | // Complete synchronously with set_stopped(). |
| 206 | __on_stop_.reset(); |
| 207 | std::exchange(__sh_state_, {})->__detach(); |
| 208 | STDEXEC::set_stopped(static_cast<_Receiver&&>(__rcvr_)); |
| 209 | } |
| 210 | |
| 211 | // Stop request callback: |
| 212 | constexpr void operator()() noexcept |
nothing calls this directly
no test coverage detected