diff options
Diffstat (limited to 'components/libc/cplusplus/cpp11/gcc/condition_variable')
| -rw-r--r-- | components/libc/cplusplus/cpp11/gcc/condition_variable | 222 |
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 |
