summaryrefslogtreecommitdiff
path: root/components/libc/cplusplus/cpp11/gcc/condition_variable
diff options
context:
space:
mode:
Diffstat (limited to 'components/libc/cplusplus/cpp11/gcc/condition_variable')
-rw-r--r--components/libc/cplusplus/cpp11/gcc/condition_variable222
1 files changed, 222 insertions, 0 deletions
diff --git a/components/libc/cplusplus/cpp11/gcc/condition_variable b/components/libc/cplusplus/cpp11/gcc/condition_variable
new file mode 100644
index 0000000000..f2d48dd5b5
--- /dev/null
+++ b/components/libc/cplusplus/cpp11/gcc/condition_variable
@@ -0,0 +1,222 @@
+#pragma once
+
+#if __cplusplus < 201103L
+#error "C++ version lower than C++11"
+#endif
+
+#include <pthread.h>
+
+#include <system_error>
+#include <chrono>
+#include <utility>
+#include <functional>
+#include <memory>
+
+#include "__utils.h"
+#include "mutex"
+
+#define rt_cpp_cond_var pthread_cond_t
+
+namespace std
+{
+
+ enum class cv_status
+ {
+ no_timeout,
+ timeout
+ };
+
+ class condition_variable
+ {
+ public:
+ typedef rt_cpp_cond_var *native_handle_type;
+
+ condition_variable(const condition_variable &) = delete;
+ condition_variable &operator=(const condition_variable &) = delete;
+
+ condition_variable() = default;
+
+ ~condition_variable()
+ {
+ pthread_cond_destroy(&_m_cond);
+ }
+
+ void wait(unique_lock<mutex> &lock);
+
+ void notify_one() noexcept
+ {
+ pthread_cond_signal(&_m_cond);
+ }
+
+ void notify_all() noexcept
+ {
+ pthread_cond_broadcast(&_m_cond);
+ }
+
+ template <class Predicate>
+ void wait(unique_lock<mutex> &lock, Predicate pred)
+ {
+ while (!pred())
+ wait(lock);
+ }
+
+ template <class Clock, class Duration>
+ cv_status wait_until(unique_lock<mutex> &lock,
+ const chrono::time_point<Clock, Duration> &abs_time)
+ {
+ if (!lock.owns_lock())
+ throw_system_error((int)errc::operation_not_permitted,
+ "condition_variable::wailt_until: waiting on unlocked lock");
+ auto secs = chrono::time_point_cast<chrono::seconds>(abs_time);
+ auto nano_secs = chrono::duration_cast<chrono::nanoseconds>(abs_time - secs);
+
+ struct timespec c_abs_time = {static_cast<time_t>(secs.time_since_epoch().count()),
+ static_cast<long>(nano_secs.count())};
+
+ pthread_cond_timedwait(&_m_cond, lock.mutex()->native_handle(), &c_abs_time);
+
+ return (Clock::now() < abs_time) ? cv_status::no_timeout : cv_status::timeout;
+ }
+
+ template <class Clock, class Duration, class Predicate>
+ bool wait_until(unique_lock<mutex> &lock,
+ const chrono::time_point<Clock, Duration> &abs_time,
+ Predicate pred)
+ {
+ while (!pred())
+ if (wait_until(lock, abs_time) == cv_status::timeout)
+ return pred();
+ return true;
+ }
+
+ template <class Rep, class Period>
+ cv_status wait_for(unique_lock<mutex> &lock,
+ const chrono::duration<Rep, Period> &rel_time)
+ {
+ return wait_until(lock, real_time_clock::now() + rel_time);
+ }
+
+ template <class Rep, class Period, class Predicate>
+ bool wait_for(unique_lock<mutex> &lock,
+ const chrono::duration<Rep, Period> &rel_time,
+ Predicate pred)
+ {
+ return wait_until(lock, real_time_clock::now() + rel_time, std::move(pred));
+ }
+
+ native_handle_type native_handle()
+ {
+ return &_m_cond;
+ }
+
+ private:
+ rt_cpp_cond_var _m_cond = PTHREAD_COND_INITIALIZER;
+ };
+
+ // Lockable is only required to have `lock()` and `unlock()`
+ class condition_variable_any
+ {
+ private:
+ condition_variable _m_cond;
+ shared_ptr<mutex> _m_mtx;
+
+ // so that Lockable automatically unlocks when waiting and locks after waiting
+ template <class Lockable>
+ struct unlocker
+ {
+ Lockable &_m_lock;
+
+ explicit unlocker(Lockable &lk)
+ : _m_lock(lk)
+ {
+ _m_lock.unlock();
+ }
+
+ ~unlocker()
+ {
+ _m_lock.lock();
+ }
+
+ unlocker(const unlocker &) = delete;
+ unlocker &operator=(const unlocker &) = delete;
+ };
+
+ public:
+ condition_variable_any() : _m_mtx(std::make_shared<mutex>()) {}
+ ~condition_variable_any() = default;
+
+ condition_variable_any(const condition_variable_any &) = delete;
+ condition_variable_any &operator=(const condition_variable_any &) = delete;
+
+ void notify_one() noexcept
+ {
+ lock_guard<mutex> lk(*_m_mtx);
+ _m_cond.notify_one();
+ }
+
+ void notify_all() noexcept
+ {
+ lock_guard<mutex> lk(*_m_mtx);
+ _m_cond.notify_all();
+ }
+
+ template <class Lock>
+ void wait(Lock &lock)
+ {
+ shared_ptr<mutex> mut = _m_mtx;
+ unique_lock<mutex> lk(*mut);
+ unlocker<Lock> auto_lk(lock); // unlock here
+
+ unique_lock<mutex> lk2(std::move(lk));
+ _m_cond.wait(lk2);
+ } // mut.unlock(); lock.lock();
+
+ template <class Lock, class Predicate>
+ void wait(Lock &lock, Predicate pred)
+ {
+ while (!pred())
+ wait(lock);
+ }
+
+ template <class Lock, class Clock, class Duration>
+ cv_status wait_until(Lock &lock,
+ const chrono::time_point<Clock, Duration> &abs_time)
+ {
+ shared_ptr<mutex> mut = _m_mtx;
+ unique_lock<mutex> lk(*mut);
+ unlocker<Lock> auto_lk(lock); // unlock here
+
+ unique_lock<mutex> lk2(std::move(lk));
+ return _m_cond.wait_until(lk2, abs_time);
+ }
+
+ template <class Lock, class Clock, class Duration, class Predicate>
+ bool wait_until(Lock &lock,
+ const chrono::time_point<Clock, Duration> &abs_time,
+ Predicate pred)
+ {
+ while (!pred())
+ if (wait_until(lock, abs_time) == cv_status::timeout)
+ return pred();
+ return true;
+ }
+
+ template <class Lock, class Rep, class Period>
+ cv_status wait_for(Lock &lock,
+ const chrono::duration<Rep, Period> &rel_time)
+ {
+ return wait_until(lock, real_time_clock::now() + rel_time);
+ }
+
+ template <class Lock, class Rep, class Period, class Predicate>
+ bool wait_for(Lock &lock,
+ const chrono::duration<Rep, Period> &rel_time,
+ Predicate pred)
+ {
+ return wait_until(lock, real_time_clock::now() + rel_time, std::move(pred));
+ }
+ };
+
+ void notify_all_at_thread_exit(condition_variable &cond, unique_lock<mutex> lk);
+
+} // namespace std