mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
200 lines
6.8 KiB
C++
200 lines
6.8 KiB
C++
/*
|
|
* 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 <a href="http://en.cppreference.com/w/cpp/thread/condition_variable">
|
|
* std::condition_variable
|
|
* </a>
|
|
*
|
|
* @author Raphael Hiesgen <raphael.hiesgen (at) haw-hamburg.de>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#ifndef RIOT_CONDITION_VARIABLE_HPP
|
|
#define RIOT_CONDITION_VARIABLE_HPP
|
|
|
|
#include "sched.h"
|
|
#include "ztimer64.h"
|
|
#include "priority_queue.h"
|
|
|
|
#include "riot/mutex.hpp"
|
|
#include "riot/chrono.hpp"
|
|
|
|
namespace riot {
|
|
|
|
/**
|
|
* @brief Status for timeout-based calls of the condition variable.
|
|
*/
|
|
enum class cv_status {
|
|
no_timeout,
|
|
timeout
|
|
};
|
|
|
|
/**
|
|
* @brief C++11 compliant implementation of condition variable, uses the time
|
|
* point implemented in our chrono replacement instead of the
|
|
* specified one
|
|
* @see <a href="http://en.cppreference.com/w/cpp/thread/condition_variable">
|
|
* std::condition_variable
|
|
* </a>
|
|
*/
|
|
class condition_variable {
|
|
public:
|
|
/**
|
|
* @brief The native handle type used by the condition variable.
|
|
*/
|
|
using native_handle_type = priority_queue_t*;
|
|
inline condition_variable() { m_queue.first = NULL; }
|
|
~condition_variable();
|
|
|
|
/**
|
|
* @brief Notify one thread waiting on this condition.
|
|
*/
|
|
void notify_one() noexcept;
|
|
/**
|
|
* @brief Notify all threads waiting on this condition variable.
|
|
*/
|
|
void notify_all() noexcept;
|
|
|
|
/**
|
|
* @brief Block until woken up through the condition variable.
|
|
* @param lock A lock that is locked by the current thread.
|
|
*/
|
|
void wait(unique_lock<mutex>& lock) noexcept;
|
|
/**
|
|
* @brief Block until woken up through the condition variable and a predicate
|
|
* is fulfilled.
|
|
* @param lock A lock that is locked by the current thread.
|
|
* @param pred A predicate that returns a bool to signify if the thread
|
|
* should continue to wait when woken up through the cv.
|
|
*/
|
|
template <class Predicate>
|
|
void wait(unique_lock<mutex>& lock, Predicate pred);
|
|
/**
|
|
* @brief Block until woken up through the condition variable or a specified
|
|
* point in time is reached. The lock is reacquired either way.
|
|
* @param lock A lock that is locked by the current thread.
|
|
* @param timeout_time Point in time when the thread is woken up
|
|
* independently of the condition variable.
|
|
* @return A status to signify if woken up due to a timeout or the cv.
|
|
*/
|
|
cv_status wait_until(unique_lock<mutex>& lock,
|
|
const time_point& timeout_time);
|
|
/**
|
|
* @brief Block until woken up through the condition variable and a predicate
|
|
* is fulfilled or a specified point in time is reached. The lock is
|
|
* reacquired either way.
|
|
* @param lock A lock that is locked by the current thread.
|
|
* @param timeout_time Point in time when the thread is woken up
|
|
* independently of the condition variable.
|
|
* @param pred A predicate that returns a bool to signify if the
|
|
* thread should continue to wait when woken up through
|
|
* the cv.
|
|
* @return Result of the pred when the function returns.
|
|
*/
|
|
template <class Predicate>
|
|
bool wait_until(unique_lock<mutex>& lock, const time_point& timeout_time,
|
|
Predicate pred);
|
|
|
|
/**
|
|
* @brief Blocks until woken up through the condition variable or when the
|
|
* thread has been blocked for a certain time.
|
|
* @param lock A lock that is locked by the current thread.
|
|
* @param rel_time The maximum time spent blocking.
|
|
* @return A status to signify if woken up due to a timeout or the cv.
|
|
*/
|
|
template <class Rep, class Period>
|
|
cv_status wait_for(unique_lock<mutex>& lock,
|
|
const std::chrono::duration<Rep, Period>& rel_time);
|
|
/**
|
|
* @brief Blocks until woken up through the condition variable and a predicate
|
|
* is fulfilled or when the thread has been blocked for a certain time.
|
|
* @param lock A lock that is locked by the current thread.
|
|
* @param rel_time The maximum time spent blocking.
|
|
* @param pred A predicate that returns a bool to signify if the thread
|
|
* should continue to wait when woken up through the cv.
|
|
* @return Result of the pred when the function returns.
|
|
*/
|
|
template <class Rep, class Period, class Predicate>
|
|
bool wait_for(unique_lock<mutex>& lock,
|
|
const std::chrono::duration<Rep, Period>& rel_time,
|
|
Predicate pred);
|
|
|
|
/**
|
|
* @brief Returns the native handle of the condition variable.
|
|
*/
|
|
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 <class Predicate>
|
|
void condition_variable::wait(unique_lock<mutex>& lock, Predicate pred) {
|
|
while (!pred()) {
|
|
wait(lock);
|
|
}
|
|
}
|
|
|
|
template <class Predicate>
|
|
bool condition_variable::wait_until(unique_lock<mutex>& lock,
|
|
const time_point& timeout_time,
|
|
Predicate pred) {
|
|
while (!pred()) {
|
|
if (wait_until(lock, timeout_time) == cv_status::timeout) {
|
|
return pred();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <class Rep, class Period>
|
|
cv_status condition_variable::wait_for(unique_lock<mutex>& lock,
|
|
const std::chrono::duration
|
|
<Rep, Period>& timeout_duration) {
|
|
using namespace std::chrono;
|
|
using std::chrono::duration;
|
|
if (timeout_duration <= timeout_duration.zero()) {
|
|
return cv_status::timeout;
|
|
}
|
|
uint64_t timeout, before, after;
|
|
timeout = (duration_cast<microseconds>(timeout_duration)).count();
|
|
before = ztimer64_now(ZTIMER64_USEC);
|
|
ztimer64_t timer;
|
|
ztimer64_set_wakeup(ZTIMER64_USEC, &timer, timeout, thread_getpid());
|
|
wait(lock);
|
|
after = ztimer64_now(ZTIMER64_USEC);
|
|
ztimer64_remove(ZTIMER64_USEC, &timer);
|
|
if (after - before >= timeout) {
|
|
return cv_status::timeout;
|
|
}
|
|
return cv_status::no_timeout;
|
|
}
|
|
|
|
template <class Rep, class Period, class Predicate>
|
|
inline bool condition_variable::wait_for(unique_lock<mutex>& lock,
|
|
const std::chrono::duration
|
|
<Rep, Period>& 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
|