1 /* 2 * Copyright (c) 2021-2024 NVIDIA Corporation 3 * 4 * Licensed under the Apache License Version 2.0 with LLVM Exceptions 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * https://llvm.org/LICENSE.txt 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include "__execution_fwd.hpp" 19 20 #include "__as_awaitable.hpp" 21 #include "__concepts.hpp" 22 #include "../coroutine.hpp" // IWYU pragma: keep for __coro::coroutine_handle 23 24 #include <exception> 25 26 namespace stdexec { 27 #if !STDEXEC_STD_NO_COROUTINES() 28 namespace __was { 29 template <class _Promise = void> 30 class __coroutine_handle; 31 32 template <> 33 class __coroutine_handle<void> : __coro::coroutine_handle<> { 34 public: 35 __coroutine_handle() = default; 36 37 template <class _Promise> __coroutine_handle(__coro::coroutine_handle<_Promise> __coro)38 __coroutine_handle(__coro::coroutine_handle<_Promise> __coro) noexcept 39 : __coro::coroutine_handle<>(__coro) { 40 if constexpr (requires(_Promise& __promise) { __promise.unhandled_stopped(); }) { 41 __stopped_callback_ = [](void* __address) noexcept -> __coro::coroutine_handle<> { 42 // This causes the rest of the coroutine (the part after the co_await 43 // of the sender) to be skipped and invokes the calling coroutine's 44 // stopped handler. 45 return __coro::coroutine_handle<_Promise>::from_address(__address) 46 .promise() 47 .unhandled_stopped(); 48 }; 49 } 50 // If _Promise doesn't implement unhandled_stopped(), then if a "stopped" unwind 51 // reaches this point, it's considered an unhandled exception and terminate() 52 // is called. 53 } 54 55 [[nodiscard]] handle() const56 auto handle() const noexcept -> __coro::coroutine_handle<> { 57 return *this; 58 } 59 60 [[nodiscard]] unhandled_stopped() const61 auto unhandled_stopped() const noexcept -> __coro::coroutine_handle<> { 62 return __stopped_callback_(address()); 63 } 64 65 private: 66 using __stopped_callback_t = __coro::coroutine_handle<> (*)(void*) noexcept; 67 __anon7e953c250202(void*) 68 __stopped_callback_t __stopped_callback_ = [](void*) noexcept -> __coro::coroutine_handle<> { 69 std::terminate(); 70 }; 71 }; 72 73 template <class _Promise> 74 class __coroutine_handle : public __coroutine_handle<> { 75 public: 76 __coroutine_handle() = default; 77 __coroutine_handle(__coro::coroutine_handle<_Promise> __coro)78 __coroutine_handle(__coro::coroutine_handle<_Promise> __coro) noexcept 79 : __coroutine_handle<>{__coro} { 80 } 81 from_promise(_Promise & __promise)82 static auto from_promise(_Promise& __promise) noexcept -> __coroutine_handle { 83 return __coroutine_handle(__coro::coroutine_handle<_Promise>::from_promise(__promise)); 84 } 85 promise() const86 auto promise() const noexcept -> _Promise& { 87 return __coro::coroutine_handle<_Promise>::from_address(address()).promise(); 88 } 89 handle() const90 auto handle() const noexcept -> __coro::coroutine_handle<_Promise> { 91 return __coro::coroutine_handle<_Promise>::from_address(address()); 92 } 93 operator __coro::coroutine_handle<_Promise>() const94 operator __coro::coroutine_handle<_Promise>() const noexcept { 95 return handle(); 96 } 97 }; 98 99 struct __with_awaitable_senders_base { 100 template <class _OtherPromise> set_continuationstdexec::__was::__with_awaitable_senders_base101 void set_continuation(__coro::coroutine_handle<_OtherPromise> __hcoro) noexcept { 102 static_assert(!__same_as<_OtherPromise, void>); 103 __continuation_ = __hcoro; 104 } 105 set_continuationstdexec::__was::__with_awaitable_senders_base106 void set_continuation(__coroutine_handle<> __continuation) noexcept { 107 __continuation_ = __continuation; 108 } 109 110 [[nodiscard]] continuationstdexec::__was::__with_awaitable_senders_base111 auto continuation() const noexcept -> __coroutine_handle<> { 112 return __continuation_; 113 } 114 unhandled_stoppedstdexec::__was::__with_awaitable_senders_base115 auto unhandled_stopped() noexcept -> __coro::coroutine_handle<> { 116 return __continuation_.unhandled_stopped(); 117 } 118 119 private: 120 __coroutine_handle<> __continuation_{}; 121 }; 122 123 template <class _Promise> 124 struct with_awaitable_senders : __with_awaitable_senders_base { 125 template <class _Value> await_transformstdexec::__was::with_awaitable_senders126 auto await_transform(_Value&& __val) -> __call_result_t<as_awaitable_t, _Value, _Promise&> { 127 static_assert(derived_from<_Promise, with_awaitable_senders>); 128 return as_awaitable(static_cast<_Value&&>(__val), static_cast<_Promise&>(*this)); 129 } 130 }; 131 } // namespace __was 132 133 using __was::with_awaitable_senders; 134 using __was::__coroutine_handle; 135 #endif 136 } // namespace stdexec 137