/*
* 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