@@ -21,35 +21,49 @@ struct Fut;
2121
2222namespace detail {
2323
24+ template <typename T>
25+ concept NotReactor = !std::same_as<Reactor, T>;
26+
2427template <typename T, typename E>
2528struct CoroutinePromiseType : CoroListNode {
26- CoroutinePromiseType () noexcept = default ;
29+
30+ CoroutinePromiseType (Reactor &reactor, NotReactor auto const &...) noexcept
31+ // reuse m_out to pass reactor to future to avoid creating additional buffer
32+ : m_reactor{reactor} {
33+ }
34+
35+ CoroutinePromiseType (NotReactor auto const &, Reactor &reactor,
36+ NotReactor auto const &...) noexcept
37+ : CoroutinePromiseType{reactor} {
38+ }
2739
2840 CoroutinePromiseType (const CoroutinePromiseType &) = delete ;
2941 CoroutinePromiseType (CoroutinePromiseType &&) = delete ;
3042 CoroutinePromiseType &operator =(const CoroutinePromiseType &) = delete ;
3143 CoroutinePromiseType &operator =(CoroutinePromiseType &&) = delete ;
3244
33- ~CoroutinePromiseType () {
34- assert (m_out);
35- m_out->m_promise = nullptr ;
45+ ~CoroutinePromiseType () override = default ;
46+
47+ static void *operator new (size_t n, Reactor &reactor, NotReactor auto const &...) noexcept {
48+ return reactor.allocate (n);
3649 }
3750
38- template < typename ... ARGS>
39- static void * operator new ( size_t n, ARGS & &...) noexcept {
40- return Reactor::instance (). allocate_frame (n);
51+ static void * operator new ( size_t n, NotReactor auto const &, Reactor &reactor,
52+ NotReactor auto const &...) noexcept {
53+ return reactor. allocate (n);
4154 }
4255
43- static void operator delete (void *frame) noexcept {
44- return Reactor::instance ().free_frame (frame);
56+ static void operator delete (void *) noexcept {
57+ // nothing to do in here since reactor is not accessible. instead, a coro frame is released when
58+ // future is destroyed
4559 }
4660
4761 void yield_to_reactor () noexcept {
48- Reactor::instance () .yield (*this );
62+ m_reactor .yield (*this );
4963 }
5064
5165 void poll_to_reactor (PollListNode &node) noexcept {
52- Reactor::instance () .poll (node);
66+ m_reactor .poll (node);
5367 }
5468
5569 [[noreturn]] static void unhandled_exception () noexcept {
@@ -64,21 +78,37 @@ struct CoroutinePromiseType : CoroListNode {
6478 }
6579
6680 auto final_suspend () noexcept {
67- return std::suspend_never{};
81+ struct ReturnControlToCaller {
82+ static bool await_ready () noexcept {
83+ return false ;
84+ }
85+
86+ static auto await_suspend (std::coroutine_handle<CoroutinePromiseType> self) noexcept {
87+ return self.promise ().m_waiting_coro ;
88+ }
89+
90+ static void await_resume () noexcept {
91+ }
92+ };
93+
94+ // coro frame must be destroyed in Fut dtor so we don't let it fall off the end here
95+ return ReturnControlToCaller{};
6896 }
6997
7098 template <std::convertible_to<Result<T, E>> U>
7199 void return_value (U &&value) noexcept {
72100 // NOLINTBEGIN false positives about m_out being uninitialized
73101 assert (m_out);
102+ assert (!m_out->m_value );
103+ assert (!m_waiting_coro.done ());
74104 m_out->m_value .emplace (std::forward<U>(value));
75- m_waiting_coro.resume ();
76105 // NOLINTEND
77106 }
78107
79108 template <std::convertible_to<T> T2, std::convertible_to<E> E2 >
80109 void return_value (Result<T2, E2 > &&result) noexcept {
81110 assert (m_out);
111+ assert (!m_out->m_value );
82112 if (result.has_value ()) {
83113 if constexpr (std::same_as<void , T>) {
84114 m_out->m_value .emplace (success ());
@@ -88,7 +118,8 @@ struct CoroutinePromiseType : CoroListNode {
88118 } else {
89119 m_out->m_value .emplace (std::move (result.assume_error ()));
90120 }
91- m_waiting_coro.resume ();
121+
122+ assert (!m_waiting_coro.done () && " Waiting coro was destroyed before child has finished" );
92123 }
93124
94125private:
@@ -99,6 +130,7 @@ struct CoroutinePromiseType : CoroListNode {
99130 friend struct Fut <T, E>;
100131
101132 std::coroutine_handle<> m_waiting_coro = std::noop_coroutine();
133+ Reactor &m_reactor;
102134 Fut<T, E> *m_out = nullptr ;
103135};
104136
@@ -110,10 +142,10 @@ struct [[nodiscard("forgot to await?")]] Fut {
110142
111143 Fut (const Fut &) = delete ;
112144 Fut (Fut &&rhs) noexcept
113- : m_promise {std::exchange (rhs.m_promise , nullptr )},
145+ : m_handle {std::exchange (rhs.m_handle , nullptr )},
114146 m_value{std::exchange (rhs.m_value , std::nullopt )} {
115- if (m_promise ) {
116- m_promise-> m_out = this ;
147+ if (m_handle ) {
148+ m_handle. promise (). m_out = this ;
117149 }
118150 }
119151
@@ -124,13 +156,21 @@ struct [[nodiscard("forgot to await?")]] Fut {
124156 return *this ;
125157 };
126158
159+ ~Fut () {
160+ if (m_handle != nullptr ) {
161+ Reactor &reactor = m_handle.promise ().m_reactor ;
162+ m_handle.destroy ();
163+ reactor.free (m_handle.address ());
164+ }
165+ }
166+
127167 [[nodiscard]] bool has_value () const noexcept {
128168 return m_value.has_value ();
129169 }
130170
131171 Result<T, extend_error<E, SyscallError>> block_on () && noexcept {
132172 while (!m_value.has_value ()) {
133- Result res = Reactor::instance () .do_event_loop_iteration ();
173+ Result res = m_handle. promise (). m_reactor .do_event_loop_iteration ();
134174 if (!res) {
135175 return failure (res.assume_error ());
136176 }
@@ -157,10 +197,11 @@ struct [[nodiscard("forgot to await?")]] Fut {
157197 }
158198
159199 void await_suspend (std::coroutine_handle<> h) const noexcept {
160- m_future.m_promise -> m_waiting_coro = h;
200+ m_future.m_handle . promise (). m_waiting_coro = h;
161201 }
162202
163203 Result<T, E> await_resume () const noexcept {
204+ assert (m_future.m_value .has_value ());
164205 return *std::move (m_future.m_value );
165206 }
166207
@@ -172,31 +213,26 @@ struct [[nodiscard("forgot to await?")]] Fut {
172213 Fut &m_future;
173214 };
174215
175- Awaiter operator co_await () noexcept {
216+ Awaiter operator co_await () && noexcept {
176217 return Awaiter{*this };
177218 }
178219
179220private:
180- Fut (promise_type &prom ) noexcept : m_promise{&prom } {
221+ Fut (std::coroutine_handle< promise_type> handle ) noexcept : m_handle{handle } {
181222 }
182223
183224 Fut (AllocationError e) noexcept : m_value{failure (e)} {
184225 }
185226
186227 friend promise_type;
187228
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 ;
229+ std::coroutine_handle<promise_type> m_handle = nullptr ;
230+ [[no_unique_address]] std::optional<Result<T, E>> m_value = std::nullopt ;
195231};
196232
197233template <typename T, typename E>
198234Fut<T, E> detail::CoroutinePromiseType<T, E>::get_return_object() noexcept {
199- Fut<T, E> fut{*this };
235+ Fut<T, E> fut{std::coroutine_handle<CoroutinePromiseType>:: from_promise ( *this ) };
200236 m_out = &fut;
201237 return fut;
202238}
0 commit comments