/*
* 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:
/**
* The native handle type used by the mutex.
*/
using native_handle_type = mutex_t*;
inline constexpr mutex() noexcept : m_mtx{{0}} {}
~mutex();
/**
* @brief Lock the mutex.
*/
void lock();
/**
* @brief Try to lock the mutex.
* @return `true` if the mutex was locked, `false` otherwise.
*/
bool try_lock() noexcept;
/**
* @brief Unlock the mutex.
*/
void unlock() noexcept;
/**
* @brief Provides access to the native handle.
* @return The native handle of the mutex.
*/
inline native_handle_type native_handle() { return &m_mtx; }
private:
mutex(const mutex&);
mutex& operator=(const mutex&);
mutex_t m_mtx;
};
/**
* @brief Tag type for defer lock strategy.
*/
struct defer_lock_t {};
/**
* @brief Tag type for try lock strategy.
*/
struct try_to_lock_t {};
/**
* @brief Tag type for adopt lock strategy.
*/
struct adopt_lock_t {};
/**
* @brief Tag constant for defer lock strategy.
*/
constexpr defer_lock_t defer_lock = defer_lock_t();
/**
* @brief Tag constant for try lock strategy.
*/
constexpr try_to_lock_t try_to_lock = try_to_lock_t();
/**
* @brief Tag constant for adopt lock strategy.
*/
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:
/**
* The type of Mutex used by the lock_guard.
*/
using mutex_type = Mutex;
/**
* @brief Constructs a lock_gurad from a Mutex and locks it.
*/
inline explicit lock_guard(mutex_type& mtx) : m_mtx(mtx) { m_mtx.lock(); }
/**
* @brief Constructs a lock_guard from a Mutex, acquireing ownership without
* locking it.
*/
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:
/**
* The type of Mutex used by the lock.
*/
using mutex_type = Mutex;
inline unique_lock() noexcept : m_mtx{nullptr}, m_owns{false} {}
/**
* @brief Constructs a unique_lock from a Mutex and locks it.
*/
inline explicit unique_lock(mutex_type& mtx) : m_mtx{&mtx}, m_owns{true} {
m_mtx->lock();
}
/**
* @brief Constructs a unique_lock from a Mutex but does not lock it.
*/
inline unique_lock(mutex_type& mtx, defer_lock_t) noexcept : m_mtx{&mtx},
m_owns{false} {}
/**
* @brief Constructs a unique_lock from a Mutex and tries to lock it.
*/
inline unique_lock(mutex_type& mtx, try_to_lock_t)
: m_mtx{&mtx}, m_owns{mtx.try_lock()} {}
/**
* @brief Constructs a unique_lock from a Mutex that is already owned by the
* thread.
*/
inline unique_lock(mutex_type& mtx, adopt_lock_t)
: m_mtx{&mtx}, m_owns{true} {}
inline ~unique_lock() {
if (m_owns) {
m_mtx->unlock();
}
}
/**
* @brief Move constructor.
*/
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;
}
/**
* @brief Move assignment operator.
*/
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;
}
/**
* @brief Locks the associated mutex.
*/
void lock();
/**
* @brief Tries to lock the associated mutex.
* @return `true` if the mutex has been locked successfully,
* `false` otherwise.
*/
bool try_lock();
/**
* @brief Unlocks the associated mutex.
*/
void unlock();
/**
* @brief Swap this unique_lock with another unique_lock.
*/
inline void swap(unique_lock& lock) noexcept {
std::swap(m_mtx, lock.m_mtx);
std::swap(m_owns, lock.m_owns);
}
/**
* @brief Disassociate this lock from its mutex. The caller is responsible to
* unlock the mutex if it was locked before.
* @return A pointer to the associated mutex or `nullptr` if there was none.
*/
inline mutex_type* release() noexcept {
mutex_type* mtx = m_mtx;
m_mtx = nullptr;
m_owns = false;
return mtx;
}
/**
* @brief Query ownership of the associate mutex.
* @return `true` if an associated mutex exists and the lock owns it,
* `false` otherwise.
*/
inline bool owns_lock() const noexcept { return m_owns; }
/**
* @brief Operator to query the ownership of the associated mutex.
* @return `true` if an associated mutex exists and the lock owns it,
* `false` otherwise.
*/
inline explicit operator bool() const noexcept { return m_owns; }
/**
* @brief Provides access to the associated mutex.
* @return A pointer to the associated mutex or nullptr it there was none.
*/
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;
}
/**
* @brief Swaps two mutexes.
* @param[inout] lhs Reference to one mutex.
* @param[inout] rhs Reference to the other mutex.
*/
template
inline void swap(unique_lock& lhs, unique_lock& rhs) noexcept {
lhs.swap(rhs);
}
} // namespace riot
#endif // RIOT_MUTEX_HPP