25 #include <seastar/core/future.hh>
26 #include <seastar/coroutine/exception.hh>
27 #include <seastar/util/modules.hh>
28 #include <seastar/util/std-compat.hh>
31 #ifndef SEASTAR_MODULE
32 #ifndef SEASTAR_COROUTINES_ENABLED
33 #error Coroutines support disabled.
42 template <
typename T =
void>
43 class coroutine_traits_base {
48 promise_type() =
default;
49 promise_type(promise_type&&) =
delete;
50 promise_type(
const promise_type&) =
delete;
52 template<
typename... U>
53 void return_value(U&&... value) {
54 _promise.
set_value(std::forward<U>(value)...);
57 void return_value(coroutine::exception ce) noexcept {
58 _promise.set_exception(std::move(ce.eptr));
61 void set_exception(std::exception_ptr&& eptr) noexcept {
62 _promise.set_exception(std::move(eptr));
65 [[deprecated(
"Forwarding coroutine returns are deprecated as too dangerous. Use 'co_return co_await ...' until explicit syntax is available.")]]
66 void return_value(future<T>&& fut) noexcept {
67 fut.forward_to(std::move(_promise));
70 void unhandled_exception() noexcept {
71 _promise.set_exception(std::current_exception());
75 return _promise.get_future();
78 std::suspend_never initial_suspend() noexcept {
return { }; }
79 std::suspend_never final_suspend() noexcept {
return { }; }
81 virtual void run_and_dispose() noexcept
override {
82 auto handle = std::coroutine_handle<promise_type>::from_promise(*
this);
86 task*
waiting_task() noexcept
override {
return _promise.waiting_task(); }
88 scheduling_group set_scheduling_group(scheduling_group sg) noexcept {
89 return std::exchange(this->_sg, sg);
95 class coroutine_traits_base<> {
100 promise_type() =
default;
101 promise_type(promise_type&&) =
delete;
102 promise_type(
const promise_type&) =
delete;
104 void return_void() noexcept {
108 void set_exception(std::exception_ptr&& eptr) noexcept {
109 _promise.set_exception(std::move(eptr));
112 void unhandled_exception() noexcept {
113 _promise.set_exception(std::current_exception());
117 return _promise.get_future();
120 std::suspend_never initial_suspend() noexcept {
return { }; }
121 std::suspend_never final_suspend() noexcept {
return { }; }
123 virtual void run_and_dispose() noexcept
override {
124 auto handle = std::coroutine_handle<promise_type>::from_promise(*
this);
128 task*
waiting_task() noexcept
override {
return _promise.waiting_task(); }
130 scheduling_group set_scheduling_group(scheduling_group new_sg) noexcept {
131 return task::set_scheduling_group(new_sg);
136 template<
bool CheckPreempt,
typename... T>
142 awaiter(
const awaiter&) =
delete;
143 awaiter(awaiter&&) =
delete;
145 bool await_ready() const noexcept {
146 return _future.
available() && (!CheckPreempt || !need_preempt());
150 void await_suspend(std::coroutine_handle<U> hndl) noexcept {
151 if (!CheckPreempt || !_future.available()) {
152 _future.set_coroutine(hndl.promise());
154 schedule(&hndl.promise());
158 std::tuple<T...> await_resume() {
return _future.get(); }
161 template<
bool CheckPreempt,
typename T>
162 struct awaiter<CheckPreempt, T> {
167 awaiter(
const awaiter&) =
delete;
168 awaiter(awaiter&&) =
delete;
170 bool await_ready() const noexcept {
171 return _future.
available() && (!CheckPreempt || !need_preempt());
175 void await_suspend(std::coroutine_handle<U> hndl) noexcept {
176 if (!CheckPreempt || !_future.available()) {
177 _future.set_coroutine(hndl.promise());
179 schedule(&hndl.promise());
183 T await_resume() {
return _future.get0(); }
186 template<
bool CheckPreempt>
187 struct awaiter<CheckPreempt> {
192 awaiter(
const awaiter&) =
delete;
193 awaiter(awaiter&&) =
delete;
195 bool await_ready() const noexcept {
196 return _future.
available() && (!CheckPreempt || !need_preempt());
200 void await_suspend(std::coroutine_handle<U> hndl) noexcept {
201 if (!CheckPreempt || !_future.available()) {
202 _future.set_coroutine(hndl.promise());
204 schedule(&hndl.promise());
208 void await_resume() { _future.get(); }
213 SEASTAR_MODULE_EXPORT_BEGIN
215 template<
typename... T>
216 auto operator co_await(future<T...> f) noexcept {
217 return internal::awaiter<
true, T...>(std::move(f));
220 namespace coroutine {
256 template <
typename Func>
262 explicit lambda(Func&& func) : _func(&func) {}
264 template <
typename... Args>
265 decltype(
auto) operator()(Args&&... args)
const {
266 return std::invoke(*_func, std::forward<Args>(args)...);
275 template<
typename... T>
277 return internal::awaiter<
false, T...>(std::move(f));
280 SEASTAR_MODULE_EXPORT_END
287 SEASTAR_MODULE_EXPORT
288 template<
typename... T,
typename... Args>
289 class coroutine_traits<
seastar::future<T...>, Args...> :
public seastar::internal::coroutine_traits_base<T...> {
Definition: coroutine.hh:257
lambda(Func &&func)
Definition: coroutine.hh:262
A representation of a possibly not-yet-computed value.
Definition: future.hh:1238
bool available() const noexcept
Checks whether the future is available.
Definition: future.hh:1379
promise - allows a future value to be made available at a later time.
Definition: future.hh:926
void set_value(A &&... a) noexcept
Sets the promises value.
Definition: future.hh:982
virtual task * waiting_task() noexcept=0
Returns the next task which is waiting for this task to complete execution, or nullptr.
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
Definition: coroutine.hh:226