// SPDX-FileCopyrightText: 2023 Daniel Vrátil // SPDX-FileCopyrightText: 2023 Martin Beran // // SPDX-License-Identifier: BSL-1.0 #pragma once #include #include #include #include #include #include #define ASIO_NS boost::asio namespace avast::asio { class async_mutex_lock; class async_mutex; /** \internal **/ namespace detail { /** * \brief Represents a suspended coroutine that is awaiting lock acquisition. **/ struct locked_waiter { /** * \brief Constructs a new locked_waiter. * \param next_waiter Pointer to the waiter to prepend this locked_waiter to. **/ explicit locked_waiter(locked_waiter *next_waiter): next(next_waiter) {} locked_waiter(locked_waiter &&) = delete; locked_waiter(const locked_waiter &) = delete; locked_waiter &operator=(locked_waiter &&) = delete; locked_waiter &operator=(const locked_waiter &) = delete; /** * \brief Destructor. **/ virtual ~locked_waiter() = default; /** * \brief Completes the pending asynchronous operation. * * Resumes the currently suspended coroutine with the acquired lock. **/ virtual void completion() = 0; /** * The waiters are held in a linked list. This is a pointer to the next member of the list. **/ locked_waiter *next = nullptr; }; /** * \brief Locked waiter that used `async_mutex::async_lock()` to acquire the lock. **/ template struct async_locked_waiter final: public locked_waiter { /** * \brief Constructs a new async_locked_waiter. * \param mutex A mutex that the waiter is trying to acquire a lock for. * \param next_waiter Pointer to the head of the waiters linked list to prepend this waiter to. * \param token The complention token to call when the asynchronous operation is completed. **/ async_locked_waiter([[maybe_unused]] async_mutex *mutex, locked_waiter *next_waiter, Token &&token): locked_waiter(next_waiter), m_token(std::move(token)) {} void completion() override { auto executor = ASIO_NS::get_associated_executor(m_token); ASIO_NS::post(std::move(executor), [token = std::move(m_token)]() mutable { token(); }); } private: Token m_token; //!< The completion token to invoke when the lock is acquired. }; /** * \brief Locked waiter that used `async_mutex::async_scoped_lock()` to acquire the lock. **/ template struct scoped_async_locked_waiter final: public locked_waiter { /** * \brief Constructs a new scoped_async_locked_waiter. * \param mutex A mutex that the waiter is trying to acquire a lock for. * \param next_waiter Pointer to the head of the waiters linked list to prepend this waiter to. * \param token The complention token to call when the asynchronous operation is completed. **/ scoped_async_locked_waiter(async_mutex *mutex, locked_waiter *next_waiter, Token &&token): locked_waiter(next_waiter), m_mutex(mutex), m_token(std::move(token)) {} void completion() override; private: async_mutex *m_mutex; //!< The mutex whose lock is being awaited. Token m_token; //!< The completion token to invoke when the lock is acquired. }; /** * \brief An initiator for asio::async_initiate(). **/ template