@@ -25,11 +25,17 @@ concept NotReactor = !std::same_as<Reactor, T>;
2525
2626template <typename T, typename E>
2727struct CoroutinePromiseType : CoroListNode {
28-
28+ // / @brief Construct new coroutine promise bound to reactor
29+ // / @note For more detailed explanation check
30+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
2931 CoroutinePromiseType (Reactor &reactor, NotReactor auto const &...) noexcept
3032 : m_reactor{reactor} {
3133 }
3234
35+ // / @brief Construct new coroutine promise bound to reactor. This overload is used when some
36+ // / object's method is declared as coroutine
37+ // / @note For more detailed explanation check
38+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
3339 CoroutinePromiseType (NotReactor auto const &,
3440 Reactor &reactor,
3541 NotReactor auto const &...) noexcept
@@ -43,41 +49,63 @@ struct CoroutinePromiseType : CoroListNode {
4349
4450 ~CoroutinePromiseType () override = default ;
4551
52+ // / @brief Allocate new coroutine frame using allocator from reactor
53+ // / @note C++20 coroutine's required method. For more detailed explanation check
54+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
4655 static void *operator new (size_t n, Reactor &reactor, NotReactor auto const &...) noexcept {
4756 return reactor.allocator ().allocate (n);
4857 }
4958
59+ // / @brief Allocate new coroutine frame using allocator from reactor. This overload is used when
60+ // / some object's method is declared as coroutine
61+ // / @note C++20 coroutine's required method. For more detailed explanation check
62+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
5063 static void *operator new (size_t n,
5164 NotReactor auto const &,
5265 Reactor &reactor,
5366 NotReactor auto const &...) noexcept {
5467 return reactor.allocator ().allocate (n);
5568 }
5669
70+ // / @brief Noop
71+ // / @note C++20 coroutine's required method. For more detailed explanation check
72+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
5773 static void operator delete (void *) noexcept {
5874 // nothing to do in here since reactor is not accessible. instead, a coro frame is released when
5975 // future is destroyed
6076 }
6177
78+ // / @brief Add this as a CoroListNode into reactor to be executed later
6279 void yield_to_reactor () noexcept {
63- m_reactor.yield (*this );
80+ m_reactor.schedule (*this );
6481 }
6582
83+ // / @brief Add this PollListNode into reactor to be executed later, when event becomes awailable
6684 void poll_to_reactor (PollListNode &node) noexcept {
67- m_reactor.poll (node);
85+ m_reactor.schedule_when_ready (node);
6886 }
6987
88+ // / @brief Call an abort. Corosig expects no exceptions to be thrown around since they are not
89+ // / safe to throw in sighandlers.
90+ // / @note C++20 coroutine's required method. For more detailed explanation check
91+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
7092 [[noreturn]] static void unhandled_exception () noexcept {
7193 std::abort ();
7294 }
7395
96+ // / @note C++20 coroutine's required method. For more detailed explanation check
97+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
7498 Fut<T, E> get_return_object () noexcept ;
7599 static Fut<T, E> get_return_object_on_allocation_failure () noexcept ;
76100
101+ // / @note C++20 coroutine's required method. For more detailed explanation check
102+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
77103 auto initial_suspend () noexcept {
78104 return std::suspend_never{};
79105 }
80106
107+ // / @note C++20 coroutine's required method. For more detailed explanation check
108+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
81109 auto final_suspend () noexcept {
82110 struct ReturnControlToCaller {
83111 static bool await_ready () noexcept {
@@ -96,6 +124,9 @@ struct CoroutinePromiseType : CoroListNode {
96124 return ReturnControlToCaller{};
97125 }
98126
127+ // / @brief Return a value form coroutine
128+ // / @note C++20 coroutine's required method. For more detailed explanation check
129+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
99130 template <std::convertible_to<Result<T, E>> U>
100131 void return_value (U &&value) noexcept {
101132 assert (m_value.is_nothing ());
@@ -117,8 +148,11 @@ struct CoroutinePromiseType : CoroListNode {
117148
118149} // namespace detail
119150
151+ // / @brief A result, which will become available in the future
120152template <typename T = void , typename E = AllocationError>
121153struct [[nodiscard(" forgot to await?" )]] Fut {
154+ // / @note C++20 coroutine's required typedef. For more detailed explanation check
155+ // / https://en.cppreference.com/w/cpp/language/coroutines.html
122156 using promise_type = detail::CoroutinePromiseType<T, E>;
123157
124158 Fut (const Fut &) = delete ;
@@ -134,10 +168,13 @@ struct [[nodiscard("forgot to await?")]] Fut {
134168 }
135169 }
136170
171+ // / @brief Tell if future is already available. General-purpose code shall not use this method
172+ // / and just simply co_await a future
137173 [[nodiscard]] bool completed () const noexcept {
138174 return m_handle.value == nullptr || !promise ().m_value .is_nothing ();
139175 }
140176
177+ // / @brief Run reactor's event loop until this future is ready
141178 Result<T, extend_error<E, SyscallError>> block_on () && noexcept {
142179 while (!completed ()) {
143180 COROSIG_TRYV (promise ().m_reactor .do_event_loop_iteration ());
@@ -148,39 +185,40 @@ struct [[nodiscard("forgot to await?")]] Fut {
148185 return std::move (promise ().m_value );
149186 }
150187
151- struct Awaiter {
152- Awaiter (const Awaiter &) = delete ;
153- Awaiter (Awaiter &&) = delete ;
154- Awaiter &operator =(const Awaiter &) = delete ;
155- Awaiter &operator =(Awaiter &&) = delete ;
156-
157- [[nodiscard]] bool await_ready () const noexcept {
158- return m_future.completed ();
159- }
188+ // / @brief Await for result inside this future to become available
189+ auto operator co_await () && noexcept {
190+ struct Awaiter {
191+ Awaiter (const Awaiter &) = delete ;
192+ Awaiter (Awaiter &&) = delete ;
193+ Awaiter &operator =(const Awaiter &) = delete ;
194+ Awaiter &operator =(Awaiter &&) = delete ;
160195
161- void await_suspend (std::coroutine_handle<> h ) const noexcept {
162- m_future.promise (). m_waiting_coro = h ;
163- }
196+ [[nodiscard]] bool await_ready ( ) const noexcept {
197+ return m_future.completed () ;
198+ }
164199
165- Result<T, E> await_resume () const noexcept {
166- if (m_future.m_handle .value == nullptr ) {
167- return Failure{AllocationError{}};
200+ void await_suspend (std::coroutine_handle<> h) const noexcept {
201+ m_future.promise ().m_waiting_coro = h;
168202 }
169203
170- assert (!m_future.promise ().m_value .is_nothing ());
171- return std::move (m_future.promise ().m_value );
172- }
204+ Result<T, E> await_resume () const noexcept {
205+ if (m_future.m_handle .value == nullptr ) {
206+ return Failure{AllocationError{}};
207+ }
173208
174- private:
175- friend Fut;
176- Awaiter (Fut &future) noexcept
177- : m_future{future} {
178- }
209+ assert (!m_future.promise ().m_value .is_nothing ());
210+ return std::move (m_future.promise ().m_value );
211+ }
179212
180- Fut &m_future;
181- };
213+ private:
214+ friend Fut;
215+ Awaiter (Fut &future) noexcept
216+ : m_future{future} {
217+ }
218+
219+ Fut &m_future;
220+ };
182221
183- Awaiter operator co_await () && noexcept {
184222 return Awaiter{*this };
185223 }
186224
0 commit comments