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