2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 * Copyright (C) 2019 ScyllaDB Ltd.
24 #include <seastar/core/future.hh>
26 #ifndef SEASTAR_COROUTINES_ENABLED
27 #error Coroutines support disabled.
30 #include <seastar/core/std-coroutine.hh>
31 #include <seastar/coroutine/exception.hh>
37 template <typename T = void>
38 class coroutine_traits_base {
40 class promise_type final : public seastar::task {
41 seastar::promise<T> _promise;
43 promise_type() = default;
44 promise_type(promise_type&&) = delete;
45 promise_type(const promise_type&) = delete;
47 template<typename... U>
48 void return_value(U&&... value) {
49 _promise.set_value(std::forward<U>(value)...);
52 void return_value(coroutine::exception ce) noexcept {
53 _promise.set_exception(std::move(ce.eptr));
56 [[deprecated("Forwarding coroutine returns are deprecated as too dangerous. Use 'co_return co_await ...' until explicit syntax is available.")]]
57 void return_value(future<T>&& fut) noexcept {
58 fut.forward_to(std::move(_promise));
61 void unhandled_exception() noexcept {
62 _promise.set_exception(std::current_exception());
65 seastar::future<T> get_return_object() noexcept {
66 return _promise.get_future();
69 SEASTAR_INTERNAL_COROUTINE_NAMESPACE::suspend_never initial_suspend() noexcept { return { }; }
70 SEASTAR_INTERNAL_COROUTINE_NAMESPACE::suspend_never final_suspend() noexcept { return { }; }
72 virtual void run_and_dispose() noexcept override {
73 auto handle = SEASTAR_INTERNAL_COROUTINE_NAMESPACE::coroutine_handle<promise_type>::from_promise(*this);
77 task* waiting_task() noexcept override { return _promise.waiting_task(); }
82 class coroutine_traits_base<> {
84 class promise_type final : public seastar::task {
85 seastar::promise<> _promise;
87 promise_type() = default;
88 promise_type(promise_type&&) = delete;
89 promise_type(const promise_type&) = delete;
91 void return_void() noexcept {
95 void unhandled_exception() noexcept {
96 _promise.set_exception(std::current_exception());
99 seastar::future<> get_return_object() noexcept {
100 return _promise.get_future();
103 SEASTAR_INTERNAL_COROUTINE_NAMESPACE::suspend_never initial_suspend() noexcept { return { }; }
104 SEASTAR_INTERNAL_COROUTINE_NAMESPACE::suspend_never final_suspend() noexcept { return { }; }
106 virtual void run_and_dispose() noexcept override {
107 auto handle = SEASTAR_INTERNAL_COROUTINE_NAMESPACE::coroutine_handle<promise_type>::from_promise(*this);
111 task* waiting_task() noexcept override { return _promise.waiting_task(); }
115 template<typename... T>
117 seastar::future<T...> _future;
119 explicit awaiter(seastar::future<T...>&& f) noexcept : _future(std::move(f)) { }
121 awaiter(const awaiter&) = delete;
122 awaiter(awaiter&&) = delete;
124 bool await_ready() const noexcept {
125 return _future.available() && !need_preempt();
129 void await_suspend(SEASTAR_INTERNAL_COROUTINE_NAMESPACE::coroutine_handle<U> hndl) noexcept {
130 if (!_future.available()) {
131 _future.set_coroutine(hndl.promise());
133 schedule(&hndl.promise());
137 std::tuple<T...> await_resume() { return _future.get(); }
142 seastar::future<T> _future;
144 explicit awaiter(seastar::future<T>&& f) noexcept : _future(std::move(f)) { }
146 awaiter(const awaiter&) = delete;
147 awaiter(awaiter&&) = delete;
149 bool await_ready() const noexcept {
150 return _future.available() && !need_preempt();
154 void await_suspend(SEASTAR_INTERNAL_COROUTINE_NAMESPACE::coroutine_handle<U> hndl) noexcept {
155 if (!_future.available()) {
156 _future.set_coroutine(hndl.promise());
158 schedule(&hndl.promise());
162 T await_resume() { return _future.get0(); }
167 seastar::future<> _future;
169 explicit awaiter(seastar::future<>&& f) noexcept : _future(std::move(f)) { }
171 awaiter(const awaiter&) = delete;
172 awaiter(awaiter&&) = delete;
174 bool await_ready() const noexcept {
175 return _future.available() && !need_preempt();
179 void await_suspend(SEASTAR_INTERNAL_COROUTINE_NAMESPACE::coroutine_handle<U> hndl) noexcept {
180 if (!_future.available()) {
181 _future.set_coroutine(hndl.promise());
183 schedule(&hndl.promise());
187 void await_resume() { _future.get(); }
190 } // seastar::internal
192 template<typename... T>
193 auto operator co_await(future<T...> f) noexcept {
194 return internal::awaiter<T...>(std::move(f));
200 namespace SEASTAR_INTERNAL_COROUTINE_NAMESPACE {
202 template<typename... T, typename... Args>
203 class coroutine_traits<seastar::future<T...>, Args...> : public seastar::internal::coroutine_traits_base<T...> {
206 } // SEASTAR_INTERNAL_COROUTINE_NAMESPACE