/* * 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 condition variable drop in replacement * @see * std::condition_variable * * * @author Raphael Hiesgen * * @} */ #ifndef RIOT_CONDITION_VARIABLE_HPP #define RIOT_CONDITION_VARIABLE_HPP #include "sched.h" #include "xtimer.h" #include "priority_queue.h" #include "riot/mutex.hpp" #include "riot/chrono.hpp" namespace riot { enum class cv_status { no_timeout, timeout }; /** * @brief C++11 complient implementation of condition variable, uses the time * point implemented in our chrono replacement instead of the * specified one * @see * std::condition_variable * */ class condition_variable { public: using native_handle_type = priority_queue_t*; inline condition_variable() { m_queue.first = NULL; } ~condition_variable(); void notify_one() noexcept; void notify_all() noexcept; void wait(unique_lock& lock) noexcept; template void wait(unique_lock& lock, Predicate pred); cv_status wait_until(unique_lock& lock, const time_point& timeout_time); template bool wait_until(unique_lock& lock, const time_point& timeout_time, Predicate pred); template cv_status wait_for(unique_lock& lock, const std::chrono::duration& rel_time); template bool wait_for(unique_lock& lock, const std::chrono::duration& rel_time, Predicate pred); inline native_handle_type native_handle() { return &m_queue; } private: condition_variable(const condition_variable&); condition_variable& operator=(const condition_variable&); priority_queue_t m_queue; }; template void condition_variable::wait(unique_lock& lock, Predicate pred) { while (!pred()) { wait(lock); } } template bool condition_variable::wait_until(unique_lock& lock, const time_point& timeout_time, Predicate pred) { while (!pred()) { if (wait_until(lock, timeout_time) == cv_status::timeout) { return pred(); } } return true; } template cv_status condition_variable::wait_for(unique_lock& lock, const std::chrono::duration & timeout_duration) { using namespace std::chrono; using std::chrono::duration; if (timeout_duration <= timeout_duration.zero()) { return cv_status::timeout; } timex_t timeout, before, after; auto s = duration_cast(timeout_duration); timeout.seconds = s.count(); timeout.microseconds = (duration_cast(timeout_duration - s)).count(); xtimer_now_timex(&before); xtimer_t timer; xtimer_set_wakeup(&timer, timex_uint64(timeout), sched_active_pid); wait(lock); xtimer_now_timex(&after); xtimer_remove(&timer); auto passed = timex_sub(after, before); auto cmp = timex_cmp(passed, timeout); return cmp < 1 ? cv_status::no_timeout : cv_status::timeout; } template inline bool condition_variable::wait_for(unique_lock& lock, const std::chrono::duration & timeout_duration, Predicate pred) { return wait_until(lock, std::chrono::steady_clock::now() + timeout_duration, std::move(pred)); } } // namespace riot #endif // RIOT_CONDITION_VARIABLE_HPP