diff options
Diffstat (limited to 'include/distortos/Mutex.hpp')
-rw-r--r-- | include/distortos/Mutex.hpp | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/include/distortos/Mutex.hpp b/include/distortos/Mutex.hpp new file mode 100644 index 0000000..481700d --- /dev/null +++ b/include/distortos/Mutex.hpp @@ -0,0 +1,280 @@ +/** + * \file + * \brief Mutex class header + * + * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info + * + * \par License + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not + * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDE_DISTORTOS_MUTEX_HPP_ +#define INCLUDE_DISTORTOS_MUTEX_HPP_ + +#include "distortos/internal/synchronization/MutexControlBlock.hpp" + +namespace distortos +{ + +/** + * \brief Mutex is the basic synchronization primitive + * + * Similar to std::mutex - http://en.cppreference.com/w/cpp/thread/mutex + * Similar to POSIX pthread_mutex_t - + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09 -> 2.9.3 Thread Mutexes + * + * \ingroup synchronization + */ + +class Mutex +{ +public: + + /// mutex protocols + using Protocol = internal::MutexControlBlock::Protocol; + + /// type used for counting recursive locks + using RecursiveLocksCount = uint16_t; + + /// type of mutex + enum class Type : uint8_t + { + /// normal mutex, similar to PTHREAD_MUTEX_NORMAL + normal, + /// mutex with additional error checking, similar to PTHREAD_MUTEX_ERRORCHECK + errorChecking, + /// recursive mutex, similar to PTHREAD_MUTEX_RECURSIVE + recursive + }; + + /** + * \brief Gets the maximum number of recursive locks possible before returning EAGAIN + * + * \note Actual number of lock() operations possible is getMaxRecursiveLocks() + 1. + * + * \return maximum number of recursive locks possible before returning EAGAIN + */ + + constexpr static RecursiveLocksCount getMaxRecursiveLocks() + { + return std::numeric_limits<RecursiveLocksCount>::max(); + } + + /** + * \brief Mutex constructor + * + * Similar to std::mutex::mutex() - http://en.cppreference.com/w/cpp/thread/mutex/mutex + * Similar to pthread_mutex_init() - + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html + * + * \param [in] type is the type of mutex, default - Type::normal + * \param [in] protocol is the mutex protocol, default - Protocol::none + * \param [in] priorityCeiling is the priority ceiling of mutex, ignored when protocol != Protocol::priorityProtect, + * default - 0 + */ + + constexpr explicit Mutex(const Type type = Type::normal, const Protocol protocol = Protocol::none, + const uint8_t priorityCeiling = {}) : + controlBlock_{protocol, priorityCeiling}, + recursiveLocksCount_{}, + type_{type} + { + + } + + /** + * \brief Locks the mutex. + * + * Similar to std::mutex::lock() - http://en.cppreference.com/w/cpp/thread/mutex/lock + * Similar to pthread_mutex_lock() - + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html# + * + * If the mutex is already locked by another thread, the calling thread shall block until the mutex becomes + * available. This function shall return with the mutex in the locked state with the calling thread as its owner. If + * a thread attempts to relock a mutex that it has already locked, deadlock occurs. + * + * \return zero if the caller successfully locked the mutex, error code otherwise: + * - EAGAIN - the mutex could not be acquired because the maximum number of recursive locks for mutex has been + * exceeded; + * - EDEADLK - the mutex type is ErrorChecking and the current thread already owns the mutex; + * - EINVAL - the mutex was created with the protocol attribute having the value PriorityProtect and the calling + * thread's priority is higher than the mutex's current priority ceiling; + */ + + int lock(); + + /** + * \brief Tries to lock the mutex. + * + * Similar to std::mutex::try_lock() - http://en.cppreference.com/w/cpp/thread/mutex/try_lock + * Similar to pthread_mutex_trylock() - + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html# + * + * This function shall be equivalent to lock(), except that if the mutex is currently locked (by any thread, + * including the current thread), the call shall return immediately. + * + * \return zero if the caller successfully locked the mutex, error code otherwise: + * - EAGAIN - the mutex could not be acquired because the maximum number of recursive locks for mutex has been + * exceeded; + * - EBUSY - the mutex could not be acquired because it was already locked; + * - EINVAL - the mutex was created with the protocol attribute having the value PriorityProtect and the calling + * thread's priority is higher than the mutex's current priority ceiling; + */ + + int tryLock(); + + /** + * \brief Tries to lock the mutex for given duration of time. + * + * Similar to std::timed_mutex::try_lock_for() - http://en.cppreference.com/w/cpp/thread/timed_mutex/try_lock_for + * Similar to pthread_mutex_timedlock() - + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_timedlock.html# + * + * If the mutex is already locked, the calling thread shall block until the mutex becomes available as in lock() + * function. If the mutex cannot be locked without waiting for another thread to unlock the mutex, this wait shall + * be terminated when the specified timeout expires. + * + * Under no circumstance shall the function fail with a timeout if the mutex can be locked immediately. The validity + * of the duration parameter need not be checked if the mutex can be locked immediately. + * + * \param [in] duration is the duration after which the wait will be terminated without locking the mutex + * + * \return zero if the caller successfully locked the mutex, error code otherwise: + * - EAGAIN - the mutex could not be acquired because the maximum number of recursive locks for mutex has been + * exceeded; + * - EDEADLK - the mutex type is ErrorChecking and the current thread already owns the mutex; + * - EINVAL - the mutex was created with the protocol attribute having the value PriorityProtect and the calling + * thread's priority is higher than the mutex's current priority ceiling; + * - ETIMEDOUT - the mutex could not be locked before the specified timeout expired; + */ + + int tryLockFor(TickClock::duration duration); + + /** + * Tries to lock the mutex for given duration of time. + * + * Template variant of tryLockFor(TickClock::duration duration). + * + * \tparam Rep is type of tick counter + * \tparam Period is std::ratio type representing the tick period of the clock, in seconds + * + * \param [in] duration is the duration after which the wait will be terminated without locking the mutex + * + * \return zero if the caller successfully locked the mutex, error code otherwise: + * - EAGAIN - the mutex could not be acquired because the maximum number of recursive locks for mutex has been + * exceeded; + * - EDEADLK - the mutex type is ErrorChecking and the current thread already owns the mutex; + * - EINVAL - the mutex was created with the protocol attribute having the value PriorityProtect and the calling + * thread's priority is higher than the mutex's current priority ceiling; + * - ETIMEDOUT - the mutex could not be locked before the specified timeout expired; + */ + + template<typename Rep, typename Period> + int tryLockFor(const std::chrono::duration<Rep, Period> duration) + { + return tryLockFor(std::chrono::duration_cast<TickClock::duration>(duration)); + } + + /** + * \brief Tries to lock the mutex until given time point. + * + * Similar to std::timed_mutex::try_lock_until() - + * http://en.cppreference.com/w/cpp/thread/timed_mutex/try_lock_until + * Similar to pthread_mutex_timedlock() - + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_timedlock.html# + * + * If the mutex is already locked, the calling thread shall block until the mutex becomes available as in lock() + * function. If the mutex cannot be locked without waiting for another thread to unlock the mutex, this wait shall + * be terminated when the specified timeout expires. + * + * Under no circumstance shall the function fail with a timeout if the mutex can be locked immediately. The validity + * of the timePoint parameter need not be checked if the mutex can be locked immediately. + * + * \param [in] timePoint is the time point at which the wait will be terminated without locking the mutex + * + * \return zero if the caller successfully locked the mutex, error code otherwise: + * - EAGAIN - the mutex could not be acquired because the maximum number of recursive locks for mutex has been + * exceeded; + * - EDEADLK - the mutex type is ErrorChecking and the current thread already owns the mutex; + * - EINVAL - the mutex was created with the protocol attribute having the value PriorityProtect and the calling + * thread's priority is higher than the mutex's current priority ceiling; + * - ETIMEDOUT - the mutex could not be locked before the specified timeout expired; + */ + + int tryLockUntil(TickClock::time_point timePoint); + + /** + * \brief Tries to lock the mutex until given time point. + * + * Template variant of tryLockUntil(TickClock::time_point timePoint). + * + * \tparam Duration is a std::chrono::duration type used to measure duration + * + * \param [in] timePoint is the time point at which the wait will be terminated without locking the mutex + * + * \return zero if the caller successfully locked the mutex, error code otherwise: + * - EAGAIN - the mutex could not be acquired because the maximum number of recursive locks for mutex has been + * exceeded; + * - EDEADLK - the mutex type is ErrorChecking and the current thread already owns the mutex; + * - EINVAL - the mutex was created with the protocol attribute having the value PriorityProtect and the calling + * thread's priority is higher than the mutex's current priority ceiling; + * - ETIMEDOUT - the mutex could not be locked before the specified timeout expired; + */ + + template<typename Duration> + int tryLockUntil(const std::chrono::time_point<TickClock, Duration> timePoint) + { + return tryLockUntil(std::chrono::time_point_cast<TickClock::duration>(timePoint)); + } + + /** + * \brief Unlocks the mutex. + * + * Similar to std::mutex::unlock() - http://en.cppreference.com/w/cpp/thread/mutex/unlock + * Similar to pthread_mutex_unlock() - + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html# + * + * The mutex must be locked by the current thread, otherwise, the behavior is undefined. If there are threads + * blocked on this mutex, the highest priority waiting thread shall be unblocked, and if there is more than one + * highest priority thread blocked waiting, then the highest priority thread that has been waiting the longest shall + * be unblocked. + * + * \return zero if the caller successfully unlocked the mutex, error code otherwise: + * - EPERM - the mutex type is ErrorChecking or Recursive, and the current thread does not own the mutex; + */ + + int unlock(); + +private: + + /** + * \brief Internal version of tryLock(). + * + * Internal version with no interrupt masking and additional code for ErrorChecking type (which is not required for + * tryLock()). + * + * \return zero if the caller successfully locked the mutex, error code otherwise: + * - EAGAIN - the mutex could not be acquired because the maximum number of recursive locks for mutex has been + * exceeded; + * - EBUSY - the mutex could not be acquired because it was already locked; + * - EDEADLK - the mutex type is ErrorChecking and the current thread already owns the mutex; + * - EINVAL - the mutex was created with the protocol attribute having the value PriorityProtect and the calling + * thread's priority is higher than the mutex's current priority ceiling; + */ + + int tryLockInternal(); + + /// instance of control block + internal::MutexControlBlock controlBlock_; + + /// number of recursive locks, used when mutex type is Recursive + RecursiveLocksCount recursiveLocksCount_; + + /// type of mutex + Type type_; +}; + +} // namespace distortos + +#endif // INCLUDE_DISTORTOS_MUTEX_HPP_ |