aboutsummaryrefslogtreecommitdiffstats
path: root/include/distortos/ConditionVariable.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/distortos/ConditionVariable.hpp')
-rw-r--r--include/distortos/ConditionVariable.hpp304
1 files changed, 304 insertions, 0 deletions
diff --git a/include/distortos/ConditionVariable.hpp b/include/distortos/ConditionVariable.hpp
new file mode 100644
index 0000000..6b7f869
--- /dev/null
+++ b/include/distortos/ConditionVariable.hpp
@@ -0,0 +1,304 @@
+/**
+ * \file
+ * \brief ConditionVariable 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_CONDITIONVARIABLE_HPP_
+#define INCLUDE_DISTORTOS_CONDITIONVARIABLE_HPP_
+
+#include "distortos/internal/scheduler/ThreadList.hpp"
+
+#include "distortos/TickClock.hpp"
+
+namespace distortos
+{
+
+class Mutex;
+
+/**
+ * \brief ConditionVariable is an advanced synchronization primitive
+ *
+ * Similar to std::condition_variable - http://en.cppreference.com/w/cpp/thread/condition_variable
+ * Similar to POSIX pthread_cond_t
+ *
+ * \ingroup synchronization
+ */
+
+class ConditionVariable
+{
+public:
+
+ /**
+ * \brief ConditionVariable constructor
+ *
+ * Similar to std::condition_variable::condition_variable() -
+ * http://en.cppreference.com/w/cpp/thread/condition_variable/condition_variable
+ * Similar to pthread_cond_init() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_init.html
+ */
+
+ constexpr ConditionVariable() :
+ blockedList_{}
+ {
+
+ }
+
+ /**
+ * \brief Notifies all waiting threads.
+ *
+ * Similar to std::condition_variable::notify_all() -
+ * http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all
+ * Similar to pthread_cond_broadcast() -
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html
+ *
+ * Unblocks all threads waiting on this condition variable. The notifying thread does not need to hold the same
+ * mutex as the one held by the waiting thread(s).
+ */
+
+ void notifyAll();
+
+ /**
+ * \brief Notifies one waiting thread.
+ *
+ * Similar to std::condition_variable::notify_one() -
+ * http://en.cppreference.com/w/cpp/thread/condition_variable/notify_one
+ * Similar to pthread_cond_signal() -
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html
+ *
+ * Unblocks one thread waiting on this condition variable. The notifying thread does not need to hold the same
+ * mutex as the one held by the waiting thread(s).
+ */
+
+ void notifyOne();
+
+ /**
+ * \brief Waits for notification.
+ *
+ * Similar to std::condition_variable::wait() - http://en.cppreference.com/w/cpp/thread/condition_variable/wait
+ * Similar to pthread_cond_wait() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html
+ *
+ * Atomically releases supplied mutex and blocks current thread until the condition variable is notified. The thread
+ * will be unblocked when notifyAll() or notifyOne() is executed. It may also be unblocked spuriously. When
+ * unblocked, regardless of the reason, lock is reacquired and wait exits.
+ *
+ * \param [in] mutex is a reference to mutex which must be owned by calling thread
+ *
+ * \return zero if the wait was completed successfully, error code otherwise:
+ * - EPERM - the mutex type is ErrorChecking or Recursive, and the current thread does not own the mutex;
+ */
+
+ int wait(Mutex& mutex);
+
+ /**
+ * \brief Waits for predicate to become true.
+ *
+ * Similar to std::condition_variable::wait() - http://en.cppreference.com/w/cpp/thread/condition_variable/wait
+ * Similar to pthread_cond_wait() - http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html
+ *
+ * Overload for wait() which also checks the predicate. This function will return only if the predicate is true.
+ *
+ * \tparam Predicate is a type of functor to check the predicate
+ *
+ * \param [in] mutex is a reference to mutex which must be owned by calling thread
+ * \param [in] predicate is the predicate that will be checked
+ *
+ * \return zero if the wait was completed successfully, error code otherwise:
+ * - EPERM - the mutex type is ErrorChecking or Recursive, and the current thread does not own the mutex;
+ */
+
+ template<typename Predicate>
+ int wait(Mutex& mutex, Predicate predicate);
+
+ /**
+ * \brief Waits for notification for given duration of time.
+ *
+ * Similar to std::condition_variable::wait_for() -
+ * http://en.cppreference.com/w/cpp/thread/condition_variable/wait_for
+ * Similar to pthread_cond_timedwait() -
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html#
+ *
+ * Atomically releases supplied mutex and blocks current thread until the condition variable is notified. The thread
+ * will be unblocked when notifyAll() or notifyOne() is executed or when given duration of time expires. It may also
+ * be unblocked spuriously. When unblocked, regardless of the reason, lock is reacquired and wait exits.
+ *
+ * \param [in] mutex is a reference to mutex which must be owned by calling thread
+ * \param [in] duration is the duration after which the wait for notification will be terminated
+ *
+ * \return zero if the wait was completed successfully, error code otherwise:
+ * - EPERM - the mutex type is ErrorChecking or Recursive, and the current thread does not own the mutex;
+ * - ETIMEDOUT - no notification was received before the specified timeout expired;
+ */
+
+ int waitFor(Mutex& mutex, TickClock::duration duration);
+
+ /**
+ * \brief Waits for notification for given duration of time.
+ *
+ * Similar to std::condition_variable::wait_for() -
+ * http://en.cppreference.com/w/cpp/thread/condition_variable/wait_for
+ * Similar to pthread_cond_timedwait() -
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html#
+ *
+ * Template variant of waitFor(Mutex& mutex, 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] mutex is a reference to mutex which must be owned by calling thread
+ * \param [in] duration is the duration after which the wait for notification will be terminated
+ *
+ * \return zero if the wait was completed successfully, error code otherwise:
+ * - EPERM - the mutex type is ErrorChecking or Recursive, and the current thread does not own the mutex;
+ * - ETIMEDOUT - no notification was received before the specified timeout expired;
+ */
+
+ template<typename Rep, typename Period>
+ int waitFor(Mutex& mutex, const std::chrono::duration<Rep, Period> duration)
+ {
+ return waitFor(mutex, std::chrono::duration_cast<TickClock::duration>(duration));
+ }
+
+ /**
+ * \brief Waits for predicate to become true for given duration of time.
+ *
+ * Similar to std::condition_variable::wait_for() -
+ * http://en.cppreference.com/w/cpp/thread/condition_variable/wait_for
+ * Similar to pthread_cond_timedwait() -
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html#
+ *
+ * Overload for waitFor() which also checks the predicate. This function will return only if the predicate is true
+ * or when given duration of time expires.
+ *
+ * \tparam Rep is type of tick counter
+ * \tparam Period is std::ratio type representing the tick period of the clock, in seconds
+ * \tparam Predicate is a type of functor to check the predicate
+ *
+ * \param [in] mutex is a reference to mutex which must be owned by calling thread
+ * \param [in] duration is the duration after which the wait for notification will be terminated
+ * \param [in] predicate is the predicate that will be checked
+ *
+ * \return zero if the wait was completed successfully, error code otherwise:
+ * - EPERM - the mutex type is ErrorChecking or Recursive, and the current thread does not own the mutex;
+ * - ETIMEDOUT - no notification was received before the specified timeout expired;
+ */
+
+ template<typename Rep, typename Period, typename Predicate>
+ int waitFor(Mutex& mutex, const std::chrono::duration<Rep, Period> duration, Predicate predicate)
+ {
+ return waitUntil(mutex, TickClock::now() + duration + TickClock::duration{1}, std::move(predicate));
+ }
+
+ /**
+ * \brief Waits for notification until given time point.
+ *
+ * Similar to std::condition_variable::wait_until() -
+ * http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until
+ * Similar to pthread_cond_timedwait() -
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html#
+ *
+ * Atomically releases supplied mutex and blocks current thread until the condition variable is notified. The thread
+ * will be unblocked when notifyAll() or notifyOne() is executed or when given time point is reached. It may also be
+ * unblocked spuriously. When unblocked, regardless of the reason, lock is reacquired and wait exits.
+ *
+ * \param [in] mutex is a reference to mutex which must be owned by calling thread
+ * \param [in] timePoint is the time point at which the wait for notification will be terminated
+ *
+ * \return zero if the wait was completed successfully, error code otherwise:
+ * - EPERM - the mutex type is ErrorChecking or Recursive, and the current thread does not own the mutex;
+ * - ETIMEDOUT - no notification was received before the specified timeout expired;
+ */
+
+ int waitUntil(Mutex& mutex, TickClock::time_point timePoint);
+
+ /**
+ * \brief Waits for notification until given time point.
+ *
+ * Similar to std::condition_variable::wait_until() -
+ * http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until
+ * Similar to pthread_cond_timedwait() -
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html#
+ *
+ * Template variant of waitUntil(Mutex& mutex, TickClock::time_point timePoint).
+ *
+ * \tparam Duration is a std::chrono::duration type used to measure duration
+ *
+ * \param [in] mutex is a reference to mutex which must be owned by calling thread
+ * \param [in] timePoint is the time point at which the wait for notification will be terminated
+ *
+ * \return zero if the wait was completed successfully, error code otherwise:
+ * - EPERM - the mutex type is ErrorChecking or Recursive, and the current thread does not own the mutex;
+ * - ETIMEDOUT - no notification was received before the specified timeout expired;
+ */
+
+ template<typename Duration>
+ int waitUntil(Mutex& mutex, const std::chrono::time_point<TickClock, Duration> timePoint)
+ {
+ return waitUntil(mutex, std::chrono::time_point_cast<TickClock::duration>(timePoint));
+ }
+
+ /**
+ * \brief Waits for predicate to become true until given time point.
+ *
+ * Similar to std::condition_variable::wait_until() -
+ * http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until
+ * Similar to pthread_cond_timedwait() -
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html#
+ *
+ * Overload for waitUntil() which also checks the predicate. This function will return only if the predicate is true
+ * or when given time point is reached.
+ *
+ * \tparam Duration is a std::chrono::duration type used to measure duration
+ * \tparam Predicate is a type of functor to check the predicate
+ *
+ * \param [in] mutex is a reference to mutex which must be owned by calling thread
+ * \param [in] timePoint is the time point at which the wait for notification will be terminated
+ * \param [in] predicate is the predicate that will be checked
+ *
+ * \return zero if the wait was completed successfully, error code otherwise:
+ * - EPERM - the mutex type is ErrorChecking or Recursive, and the current thread does not own the mutex;
+ * - ETIMEDOUT - no notification was received before the specified timeout expired;
+ */
+
+ template<typename Duration, typename Predicate>
+ int waitUntil(Mutex& mutex, std::chrono::time_point<TickClock, Duration> timePoint, Predicate predicate);
+
+private:
+
+ /// ThreadControlBlock objects blocked on this condition variable
+ internal::ThreadList blockedList_;
+};
+
+template<typename Predicate>
+int ConditionVariable::wait(Mutex& mutex, Predicate predicate)
+{
+ while (predicate() == false)
+ {
+ const auto ret = wait(mutex);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+template<typename Duration, typename Predicate>
+int ConditionVariable::waitUntil(Mutex& mutex, const std::chrono::time_point<TickClock, Duration> timePoint, Predicate predicate)
+{
+ while (predicate() == false)
+ {
+ const auto ret = waitUntil(mutex, timePoint);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+} // namespace distortos
+
+#endif // INCLUDE_DISTORTOS_CONDITIONVARIABLE_HPP_