/* * Copyright (C) 2015 Hamburg University of Applied Sciences (HAW) * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @ingroup cpp11-compat * @{ * * @file * @brief C++11 mutex drop in replacement * @see * std::mutex, std::lock_guard and std::unique_lock * * * @author Raphael Hiesgen * * @} */ #ifndef RIOT_MUTEX_HPP #define RIOT_MUTEX_HPP #include "mutex.h" #include #include #include namespace riot { /** * @brief C++11 complient implementation of mutex, uses the time point * implemented in our chrono replacement instead of the specified * one * @see * std::mutex * */ class mutex { public: using native_handle_type = mutex_t*; inline constexpr mutex() noexcept : m_mtx{{0}} {} ~mutex(); void lock(); bool try_lock() noexcept; void unlock() noexcept; inline native_handle_type native_handle() { return &m_mtx; } private: mutex(const mutex&); mutex& operator=(const mutex&); mutex_t m_mtx; }; struct defer_lock_t {}; struct try_to_lock_t {}; struct adopt_lock_t {}; constexpr defer_lock_t defer_lock = defer_lock_t(); constexpr try_to_lock_t try_to_lock = try_to_lock_t(); constexpr adopt_lock_t adopt_lock = adopt_lock_t(); /** * @brief C++11 complient implementation of unique lock * @see * std::lock_guard * */ template class lock_guard { public: using mutex_type = Mutex; inline explicit lock_guard(mutex_type& mtx) : m_mtx(mtx) { m_mtx.lock(); } inline lock_guard(mutex_type& mtx, adopt_lock_t) : m_mtx{mtx} {} inline ~lock_guard() { m_mtx.unlock(); } private: mutex_type& m_mtx; }; /** * @brief C++11 complient implementation of unique lock * @see * std::unique_lock * */ template class unique_lock { public: using mutex_type = Mutex; inline unique_lock() noexcept : m_mtx{nullptr}, m_owns{false} {} inline explicit unique_lock(mutex_type& mtx) : m_mtx{&mtx}, m_owns{true} { m_mtx->lock(); } inline unique_lock(mutex_type& mtx, defer_lock_t) noexcept : m_mtx{&mtx}, m_owns{false} {} inline unique_lock(mutex_type& mtx, try_to_lock_t) : m_mtx{&mtx}, m_owns{mtx.try_lock()} {} inline unique_lock(mutex_type& mtx, adopt_lock_t) : m_mtx{&mtx}, m_owns{true} {} inline ~unique_lock() { if (m_owns) { m_mtx->unlock(); } } inline unique_lock(unique_lock&& lock) noexcept : m_mtx{lock.m_mtx}, m_owns{lock.m_owns} { lock.m_mtx = nullptr; lock.m_owns = false; } inline unique_lock& operator=(unique_lock&& lock) noexcept { if (m_owns) { m_mtx->unlock(); } m_mtx = lock.m_mtx; m_owns = lock.m_owns; lock.m_mtx = nullptr; lock.m_owns = false; return *this; } void lock(); bool try_lock(); void unlock(); inline void swap(unique_lock& lock) noexcept { std::swap(m_mtx, lock.m_mtx); std::swap(m_owns, lock.m_owns); } inline mutex_type* release() noexcept { mutex_type* mtx = m_mtx; m_mtx = nullptr; m_owns = false; return mtx; } inline bool owns_lock() const noexcept { return m_owns; } inline explicit operator bool() const noexcept { return m_owns; } inline mutex_type* mutex() const noexcept { return m_mtx; } private: unique_lock(unique_lock const&); unique_lock& operator=(unique_lock const&); mutex_type* m_mtx; bool m_owns; }; template void unique_lock::lock() { if (m_mtx == nullptr) { throw std::system_error( std::make_error_code(std::errc::operation_not_permitted), "References null mutex."); } if (m_owns) { throw std::system_error( std::make_error_code(std::errc::resource_deadlock_would_occur), "Already locked."); } m_mtx->lock(); m_owns = true; } template bool unique_lock::try_lock() { if (m_mtx == nullptr) { throw std::system_error( std::make_error_code(std::errc::operation_not_permitted), "References null mutex."); } if (m_owns) { throw std::system_error( std::make_error_code(std::errc::resource_deadlock_would_occur), "Already locked."); } m_owns = m_mtx->try_lock(); return m_owns; } template void unique_lock::unlock() { if (!m_owns) { throw std::system_error( std::make_error_code(std::errc::operation_not_permitted), "Mutex not locked."); } m_mtx->unlock(); m_owns = false; } template inline void swap(unique_lock& lhs, unique_lock& rhs) noexcept { lhs.swap(rhs); } } // namespace riot #endif // RIOT_MUTEX_HPP