/* * Shared State * * Copyright (c) 2023 Javier Jorge * Copyright (c) 2023 Instituto Nacional de Tecnología Industrial * Copyright (C) 2023 Gioacchino Mazzurco * Copyright (C) 2023 Asociación Civil Altermundi * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the * Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see * * SPDX-License-Identifier: AGPL-3.0-only */ #pragma once #include #include #include #include namespace std { template struct task; namespace detail { template /** * @brief base for constructing other promise types. * this class contains the most important aspect that * enables the construction of detachable tasks */ struct promise_type_base { promise_type_base() { RS_DBG4(""); } ~promise_type_base() { RS_DBG4(""); } coroutine_handle<> waiter; // who waits on this coroutine task get_return_object(); suspend_always initial_suspend() { return {}; } struct final_awaiter { bool await_ready() noexcept { return false; } void await_resume() noexcept {} template void await_suspend(coroutine_handle me) noexcept { if (me.promise().waiter) me.promise().waiter.resume(); else { me.destroy(); } } }; auto final_suspend() noexcept { return final_awaiter{}; } void unhandled_exception() {} }; /** * @brief This promise type is used as return type of a typed task * * @tparam T used by task to return custom type, this promise type * contains a copy of the return value. */ template struct promise_type final : promise_type_base { T result; void return_value(T value) { result = std::move(value); } T await_resume() { return result; } task get_return_object(); }; template <> struct promise_type final : promise_type_base { void return_void() {} void await_resume() {} task get_return_object(); }; } /** * @brief Basic coroutine task * * Basic coroutine task * * after creation of a task * * "std::task echo_loop(Socket &socket);" * * it can be coawaited * * "bool run = co_await echo_loop(*socket);" * * or it can be detached (and resumed) * * echo_loop(std::move(socket)).detach(); * * or just resumed * * echo_loop(std::move(socket)).resume() * * @note even that is marked as no discard, this task can be * deleted after using the explicit method "detach()" and * ensuring subscription to the io_context. * @tparam T */ template struct [[nodiscard]] task { using promise_type = detail::promise_type; task(): mCoroutineHandle(nullptr) { RS_DBG4(""); } task(coroutine_handle handle): mCoroutineHandle(handle) { RS_DBG4("", mCoroutineHandle.promise().number); } ~task() { RS_DBG4(""); if (mCoroutineHandle) { RS_DBG4("Task finished? ", mCoroutineHandle.done()); if (mCoroutineHandle.done()) { RS_DBG4("Destroing m_coro"); mCoroutineHandle.destroy(); } else { RS_DBG4("do not destroy coro"); } } } bool await_ready() { return false; } T await_resume(); void await_suspend(coroutine_handle<> waiter) { mCoroutineHandle.promise().waiter = waiter; mCoroutineHandle.resume(); } /** * @brief starts the execution of the task * */ void resume() { mCoroutineHandle.resume(); } private: coroutine_handle mCoroutineHandle; }; template T task::await_resume() { return std::move(mCoroutineHandle.promise().result); } template <> inline void task::await_resume() {} namespace detail { // the formal return value of the coroutine template task promise_type::get_return_object() { return task{coroutine_handle>::from_promise(*this)}; } inline task promise_type::get_return_object() { return task{coroutine_handle>::from_promise(*this)}; } } }