1010#include < concepts>
1111#include < coroutine>
1212#include < cstddef>
13- #include < exception>
1413#include < optional>
1514#include < utility>
1615
@@ -21,39 +20,53 @@ struct Fut;
2120
2221namespace detail {
2322
23+ template <typename T>
24+ concept NotReactor = !std::same_as<Reactor, T>;
25+
2426template <typename T, typename E>
2527struct CoroutinePromiseType : CoroListNode {
26- CoroutinePromiseType () noexcept = default ;
28+
29+ CoroutinePromiseType (Reactor &reactor, NotReactor auto const &...) noexcept
30+ // reuse m_out to pass reactor to future to avoid creating additional buffer
31+ : m_reactor{reactor} {
32+ }
33+
34+ CoroutinePromiseType (NotReactor auto const &, Reactor &reactor,
35+ NotReactor auto const &...) noexcept
36+ : CoroutinePromiseType{reactor} {
37+ }
2738
2839 CoroutinePromiseType (const CoroutinePromiseType &) = delete ;
2940 CoroutinePromiseType (CoroutinePromiseType &&) = delete ;
3041 CoroutinePromiseType &operator =(const CoroutinePromiseType &) = delete ;
3142 CoroutinePromiseType &operator =(CoroutinePromiseType &&) = delete ;
3243
33- ~CoroutinePromiseType () {
34- assert (m_out);
35- m_out->m_promise = nullptr ;
44+ ~CoroutinePromiseType () override = default ;
45+
46+ static void *operator new (size_t n, Reactor &reactor, NotReactor auto const &...) noexcept {
47+ return reactor.allocate (n);
3648 }
3749
38- template < typename ... ARGS>
39- static void * operator new ( size_t n, ARGS & &...) noexcept {
40- return Reactor::instance (). allocate_frame (n);
50+ static void * operator new ( size_t n, NotReactor auto const &, Reactor &reactor,
51+ NotReactor auto const &...) noexcept {
52+ return reactor. allocate (n);
4153 }
4254
43- static void operator delete (void *frame) noexcept {
44- return Reactor::instance ().free_frame (frame);
55+ static void operator delete (void *) noexcept {
56+ // nothing to do in here since reactor is not accessible. instead, a coro frame is released when
57+ // future is destroyed
4558 }
4659
4760 void yield_to_reactor () noexcept {
48- Reactor::instance () .yield (*this );
61+ m_reactor .yield (*this );
4962 }
5063
5164 void poll_to_reactor (PollListNode &node) noexcept {
52- Reactor::instance () .poll (node);
65+ m_reactor .poll (node);
5366 }
5467
5568 [[noreturn]] static void unhandled_exception () noexcept {
56- std::terminate ();
69+ std::abort ();
5770 }
5871
5972 Fut<T, E> get_return_object () noexcept ;
@@ -64,21 +77,37 @@ struct CoroutinePromiseType : CoroListNode {
6477 }
6578
6679 auto final_suspend () noexcept {
67- return std::suspend_never{};
80+ struct ReturnControlToCaller {
81+ static bool await_ready () noexcept {
82+ return false ;
83+ }
84+
85+ static auto await_suspend (std::coroutine_handle<CoroutinePromiseType> self) noexcept {
86+ return self.promise ().m_waiting_coro ;
87+ }
88+
89+ static void await_resume () noexcept {
90+ }
91+ };
92+
93+ // coro frame must be destroyed in Fut dtor so we don't let it fall off the end here
94+ return ReturnControlToCaller{};
6895 }
6996
7097 template <std::convertible_to<Result<T, E>> U>
7198 void return_value (U &&value) noexcept {
7299 // NOLINTBEGIN false positives about m_out being uninitialized
73100 assert (m_out);
101+ assert (!m_out->m_value );
102+ assert (!m_waiting_coro.done ());
74103 m_out->m_value .emplace (std::forward<U>(value));
75- m_waiting_coro.resume ();
76104 // NOLINTEND
77105 }
78106
79107 template <std::convertible_to<T> T2, std::convertible_to<E> E2 >
80108 void return_value (Result<T2, E2 > &&result) noexcept {
81109 assert (m_out);
110+ assert (!m_out->m_value );
82111 if (result.has_value ()) {
83112 if constexpr (std::same_as<void , T>) {
84113 m_out->m_value .emplace (success ());
@@ -88,7 +117,8 @@ struct CoroutinePromiseType : CoroListNode {
88117 } else {
89118 m_out->m_value .emplace (std::move (result.assume_error ()));
90119 }
91- m_waiting_coro.resume ();
120+
121+ assert (!m_waiting_coro.done () && " Waiting coro was destroyed before child has finished" );
92122 }
93123
94124private:
@@ -99,6 +129,7 @@ struct CoroutinePromiseType : CoroListNode {
99129 friend struct Fut <T, E>;
100130
101131 std::coroutine_handle<> m_waiting_coro = std::noop_coroutine();
132+ Reactor &m_reactor;
102133 Fut<T, E> *m_out = nullptr ;
103134};
104135
@@ -110,10 +141,10 @@ struct [[nodiscard("forgot to await?")]] Fut {
110141
111142 Fut (const Fut &) = delete ;
112143 Fut (Fut &&rhs) noexcept
113- : m_promise {std::exchange (rhs.m_promise , nullptr )},
144+ : m_handle {std::exchange (rhs.m_handle , nullptr )},
114145 m_value{std::exchange (rhs.m_value , std::nullopt )} {
115- if (m_promise ) {
116- m_promise-> m_out = this ;
146+ if (m_handle ) {
147+ m_handle. promise (). m_out = this ;
117148 }
118149 }
119150
@@ -124,13 +155,21 @@ struct [[nodiscard("forgot to await?")]] Fut {
124155 return *this ;
125156 };
126157
158+ ~Fut () {
159+ if (m_handle != nullptr ) {
160+ Reactor &reactor = m_handle.promise ().m_reactor ;
161+ m_handle.destroy ();
162+ reactor.free (m_handle.address ());
163+ }
164+ }
165+
127166 [[nodiscard]] bool has_value () const noexcept {
128167 return m_value.has_value ();
129168 }
130169
131170 Result<T, extend_error<E, SyscallError>> block_on () && noexcept {
132171 while (!m_value.has_value ()) {
133- Result res = Reactor::instance () .do_event_loop_iteration ();
172+ Result res = m_handle. promise (). m_reactor .do_event_loop_iteration ();
134173 if (!res) {
135174 return failure (res.assume_error ());
136175 }
@@ -157,10 +196,11 @@ struct [[nodiscard("forgot to await?")]] Fut {
157196 }
158197
159198 void await_suspend (std::coroutine_handle<> h) const noexcept {
160- m_future.m_promise -> m_waiting_coro = h;
199+ m_future.m_handle . promise (). m_waiting_coro = h;
161200 }
162201
163202 Result<T, E> await_resume () const noexcept {
203+ assert (m_future.m_value .has_value ());
164204 return *std::move (m_future.m_value );
165205 }
166206
@@ -172,31 +212,26 @@ struct [[nodiscard("forgot to await?")]] Fut {
172212 Fut &m_future;
173213 };
174214
175- Awaiter operator co_await () noexcept {
215+ Awaiter operator co_await () && noexcept {
176216 return Awaiter{*this };
177217 }
178218
179219private:
180- Fut (promise_type &prom ) noexcept : m_promise{&prom } {
220+ Fut (std::coroutine_handle< promise_type> handle ) noexcept : m_handle{handle } {
181221 }
182222
183223 Fut (AllocationError e) noexcept : m_value{failure (e)} {
184224 }
185225
186226 friend promise_type;
187227
188- promise_type *m_promise = nullptr ;
189-
190- struct CoroListNode : bi::slist_base_hook<bi::link_mode<bi::link_mode_type::auto_unlink>> {
191- virtual std::coroutine_handle<> coro_from_this () noexcept = 0;
192- };
193-
194- std::optional<Result<T, E>> m_value = std::nullopt ;
228+ std::coroutine_handle<promise_type> m_handle = nullptr ;
229+ [[no_unique_address]] std::optional<Result<T, E>> m_value = std::nullopt ;
195230};
196231
197232template <typename T, typename E>
198233Fut<T, E> detail::CoroutinePromiseType<T, E>::get_return_object() noexcept {
199- Fut<T, E> fut{*this };
234+ Fut<T, E> fut{std::coroutine_handle<CoroutinePromiseType>:: from_promise ( *this ) };
200235 m_out = &fut;
201236 return fut;
202237}
0 commit comments