diff options
| author | guo <[email protected]> | 2021-09-28 10:36:54 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-09-28 10:36:54 +0800 |
| commit | 55a302cd092758a44b589d65470a69d9e8ae4ced (patch) | |
| tree | e60fc53994c426007e9eb4877e5bd123f124ef39 /components/cplusplus/cpp11/gcc | |
| parent | 00727d6b6db92dc1cf98f028f26fd6168594b905 (diff) | |
| parent | 00d42ef73cff61ecda7ff006b077a73e1a4ff669 (diff) | |
Merge branch 'master' into usbh_construct
Diffstat (limited to 'components/cplusplus/cpp11/gcc')
| -rw-r--r-- | components/cplusplus/cpp11/gcc/__utils.h | 59 | ||||
| -rw-r--r-- | components/cplusplus/cpp11/gcc/condition_variable | 222 | ||||
| -rw-r--r-- | components/cplusplus/cpp11/gcc/condition_variable.cpp | 34 | ||||
| -rw-r--r-- | components/cplusplus/cpp11/gcc/future | 336 | ||||
| -rw-r--r-- | components/cplusplus/cpp11/gcc/mutex | 512 | ||||
| -rw-r--r-- | components/cplusplus/cpp11/gcc/mutex.cpp | 52 | ||||
| -rw-r--r-- | components/cplusplus/cpp11/gcc/thread | 239 | ||||
| -rw-r--r-- | components/cplusplus/cpp11/gcc/thread.cpp | 94 | ||||
| -rw-r--r-- | components/cplusplus/cpp11/gcc/utils.cpp | 29 |
9 files changed, 1577 insertions, 0 deletions
diff --git a/components/cplusplus/cpp11/gcc/__utils.h b/components/cplusplus/cpp11/gcc/__utils.h new file mode 100644 index 0000000000..f9a3c93796 --- /dev/null +++ b/components/cplusplus/cpp11/gcc/__utils.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-04-27 flybreak the first version. + */ + +#pragma once + +#include <cstdlib> +#include <system_error> +#include <chrono> +#include <ratio> + +#include <rtthread.h> + +#define RT_USING_CPP_EXCEPTION + +inline void throw_system_error(int err, const char *what_msg) +{ +#ifdef RT_USING_CPP_EXCEPTION + throw std::system_error(std::error_code(err, std::system_category()), what_msg); +#else + (void)err; + (void)what_msg; + ::abort(); +#endif +} + +class tick_clock +{ +public: + typedef clock_t rep; + typedef std::ratio<1, RT_TICK_PER_SECOND> period; + + typedef std::chrono::duration<tick_clock::rep, tick_clock::period> duration; + typedef std::chrono::time_point<tick_clock> time_point; + + constexpr static bool is_ready = true; + + static time_point now(); +}; + +class real_time_clock +{ +public: + typedef std::chrono::nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef std::chrono::time_point<real_time_clock, duration> time_point; + + static constexpr bool is_steady = true; + + static time_point + now() noexcept; +}; diff --git a/components/cplusplus/cpp11/gcc/condition_variable b/components/cplusplus/cpp11/gcc/condition_variable new file mode 100644 index 0000000000..f2d48dd5b5 --- /dev/null +++ b/components/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 diff --git a/components/cplusplus/cpp11/gcc/condition_variable.cpp b/components/cplusplus/cpp11/gcc/condition_variable.cpp new file mode 100644 index 0000000000..2860dd9161 --- /dev/null +++ b/components/cplusplus/cpp11/gcc/condition_variable.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-04-27 flybreak the first version. + */ + +#include "condition_variable" + +namespace std +{ + void condition_variable::wait(unique_lock<mutex>& lock) + { + int err = pthread_cond_wait(&_m_cond, lock.mutex()->native_handle()); + + if (err) + { + throw_system_error(err, "condition_variable::wait: failed to wait on a condition"); + } + } + + void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk) + { + // TLS currently not available + mutex* mut = lk.release(); + mut->unlock(); + cond.notify_all(); + } + + +} // namespace std diff --git a/components/cplusplus/cpp11/gcc/future b/components/cplusplus/cpp11/gcc/future new file mode 100644 index 0000000000..6a686063fb --- /dev/null +++ b/components/cplusplus/cpp11/gcc/future @@ -0,0 +1,336 @@ +#pragma once + +#if __cplusplus < 201103L +#error "C++ version lower than C++11" +#endif + +#include <mutex> +#include <condition_variable> +#include <memory> +#include <chrono> +#include <cassert> + +namespace std { + +enum class future_status { + ready, + timeout, + deferred +}; + +namespace detail { + +class shared_state_base { +protected: + typedef void (*deleter_fn)(void *v); + + using scoped_lock = std::lock_guard<std::mutex>; + using unique_lock = std::unique_lock<std::mutex>; +public: + explicit shared_state_base(deleter_fn d) : v_(nullptr), d_(d), valid_(true) {} + + ~shared_state_base() { d_(v_); } + + shared_state_base(shared_state_base &&other) = delete; + + shared_state_base(const shared_state_base &other) = delete; + + shared_state_base &operator=(shared_state_base &&other) = delete; + + shared_state_base &operator=(const shared_state_base &other) = delete; + + void wait() { + unique_lock lock(m_); + c_.wait(lock, [this] { return has_value(); }); + } + + template <class Rep, class Period> + std::future_status + wait_for(const std::chrono::duration<Rep, Period> &rel_time) { + unique_lock lock(m_); + if (c_.wait_for(lock, rel_time, [this] { return has_value(); })) { + return std::future_status::ready; + } + return std::future_status::timeout; + } + + template <class Clock, class Duration> + std::future_status + wait_until(const std::chrono::time_point<Clock, Duration> &abs_time) { + unique_lock lock(m_); + if (c_.wait_until(lock, abs_time, [this] { return has_value(); })) { + return std::future_status::ready; + } + return std::future_status::timeout; + } + +protected: + bool has_value() { return v_ != nullptr; } + +protected: + std::mutex m_; + std::condition_variable c_; + void *v_; + deleter_fn d_; + bool valid_; +}; + + +template <typename R> +class shared_state: public shared_state_base { +public: + shared_state() :shared_state_base(default_deleter_) {} + + ~shared_state() {} + + R &get() { + wait(); + scoped_lock lock(m_); + assert(valid_); + valid_ = false; + return *(static_cast<R *>(v_)); + } + + void set(const R &v) { + scoped_lock lock(m_); + assert(!has_value()); + v_ = new R(v); + valid_ = true; + c_.notify_one(); + } + + void set(R &&v) { + scoped_lock lock(m_); + assert(!has_value()); + v_ = new R(std::move(v)); + valid_ = true; + c_.notify_one(); + } + + bool valid() { + scoped_lock lock(m_); + return valid_; + } + +private: + static void default_deleter_(void *v) { delete static_cast<R *>(v); } +}; + +} // namespace detail + +template <typename R> +class shared_future { +}; + + +template <typename R> +class future { + using state_type = std::shared_ptr<detail::shared_state<R>>; +public: + future() {} + + explicit future(const state_type &state) : state_(state) {} + + future(future &&other) noexcept: state_(std::move(other.state_)) { + other.state_.reset(); + } + + future(const future &other) = delete; + + ~future() {} + + future &operator=(future &&other) noexcept { + if (&other != this) { + state_ = std::move(other.state_); + other.state_.reset(); + } + return *this; + } + + future &operator=(const future &other) = delete; + + void swap(future &other) noexcept { + std::swap(state_, other.state_); + } + + std::shared_future<R> share() noexcept { return std::shared_future<R>(); } + + R get() { return state_->get(); } + + bool valid() const noexcept { return state_->valid(); } + + void wait() const { state_->wait(); } + + template <class Rep, class Period> + std::future_status + wait_for(const std::chrono::duration<Rep, Period> &rel_time) const { + return state_->wait_for(rel_time); + } + + template <class Clock, class Duration> + std::future_status + wait_until(const std::chrono::time_point<Clock, Duration> &abs_time) const { + return state_->wait_until(abs_time); + } + +private: + state_type state_; +}; + + +template <> +class future<void> { + using state_type = std::shared_ptr<detail::shared_state<int>>; +public: + future() {} + + explicit future(const state_type &state) : state_(state) {} + + future(future &&other) noexcept: state_(std::move(other.state_)) { + other.state_.reset(); + } + + future(const future &other) = delete; + + ~future() {} + + future &operator=(future &&other) noexcept { + if (&other != this) { + state_ = std::move(other.state_); + other.state_.reset(); + } + return *this; + } + + future &operator=(const future &other) = delete; + + void swap(future &other) noexcept { + std::swap(state_, other.state_); + } + + std::shared_future<void> share() noexcept { return std::shared_future<void>(); } + + void get() { state_->get(); } + + bool valid() const noexcept { return state_->valid(); } + + void wait() const { state_->wait(); } + + template <class Rep, class Period> + std::future_status + wait_for(const std::chrono::duration<Rep, Period> &rel_time) const { + return state_->wait_for(rel_time); + } + + template <class Clock, class Duration> + std::future_status + wait_until(const std::chrono::time_point<Clock, Duration> &abs_time) const { + return state_->wait_until(abs_time); + } + +private: + state_type state_; +}; + + +template <typename R> +class promise { + using state_type = std::shared_ptr<detail::shared_state<R>>; +public: + promise() : state_(new detail::shared_state<R>()) {} + + promise(promise &&other) noexcept: state_(std::move(other.state_)) { + other.state_.reset(); + } + + promise(const promise &other) = delete; + + ~promise() {} + + promise &operator=(promise &&other) noexcept { + if (&other != this) { + state_ = std::move(other.state_); + other.state_.reset(); + } + return *this; + } + + promise &operator=(const promise &other) = delete; + + void swap(promise &other) noexcept { + std::swap(state_, other.state_); + } + + std::future<R> get_future() { return std::future<R>(state_); } + + void set_value(const R &value) { state_->set(value); } + + void set_value(R &&value) { state_->set(std::move(value)); } + + void set_value_at_thread_exit(const R &value); + + void set_value_at_thread_exit(R &&value); + + void set_exception(std::exception_ptr p); + + void set_exception_at_thread_exit(std::exception_ptr p); + +private: + state_type state_; +}; + + +template <> +class promise<void> { + using state_type = std::shared_ptr<detail::shared_state<int>>; +public: + promise() : state_(new detail::shared_state<int>()) {} + + promise(promise &&other) noexcept: state_(std::move(other.state_)) { + other.state_.reset(); + } + + promise(const promise &other) = delete; + + ~promise() {} + + promise &operator=(promise &&other) noexcept { + if (&other != this) { + state_ = std::move(other.state_); + other.state_.reset(); + } + return *this; + } + + promise &operator=(const promise &other) = delete; + + void swap(promise &other) noexcept { + std::swap(state_, other.state_); + } + + std::future<void> get_future() { return std::future<void>(state_); } + + void set_value() { state_->set(0); } + + void set_value_at_thread_exit(); + + void set_exception(std::exception_ptr p); + + void set_exception_at_thread_exit(std::exception_ptr p); + +private: + state_type state_; +}; + + +template <class R> +void swap(std::future<R> &lhs, std::future<R> &rhs) noexcept { + lhs.swap(rhs); +} + +template <class R> +void swap(std::promise<R> &lhs, std::promise<R> &rhs) noexcept { + lhs.swap(rhs); +} + +} // namespace std diff --git a/components/cplusplus/cpp11/gcc/mutex b/components/cplusplus/cpp11/gcc/mutex new file mode 100644 index 0000000000..cc593cc139 --- /dev/null +++ b/components/cplusplus/cpp11/gcc/mutex @@ -0,0 +1,512 @@ +#pragma once + +#if __cplusplus < 201103L +#error "C++ version lower than C++11" +#endif + +//#if defined(RT_USING_LIBC) && defined(RT_USING_PTHREADS) + +#include <pthread.h> + +#include <system_error> +#include <chrono> +#include <utility> +#include <functional> + +#include "__utils.h" + +#define rt_cpp_mutex_t pthread_mutex_t + +namespace std +{ + // Base class on which to build std::mutex and std::timed_mutex + class __mutex_base + { + protected: + typedef rt_cpp_mutex_t __native_type; + + __native_type _m_mutex = PTHREAD_MUTEX_INITIALIZER; + + constexpr __mutex_base() noexcept = default; + __mutex_base(const __mutex_base&) = delete; + __mutex_base& operator=(const __mutex_base&) = delete; + }; + + + class mutex : private __mutex_base + { + public: + constexpr mutex() = default; + ~mutex() = default; + + mutex(const mutex&) = delete; + mutex& operator=(const mutex&) = delete; + + void lock() + { + int err = pthread_mutex_lock(&_m_mutex); + + if (err) + { + throw_system_error(err, "mutex:lock failed."); + } + } + + bool try_lock() noexcept + { + return !pthread_mutex_trylock(&_m_mutex); + } + + void unlock() noexcept + { + pthread_mutex_unlock(&_m_mutex); + } + + typedef __native_type* native_handle_type; + + native_handle_type native_handle() + { + return &_m_mutex; + }; + + }; + + inline int __rt_cpp_recursive_mutex_init(rt_cpp_mutex_t* m) + { + pthread_mutexattr_t attr; + int res; + + res = pthread_mutexattr_init(&attr); + if (res) + return res; + res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + if (res) + goto attr_cleanup; + res = pthread_mutex_init(m, &attr); + + attr_cleanup: + int err = pthread_mutexattr_destroy(&attr); + return res ? res : err; + } + + class __recursive_mutex_base + { + protected: + typedef rt_cpp_mutex_t __native_type; + + __native_type _m_recursive_mutex; + + __recursive_mutex_base(const __recursive_mutex_base&) = delete; + __recursive_mutex_base& operator=(const __recursive_mutex_base&) = delete; + + __recursive_mutex_base() + { + int err = __rt_cpp_recursive_mutex_init(&_m_recursive_mutex); + if (err) + throw_system_error(err, "Recursive mutex failed to construct"); + } + + ~__recursive_mutex_base() + { + pthread_mutex_destroy(&_m_recursive_mutex); + } + }; + + class recursive_mutex : private __recursive_mutex_base + { + public: + typedef __native_type* native_handle_type; + recursive_mutex() = default; + ~recursive_mutex() = default; + + recursive_mutex(const recursive_mutex&) = delete; + recursive_mutex& operator=(const recursive_mutex&) = delete; + void lock() + { + int err = pthread_mutex_lock(&_m_recursive_mutex); + + if (err) + throw_system_error(err, "recursive_mutex::lock failed"); + } + + bool try_lock() noexcept + { + return !pthread_mutex_trylock(&_m_recursive_mutex); + } + + void unlock() noexcept + { + pthread_mutex_unlock(&_m_recursive_mutex); + } + + native_handle_type native_handle() + { return &_m_recursive_mutex; } + }; + +#ifdef RT_PTHREAD_TIMED_MUTEX + + class timed_mutex; + + class recursive_timed_mutex; + +#endif // RT_PTHREAD_TIMED_MUTEX + + + struct defer_lock_t {}; + struct try_to_lock_t {}; + struct adopt_lock_t {}; // take ownership of a locked mtuex + + constexpr defer_lock_t defer_lock { }; + constexpr try_to_lock_t try_to_lock { }; + constexpr adopt_lock_t adopt_lock { }; + + template <class Mutex> + class lock_guard + { + public: + typedef Mutex mutex_type; + + explicit lock_guard(mutex_type& m) : pm(m) { pm.lock(); } + lock_guard(mutex_type& m, adopt_lock_t) noexcept : pm(m) + { } + ~lock_guard() + { pm.unlock(); } + + lock_guard(lock_guard const&) = delete; + lock_guard& operator=(lock_guard const&) = delete; + + private: + mutex_type& pm; + + }; + + template <class Mutex> + class unique_lock + { + public: + typedef Mutex mutex_type; + + unique_lock() noexcept : pm(nullptr), owns(false) { } + + explicit unique_lock(mutex_type& m) + : pm(std::addressof(m)), owns(false) + { + lock(); + owns = true; + } + + unique_lock(mutex_type& m, defer_lock_t) noexcept + : pm(std::addressof(m)), owns(false) + { } + + unique_lock(mutex_type& m, try_to_lock_t) noexcept + : pm(std::addressof(m)), owns(pm->try_lock()) + { } + + unique_lock(mutex_type& m, adopt_lock_t) noexcept + : pm(std::addressof(m)), owns(true) + { } + + // any lock-involving timed mutex API is currently only for custom implementations + // the standard ones are not available + template <class Clock, class Duration> + unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time) noexcept + : pm(std::addressof(m)), owns(pm->try_lock_until(abs_time)) + { } + + template <class Rep, class Period> + unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time) noexcept + : pm(std::addressof(m)), owns(pm->try_lock_for(rel_time)) + { } + + ~unique_lock() + { + if (owns) + unlock(); + } + + unique_lock(unique_lock const&) = delete; + unique_lock& operator=(unique_lock const&) = delete; + + unique_lock(unique_lock&& u) noexcept + : pm(u.pm), owns(u.owns) + { + u.pm = nullptr; + u.owns = false; + } + + unique_lock& operator=(unique_lock&& u) noexcept + { + if (owns) + unlock(); + + unique_lock(std::move(u)).swap(*this); + + u.pm = nullptr; + u.owns = false; + + return *this; + } + + void lock() + { + if (!pm) + throw_system_error(int(errc::operation_not_permitted), + "unique_lock::lock: references null mutex"); + else if (owns) + throw_system_error(int(errc::resource_deadlock_would_occur), + "unique_lock::lock: already locked" ); + else { + pm->lock(); + owns = true; + } + } + + bool try_lock() + { + if (!pm) + throw_system_error(int(errc::operation_not_permitted), + "unique_lock::try_lock: references null mutex"); + else if (owns) + throw_system_error(int(errc::resource_deadlock_would_occur), + "unique_lock::try_lock: already locked" ); + else { + owns = pm->try_lock(); + } + return owns; + } + + template <class Rep, class Period> + bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) + { + if (!pm) + throw_system_error(int(errc::operation_not_permitted), + "unique_lock::try_lock_for: references null mutex"); + else if (owns) + throw_system_error(int(errc::resource_deadlock_would_occur), + "unique_lock::try_lock_for: already locked"); + else { + owns = pm->try_lock_for(rel_time); + } + return owns; + } + + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) + { + if (!pm) + throw_system_error(int(errc::operation_not_permitted), + "unique_lock::try_lock_until: references null mutex"); + else if (owns) + throw_system_error(int(errc::resource_deadlock_would_occur), + "unique_lock::try_lock_until: already locked"); + else { + owns = pm->try_lock_until(abs_time); + } + return owns; + } + + void unlock() + { + if (!owns) + throw_system_error(int(errc::operation_not_permitted), + "unique_lock::unlock: not locked"); + else { + pm->unlock(); + owns = false; + } + } + + void swap(unique_lock& u) noexcept + { + std::swap(pm, u.pm); + std::swap(owns, u.owns); + } + + mutex_type *release() noexcept + { + mutex_type* ret_mutex = pm; + pm = nullptr; + owns = false; + + return ret_mutex; + } + + bool owns_lock() const noexcept + { return owns; } + + explicit operator bool() const noexcept + { return owns_lock(); } + + mutex_type* mutex() const noexcept + { return pm; } + + + private: + mutex_type *pm; + bool owns; + }; + + template <class Mutex> + void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) + { + x.swap(y); + } + + template <class L0, class L1> + int try_lock(L0& l0, L1& l1) + { + unique_lock<L0> u0(l0, try_to_lock); // try to lock the first Lockable + // using unique_lock since we don't want to unlock l0 manually if l1 fails to lock + if (u0.owns_lock()) + { + if (l1.try_lock()) // lock the second one + { + u0.release(); // do not let RAII of a unique_lock unlock l0 + return -1; + } + else + return 1; + } + return 0; + } + + + template <class L0, class L1, class L2, class... L3> + int try_lock(L0& l0, L1& l1, L2& l2, L3&... l3) + { + int r = 0; + unique_lock<L0> u0(l0, try_to_lock); + // automatically unlock is done through RAII of unique_lock + if (u0.owns_lock()) + { + r = try_lock(l1, l2, l3...); + if (r == -1) + u0.release(); + else + ++r; + } + return r; + } + + template <class L0, class L1, class L2, class ...L3> + void + __lock_first(int i, L0& l0, L1& l1, L2& l2, L3&... l3) + { + while (true) + { + // we first lock the one that is the most difficult to lock + switch (i) + { + case 0: + { + unique_lock<L0> u0(l0); + i = try_lock(l1, l2, l3...); + if (i == -1) + { + u0.release(); + return; + } + } + ++i; + sched_yield(); + break; + case 1: + { + unique_lock<L1> u1(l1); + i = try_lock(l2, l3..., l0); + if (i == -1) + { + u1.release(); + return; + } + } + if (i == sizeof...(L3) + 1) // all except l0 are locked + i = 0; + else + i += 2; // since i was two-based above + sched_yield(); + break; + default: + __lock_first(i - 2, l2, l3..., l0, l1); + return; + } + } + } + + + template <class L0, class L1> + void lock(L0& l0, L1& l1) + { + while (true) + { + { + unique_lock<L0> u0(l0); + if (l1.try_lock()) + { + u0.release(); + break; + } + } + sched_yield(); + // wait and try the other way + { + unique_lock<L1> u1(l1); + if (l0.try_lock()) + { + u1.release(); + break; + } + } + sched_yield(); + } + } + + template <class L0, class L1, class... L2> + void lock(L0& l0, L1& l1, L2&... l2) + { + __lock_first(0, l0, l1, l2...); + } + + struct once_flag + { + constexpr once_flag() noexcept = default; + + once_flag(const once_flag&) = delete; + once_flag& operator=(const once_flag&) = delete; + + template <class Callable, class... Args> + friend void call_once(once_flag& flag, Callable&& func, Args&&... args); + + private: + pthread_once_t _m_once = PTHREAD_ONCE_INIT; + }; + + mutex& get_once_mutex(); + extern function<void()> once_functor; + extern void set_once_functor_lock_ptr(unique_lock<mutex>*); + + extern "C" void once_proxy(); // passed into pthread_once + + template <class Callable, class... Args> + void call_once(once_flag& flag, Callable&& func, Args&&... args) + { + // use a lock to ensure the call to the functor + // is exclusive to only the first calling thread + unique_lock<mutex> functor_lock(get_once_mutex()); + + auto call_wrapper = std::bind(std::forward<Callable>(func), std::forward<Args>(args)...); + once_functor = [&]() { call_wrapper(); }; + + set_once_functor_lock_ptr(&functor_lock); // so as to unlock when actually calling + + int err = pthread_once(&flag._m_once, &once_proxy); + + if (functor_lock) + set_once_functor_lock_ptr(nullptr); + if (err) + throw_system_error(err, "call_once failed"); + } +} + +//#endif // (RT_USING_LIBC) && (RT_USING_PTHREADS)
\ No newline at end of file diff --git a/components/cplusplus/cpp11/gcc/mutex.cpp b/components/cplusplus/cpp11/gcc/mutex.cpp new file mode 100644 index 0000000000..014460ffde --- /dev/null +++ b/components/cplusplus/cpp11/gcc/mutex.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-04-27 flybreak the first version. + */ + +#include "mutex" + +namespace std +{ + // use a set of global and static objects + // a proxy function to pthread_once + + function<void()> once_functor; + + mutex& get_once_mutex() + { + static mutex once_mutex; + return once_mutex; + } + + inline unique_lock<mutex>*& get_once_functor_lock_ptr() + { + static unique_lock<mutex>* once_functor_mutex_ptr = nullptr; + return once_functor_mutex_ptr; + } + + void set_once_functor_lock_ptr(unique_lock<mutex>* m_ptr) + { + get_once_functor_lock_ptr() = m_ptr; + } + + extern "C" + { + void once_proxy() + { + // need to first transfer the functor's ownership so as to call it + function<void()> once_call = std::move(once_functor); + + // no need to hold the lock anymore + unique_lock<mutex>* lock_ptr = get_once_functor_lock_ptr(); + get_once_functor_lock_ptr() = nullptr; + lock_ptr->unlock(); + + once_call(); + } + } +} diff --git a/components/cplusplus/cpp11/gcc/thread b/components/cplusplus/cpp11/gcc/thread new file mode 100644 index 0000000000..5b64decd6a --- /dev/null +++ b/components/cplusplus/cpp11/gcc/thread @@ -0,0 +1,239 @@ +#pragma once + +#if __cplusplus < 201103L +#error "C++ version lower than C++11" +#endif + +//#if defined(RT_USING_LIBC) && defined(RT_USING_PTHREADS) + +#include <unistd.h> +#include <pthread.h> +#include <sched.h> +#include <rtthread.h> + +#include <cstddef> +#include <cerrno> +#include <ostream> +#include <functional> +#include <utility> +#include <chrono> +#include <memory> + +#define rt_cpp_thread_t pthread_t +#ifndef PTHREAD_NUM_MAX +#define PTHREAD_NUM_MAX 32 +#endif +#define CPP_UNJOINABLE_THREAD PTHREAD_NUM_MAX + +namespace std +{ + #define __STDCPP_THREADS__ __cplusplus + + + + class thread + { + public: + typedef rt_cpp_thread_t native_handle_type; + + struct invoker_base; + typedef shared_ptr<invoker_base> invoker_base_ptr; + + class id + { + // basically a wrapper around native_handle_type + native_handle_type __cpp_thread_t; + + public: + id() noexcept : __cpp_thread_t(CPP_UNJOINABLE_THREAD) {} + + explicit id(native_handle_type hid) + : __cpp_thread_t(hid) {} + private: + friend class thread; + friend class hash<thread::id>; + + friend bool operator==(thread::id x, thread::id y) noexcept; + + friend bool operator<(thread::id x, thread::id y) noexcept; + + template <class charT, class traits> + friend basic_ostream<charT, traits>& + operator<<(basic_ostream<charT, traits>& out, thread::id id); + }; + + thread() noexcept = default; + thread(const thread&) = delete; + thread& operator=(const thread&) = delete; + ~thread(); + + template <class F, class ...Args> + explicit thread(F&& f, Args&&... args) + { + start_thread(make_invoker_ptr(std::bind( + std::forward<F>(f), + std::forward<Args>(args)... + ))); + } + + thread(thread&& t) noexcept + { + swap(t); + } + + thread& operator=(thread&& t) noexcept + { + if (joinable()) + terminate(); + swap(t); + return *this; + } + + // member functions + void swap(thread& t) noexcept + { + std::swap(_m_thr, t._m_thr); + } + + bool joinable() const noexcept + { + return (_m_thr.__cpp_thread_t < PTHREAD_NUM_MAX); + } + + void join(); + + void detach(); + + id get_id() const noexcept { return _m_thr; } + + native_handle_type native_handle() { return _m_thr.__cpp_thread_t; } + + // static members + static unsigned hardware_concurrency() noexcept; + + private: + id _m_thr; + + void start_thread(invoker_base_ptr b); + public: + struct invoker_base + { + invoker_base_ptr this_ptr; + + virtual ~invoker_base() = default; + + virtual void invoke() = 0; + }; + + + template<typename Callable> + struct invoker : public invoker_base + { + Callable func; + + invoker(Callable&& F) : func(std::forward<Callable>(F)) { } + + void invoke() { func(); } + }; + + template <typename Callable> + shared_ptr<invoker<Callable>> make_invoker_ptr(Callable&& F) + { + return std::make_shared<invoker<Callable>>(std::forward<Callable>(F)); + } + + + }; + + inline void swap(thread& x, thread& y) noexcept + { + x.swap(y); + } + + + inline bool operator==(thread::id x, thread::id y) noexcept + { + // From POSIX for pthread_equal: + //"If either t1 or t2 are not valid thread IDs, the behavior is undefined." + return x.__cpp_thread_t == y.__cpp_thread_t; + } + + inline bool operator!=(thread::id x, thread::id y) noexcept + { + return !(x == y); + } + + inline bool operator<(thread::id x, thread::id y) noexcept + { + return x.__cpp_thread_t < y.__cpp_thread_t; + } + + inline bool operator<=(thread::id x, thread::id y) noexcept + { + return !(y < x); + } + + inline bool operator>(thread::id x, thread::id y) noexcept + { + return !(x <= y); + } + + inline bool operator>=(thread::id x, thread::id y) noexcept + { + return !(x < y); + } + + template <class charT, class traits> + inline basic_ostream<charT, traits>& + operator<<(basic_ostream<charT, traits>& out, thread::id id) + { + if (id == thread::id()) // id is invalid, representing no pthread + out << "thread::id of a non-executing thread"; + else + out << id.__cpp_thread_t; + return out; + } + + template <> + struct hash<thread::id> + { + typedef size_t result_type; + typedef thread::id argument_type; + size_t operator()(const thread::id& id) const noexcept + { + return hash<rt_cpp_thread_t>()(id.__cpp_thread_t); + } + }; + + namespace this_thread + { + inline thread::id get_id() noexcept + { + return thread::id(pthread_self()); + } + + inline void yield() noexcept + { + sched_yield(); + } + + template <class Rep, class Period> + inline void sleep_for(const chrono::duration<Rep, Period>& rel_time) + { + if (rel_time <= rel_time.zero()) // less than zero, no need to sleep + return; + auto milli_secs = chrono::duration_cast<chrono::milliseconds>(rel_time); + // the precision is limited by rt-thread thread API + rt_thread_mdelay(milli_secs.count()); + } + + template <class Clock, class Duration> + inline void sleep_until(const chrono::time_point<Clock, Duration>& abs_time) + { + auto now = Clock::now(); + if (abs_time > now) + sleep_for(abs_time - now); + } + + } +} diff --git a/components/cplusplus/cpp11/gcc/thread.cpp b/components/cplusplus/cpp11/gcc/thread.cpp new file mode 100644 index 0000000000..947170da25 --- /dev/null +++ b/components/cplusplus/cpp11/gcc/thread.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-04-27 flybreak the first version. + */ + +#include "thread" +#include "__utils.h" + + +#define _RT_NPROCS 0 + +namespace std +{ + + extern "C" + { + static void* execute_native_thread_routine(void *p) + { + thread::invoker_base* t = static_cast<thread::invoker_base*>(p); + thread::invoker_base_ptr local; + local.swap(t->this_ptr); // tranfer the ownership of the invoker into the thread entry + + local->invoke(); + + return NULL; + } + } + + void thread::start_thread(invoker_base_ptr b) + { + auto raw_ptr = b.get(); + // transfer the ownership of the invoker to the new thread + raw_ptr->this_ptr = std::move(b); + int err = pthread_create(&_m_thr.__cpp_thread_t, NULL, + &execute_native_thread_routine, raw_ptr); + + if (err) + { + raw_ptr->this_ptr.reset(); + throw_system_error(err, "Failed to create a thread"); + } + + } + + thread::~thread() + { + if (joinable()) // when either not joined or not detached + terminate(); + } + + void thread::join() + { + int err = EINVAL; + + if (joinable()) + err = pthread_join(native_handle(), NULL); + + if (err) + { + throw_system_error(err, "thread::join failed"); + } + + _m_thr = id(); + } + + void thread::detach() + { + int err = EINVAL; + + if (joinable()) + err = pthread_detach(native_handle()); + if (err) + { + throw_system_error(err, "thread::detach failed"); + } + + _m_thr = id(); + } + + // TODO: not yet actually implemented. + // The standard states that the returned value should only be considered a hint. + unsigned thread::hardware_concurrency() noexcept + { + int __n = _RT_NPROCS; + if (__n < 0) + __n = 0; + return __n; + } +} diff --git a/components/cplusplus/cpp11/gcc/utils.cpp b/components/cplusplus/cpp11/gcc/utils.cpp new file mode 100644 index 0000000000..1ec3b70cad --- /dev/null +++ b/components/cplusplus/cpp11/gcc/utils.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-04-27 flybreak the first version. + */ + +#include "__utils.h" +#include <sys/time.h> + +tick_clock::time_point tick_clock::now() +{ + tick_clock::rep cur_tk = clock(); + tick_clock::duration cur_time(cur_tk); + + return tick_clock::time_point(cur_time); +} + +real_time_clock::time_point real_time_clock::now() noexcept +{ + timespec tp; + clock_gettime(CLOCK_REALTIME, &tp); + + return time_point(duration(std::chrono::seconds(tp.tv_sec)) + + std::chrono::nanoseconds(tp.tv_nsec)); +} |
