aboutsummaryrefslogtreecommitdiffstats
path: root/include/distortos/Mutex.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/distortos/Mutex.hpp')
-rw-r--r--include/distortos/Mutex.hpp280
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_