From a3541b2a243bdf1cc49029b696b217ce752199c7 Mon Sep 17 00:00:00 2001 From: liukangcc Date: Fri, 3 Sep 2021 11:38:48 +0800 Subject: [PATCH 1/3] [update] support armclang and c++11. --- components/cplusplus/Kconfig | 12 + components/cplusplus/SConscript | 13 +- components/cplusplus/cpp11/README.md | 49 ++ components/cplusplus/cpp11/README_ZH.md | 48 ++ components/cplusplus/cpp11/armclang/clock.cpp | 29 + .../cplusplus/cpp11/armclang/condvar.cpp | 178 ++++++ .../cpp11/armclang/miscellaneous.cpp | 22 + components/cplusplus/cpp11/armclang/mutex.cpp | 108 ++++ .../cplusplus/cpp11/armclang/thread.cpp | 109 ++++ components/cplusplus/cpp11/armclang/tpl.h | 56 ++ components/cplusplus/cpp11/atomic_8.c | 88 +++ components/cplusplus/cpp11/emutls.c | 216 ++++++++ .../figures/Snipaste_2021-09-02_16-00-09.png | Bin 0 -> 24214 bytes components/cplusplus/cpp11/gcc/__utils.h | 59 ++ .../cplusplus/cpp11/gcc/condition_variable | 222 ++++++++ .../cpp11/gcc/condition_variable.cpp | 34 ++ components/cplusplus/cpp11/gcc/future | 336 ++++++++++++ components/cplusplus/cpp11/gcc/mutex | 512 ++++++++++++++++++ components/cplusplus/cpp11/gcc/mutex.cpp | 52 ++ components/cplusplus/cpp11/gcc/thread | 239 ++++++++ components/cplusplus/cpp11/gcc/thread.cpp | 94 ++++ components/cplusplus/cpp11/gcc/utils.cpp | 29 + .../cplusplus/cpp11/thread_local_impl.cpp | 34 ++ .../compilers/common/none-gcc/sys/types.h | 1 + components/libc/compilers/common/sys/time.h | 7 +- components/libc/pthreads/pthread.c | 55 +- components/libc/pthreads/pthread.h | 5 + 27 files changed, 2595 insertions(+), 12 deletions(-) create mode 100644 components/cplusplus/cpp11/README.md create mode 100644 components/cplusplus/cpp11/README_ZH.md create mode 100644 components/cplusplus/cpp11/armclang/clock.cpp create mode 100644 components/cplusplus/cpp11/armclang/condvar.cpp create mode 100644 components/cplusplus/cpp11/armclang/miscellaneous.cpp create mode 100644 components/cplusplus/cpp11/armclang/mutex.cpp create mode 100644 components/cplusplus/cpp11/armclang/thread.cpp create mode 100644 components/cplusplus/cpp11/armclang/tpl.h create mode 100644 components/cplusplus/cpp11/atomic_8.c create mode 100644 components/cplusplus/cpp11/emutls.c create mode 100644 components/cplusplus/cpp11/figures/Snipaste_2021-09-02_16-00-09.png create mode 100644 components/cplusplus/cpp11/gcc/__utils.h create mode 100644 components/cplusplus/cpp11/gcc/condition_variable create mode 100644 components/cplusplus/cpp11/gcc/condition_variable.cpp create mode 100644 components/cplusplus/cpp11/gcc/future create mode 100644 components/cplusplus/cpp11/gcc/mutex create mode 100644 components/cplusplus/cpp11/gcc/mutex.cpp create mode 100644 components/cplusplus/cpp11/gcc/thread create mode 100644 components/cplusplus/cpp11/gcc/thread.cpp create mode 100644 components/cplusplus/cpp11/gcc/utils.cpp create mode 100644 components/cplusplus/cpp11/thread_local_impl.cpp diff --git a/components/cplusplus/Kconfig b/components/cplusplus/Kconfig index f2b817823d..dfd6786004 100644 --- a/components/cplusplus/Kconfig +++ b/components/cplusplus/Kconfig @@ -4,4 +4,16 @@ config RT_USING_CPLUSPLUS bool "Support C++ features" default n +if RT_USING_CPLUSPLUS + + config RT_USING_CPLUSPLUS11 + bool "Enable c++11 feature support" + default n + select RT_USING_LIBC + select RT_USING_DFS + select RT_USING_PTHREADS + select RT_USING_RTC + +endif + endmenu diff --git a/components/cplusplus/SConscript b/components/cplusplus/SConscript index 4f7fab9b9d..325a27f65f 100644 --- a/components/cplusplus/SConscript +++ b/components/cplusplus/SConscript @@ -1,12 +1,23 @@ # RT-Thread building script for component from building import * +Import('rtconfig') cwd = GetCurrentDir() src = Glob('*.cpp') + Glob('*.c') +if GetDepend('RT_USING_CPLUSPLUS11'): + src += Glob('cpp11/*.cpp') + Glob('cpp11/*.c') + CPPPATH = [cwd] +if rtconfig.PLATFORM == 'armclang' and GetDepend('RT_USING_CPLUSPLUS11'): + src += Glob('cpp11/armclang/*.cpp') + Glob('cpp11/armclang/*.c') + CPPPATH += [cwd + '/cpp11/armclang'] +elif rtconfig.PLATFORM == 'gcc' and GetDepend('RT_USING_CPLUSPLUS11'): + src += Glob('cpp11/gcc/*.cpp') + Glob('cpp11/gcc/*.c') + CPPPATH += [cwd + '/cpp11/gcc'] + group = DefineGroup('CPlusPlus', src, depend = ['RT_USING_CPLUSPLUS'], CPPPATH = CPPPATH) -Return('group') +Return('group') \ No newline at end of file diff --git a/components/cplusplus/cpp11/README.md b/components/cplusplus/cpp11/README.md new file mode 100644 index 0000000000..a292051608 --- /dev/null +++ b/components/cplusplus/cpp11/README.md @@ -0,0 +1,49 @@ +# C++ 11 support for RT-Thread + +## Features + +Here are some features about rt-thread c++11 threading futures. + +- Atomic. +- Conditional variables. +- Clocks. +- Future. +- Mutexes. +- Threads. +- TLS. + +## How To Use + +Note that using C++ 11 in rt-thread requires modifying some of the files in the toolchain. Before modifying the tool, back up the tool chain. + +1. Enable c++11 support + + ![](figures/Snipaste_2021-09-02_16-00-09.png) + +2. Download toolchain GCC 10.2.1: + + ```shell + gcc version 10.2.1 20201103 (release) (GNU Arm Embedded Toolchain 10-2020-q4-major) + ``` + +3. Delete the following files: + + ```shell + rm -f toolchain/arm-none-eabi/include/c++/10.2.1/thread + rm -f toolchain/arm-none-eabi/include/c++/10.2.1/mutex + rm -f toolchain/arm-none-eabi/include/c++/10.2.1/condition_variable + rm -f toolchain/arm-none-eabi/include/c++/10.2.1/future + rm -f toolchain/arm-none-eabi/include/pthread.h + ``` + +4. Clear the contents of the following files and keep them to prevent compilation failures: + + ```shell + toolchain/arm-none-eabi/include/sys/_pthreadtypes.h + ``` + +5. Update `rtconfig.py` file. add compilation parameters: + + ```shell + CXXFLAGS = CFLAGS + ' -std=c++11 -fabi-version=0 -MMD -MP -MF' + ``` diff --git a/components/cplusplus/cpp11/README_ZH.md b/components/cplusplus/cpp11/README_ZH.md new file mode 100644 index 0000000000..e46bcb90c4 --- /dev/null +++ b/components/cplusplus/cpp11/README_ZH.md @@ -0,0 +1,48 @@ +# cpp 11 support for rt-thread + +## 特性 + +下面是 RT-Thread 支持的 C++ 11 线程特性。 + +- Atomic. +- Conditional variables. +- Clocks. +- Future. +- Mutexes. +- Threads. +- TLS. + +## 如何使用 + +请注意,在 RT-Thread 中使用 C++ 11,需要修改工具链中的部分文件。请在修改之前,备份好工具链。 + +1. 使能 c++11 + ![](figures/Snipaste_2021-09-02_16-00-09.png) + +2. 下载 GCC 工具链 + + ```shell + gcc version 10.2.1 20201103 (release) (GNU Arm Embedded Toolchain 10-2020-q4-major) + ``` + +3. 删除下面的文件 + + ```shell + rm -f toolchain/arm-none-eabi/include/c++/10.2.1/thread + rm -f toolchain/arm-none-eabi/include/c++/10.2.1/mutex + rm -f toolchain/arm-none-eabi/include/c++/10.2.1/condition_variable + rm -f toolchain/arm-none-eabi/include/c++/10.2.1/future + rm -f toolchain/arm-none-eabi/include/pthread.h + ``` + +4. 请清除下面文件的内容,保留文件避免编译失败 + + ```shell + toolchain/arm-none-eabi/include/sys/_pthreadtypes.h + ``` + +5. 更新 `rtconfig.py` 文件,添加 c++ 编译参数: + + ```shell + CXXFLAGS = CFLAGS + ' -std=c++11 -fabi-version=0 -MMD -MP -MF' + ``` diff --git a/components/cplusplus/cpp11/armclang/clock.cpp b/components/cplusplus/cpp11/armclang/clock.cpp new file mode 100644 index 0000000000..137af393b0 --- /dev/null +++ b/components/cplusplus/cpp11/armclang/clock.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 +#include +#include + +extern "C" int __ARM_TPL_clock_realtime(__ARM_TPL_timespec_t* __ts) +{ + unsigned int t = std::time(nullptr); + __ts->tv_sec = t; + __ts->tv_nsec = 0; + return 0; +} + +extern "C" int __ARM_TPL_clock_monotonic(__ARM_TPL_timespec_t* __ts) +{ + unsigned int t = rt_tick_get(); + __ts->tv_sec = t / RT_TICK_PER_SECOND; + __ts->tv_nsec = (t %RT_TICK_PER_SECOND) * NANOSECOND_PER_TICK ; + return 0; +} diff --git a/components/cplusplus/cpp11/armclang/condvar.cpp b/components/cplusplus/cpp11/armclang/condvar.cpp new file mode 100644 index 0000000000..7943ccee60 --- /dev/null +++ b/components/cplusplus/cpp11/armclang/condvar.cpp @@ -0,0 +1,178 @@ +/* + * 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 +#include "tpl.h" +#include +#include +#include + +arm_tpl_cv::arm_tpl_cv() +{ + s = rt_sem_create("semxs", 0, RT_IPC_FLAG_PRIO); + if (s == nullptr) + RT_ASSERT(0); + h = rt_sem_create("semxh", 0, RT_IPC_FLAG_PRIO); + if (h == nullptr) + { + rt_sem_delete(s); + RT_ASSERT(0); + } + x = rt_mutex_create("mutx", RT_IPC_FLAG_PRIO); + if (x == nullptr) + { + rt_sem_delete(s); + rt_sem_delete(h); + RT_ASSERT(0); + } +} + +arm_tpl_cv::~arm_tpl_cv() +{ + rt_mutex_delete(x); + rt_sem_delete(h); + rt_sem_delete(s); +} + +void arm_tpl_cv::wait(rt_mutex_t lock, bool recursive) +{ + while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0); + rt_sem_release(s); + rt_mutex_release(x); + if (recursive) + rt_mutex_release(lock); + else + rt_mutex_release(lock); + while (rt_sem_take(h, ARM_TPL_MAX_DELAY) != 0); + if (recursive) + while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0); + else + while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0); +} + +int arm_tpl_cv::timedwait(rt_mutex_t lock, bool recursive, unsigned int timeout_ms) +{ + int result = 0; + while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0); + rt_sem_release(s); + rt_mutex_release(x); + if (recursive) + rt_mutex_release(lock); + else + rt_mutex_release(lock); + if (rt_sem_take(h, rt_tick_from_millisecond(timeout_ms)) != 0) + { + while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0); + if (rt_sem_take(h, 0) != 0) + { + if (rt_sem_take(s, 0) != 0) + result = -1; + else + result = 1; + } + rt_mutex_release(x); + } + if (recursive) + while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0); + else + while (rt_mutex_take(lock, ARM_TPL_MAX_DELAY) != 0); + return result; +} + +void arm_tpl_cv::signal() +{ + while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0); + if (rt_sem_take(s, 0) == 0) + rt_sem_release(h); + rt_mutex_release(x); +} + +void arm_tpl_cv::broadcast() +{ + while (rt_mutex_take(x, ARM_TPL_MAX_DELAY) != 0); + auto count = s->value; + for (auto i = 0; i < count; i++) + { + while (rt_sem_take(s, ARM_TPL_MAX_DELAY) != 0); + rt_sem_release(h); + } + rt_mutex_release(x); +} + +static int check_create(volatile __ARM_TPL_condvar_t *__vcv) +{ + if (__vcv->data == 0) + { + uintptr_t cv_new; + cv_new = reinterpret_cast(new arm_tpl_cv()); + if (cv_new == 0) + { + return -1; + } + uintptr_t cv_null = 0; + if (!atomic_compare_exchange_strong(&__vcv->data, &cv_null, cv_new)) + delete reinterpret_cast(cv_new); + } + return 0; +} + +extern "C" int __ARM_TPL_condvar_wait(__ARM_TPL_condvar_t *__cv, __ARM_TPL_mutex_t *__m) +{ + volatile __ARM_TPL_condvar_t *__vcv = __cv; + if (check_create(__vcv) != 0) + return -1; + struct arm_tpl_mutex_struct *tmutex = (struct arm_tpl_mutex_struct *)(__m->data); + ((arm_tpl_cv *) __vcv->data)->wait(tmutex->mutex, tmutex->type == RECURSIVE); + return 0; +} + +extern "C" int __ARM_TPL_condvar_timedwait(__ARM_TPL_condvar_t *__cv, + __ARM_TPL_mutex_t *__m, + __ARM_TPL_timespec_t *__ts) +{ + volatile __ARM_TPL_condvar_t *__vcv = __cv; + if (check_create(__vcv) != 0) + return -1; + __ARM_TPL_timespec_t now; + if (__ARM_TPL_clock_realtime(&now) != 0) + return -1; + struct arm_tpl_mutex_struct *tmutex = (struct arm_tpl_mutex_struct *)(__m->data); + unsigned int timeout_ms = (__ts->tv_sec - now.tv_sec) * 1000 + (__ts->tv_nsec - now.tv_nsec) / 1000000; + if (((arm_tpl_cv *) __vcv->data)->timedwait(tmutex->mutex, tmutex->type == RECURSIVE, timeout_ms) < 0) + return -1; + return 0; +} + +extern "C" int __ARM_TPL_condvar_signal(__ARM_TPL_condvar_t *__cv) +{ + volatile __ARM_TPL_condvar_t *__vcv = __cv; + if (__vcv->data != 0) + ((arm_tpl_cv *) __vcv->data)->signal(); + return 0; +} + +extern "C" int __ARM_TPL_condvar_broadcast(__ARM_TPL_condvar_t *__cv) +{ + volatile __ARM_TPL_condvar_t *__vcv = __cv; + if (__vcv->data != 0) + ((arm_tpl_cv *) __vcv->data)->broadcast(); + return 0; +} + +extern "C" int __ARM_TPL_condvar_destroy(__ARM_TPL_condvar_t *__cv) +{ + volatile __ARM_TPL_condvar_t *__vcv = __cv; + if (__vcv->data != 0) + { + delete (arm_tpl_cv *) __vcv->data; + __vcv->data = 0; + } + return 0; +} diff --git a/components/cplusplus/cpp11/armclang/miscellaneous.cpp b/components/cplusplus/cpp11/armclang/miscellaneous.cpp new file mode 100644 index 0000000000..a084eda8c8 --- /dev/null +++ b/components/cplusplus/cpp11/armclang/miscellaneous.cpp @@ -0,0 +1,22 @@ +/* + * 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 + +extern "C" int __ARM_TPL_execute_once(__ARM_TPL_exec_once_flag *__flag, + void (*__init_routine)(void)) +{ + if (*__flag == 0) + { + __init_routine(); + *__flag = 1; + } + return 0; +} diff --git a/components/cplusplus/cpp11/armclang/mutex.cpp b/components/cplusplus/cpp11/armclang/mutex.cpp new file mode 100644 index 0000000000..44a70efcf7 --- /dev/null +++ b/components/cplusplus/cpp11/armclang/mutex.cpp @@ -0,0 +1,108 @@ +/* + * 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 +#include +#include +#include "tpl.h" + +static int check_create(volatile __ARM_TPL_mutex_t *__vm, bool recursive = false) +{ + if (__vm->data == 0) + { + uintptr_t mut_null = 0; + arm_tpl_mutex_struct *mutex_p = (arm_tpl_mutex_struct *)rt_malloc(sizeof(arm_tpl_mutex_struct)); + if (mutex_p == nullptr) return -1; + + if (recursive) + mutex_p->mutex = rt_mutex_create("mutexx", RT_IPC_FLAG_PRIO); + else + mutex_p->mutex = rt_mutex_create("mutexx", RT_IPC_FLAG_PRIO); + + if (mutex_p->mutex == nullptr) + { + rt_free(mutex_p); + return -1; + } + mutex_p->type = recursive ? RECURSIVE : NORMAL; + uintptr_t mut_new = reinterpret_cast(mutex_p); + if (!atomic_compare_exchange_strong(&__vm->data, &mut_null, mut_new)) + { + rt_mutex_delete(mutex_p->mutex); + rt_free(mutex_p); + } + } + return 0; +} + +static int mutexLock(arm_tpl_mutex_struct *mutex_p, rt_tick_t timeOut) +{ + if (mutex_p->type == RECURSIVE) + { + if (rt_mutex_take(mutex_p->mutex, timeOut) == 0) + return 0; + } + else + { + if (rt_mutex_take(mutex_p->mutex, timeOut) == 0) + return 0; + } + return -1; +} + +static int mutexUnlock(arm_tpl_mutex_struct *mutex_p) +{ + if (mutex_p->type == RECURSIVE) + rt_mutex_release(mutex_p->mutex); + else + rt_mutex_release(mutex_p->mutex); + return 0; +} + +extern "C" int __ARM_TPL_recursive_mutex_init(__ARM_TPL_mutex_t *__m) +{ + volatile __ARM_TPL_mutex_t *__vm = __m; + return check_create(__vm, true); +} + +extern "C" int __ARM_TPL_mutex_lock(__ARM_TPL_mutex_t *__m) +{ + volatile __ARM_TPL_mutex_t *__vm = __m; + if (check_create(__vm)) + return -1; + while (mutexLock((arm_tpl_mutex_struct *)(__vm->data), ARM_TPL_MAX_DELAY) != 0); + return 0; +} + +extern "C" int __ARM_TPL_mutex_trylock(__ARM_TPL_mutex_t *__m) +{ + volatile __ARM_TPL_mutex_t *__vm = __m; + if (check_create(__vm)) + return -1; + return mutexLock((arm_tpl_mutex_struct *)(__vm->data), 0); +} + +extern "C" int __ARM_TPL_mutex_unlock(__ARM_TPL_mutex_t *__m) +{ + volatile __ARM_TPL_mutex_t *__vm = __m; + return mutexUnlock((arm_tpl_mutex_struct *)(__vm->data)); +} + +extern "C" int __ARM_TPL_mutex_destroy(__ARM_TPL_mutex_t *__m) +{ + volatile __ARM_TPL_mutex_t *__vm = __m; + if (__vm->data != 0) + { + rt_mutex_delete(((arm_tpl_mutex_struct *)(__vm->data))->mutex); + rt_free((void *)(__vm->data)); + __vm->data = 0; + } + return 0; +} diff --git a/components/cplusplus/cpp11/armclang/thread.cpp b/components/cplusplus/cpp11/armclang/thread.cpp new file mode 100644 index 0000000000..f7f0cb4077 --- /dev/null +++ b/components/cplusplus/cpp11/armclang/thread.cpp @@ -0,0 +1,109 @@ +/* + * 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 +#include "tpl.h" +#include +#include + +extern "C" int __ARM_TPL_thread_create(__ARM_TPL_thread_t *__t, + void *(*__func)(void *), + void *__arg) +{ + int ret = 0; + /* TODO memory leek */ + pthread_t *pid = (pthread_t *)rt_malloc(sizeof(pthread_t)); + if (pid == nullptr) + return -1; + ret = pthread_create(pid, RT_NULL, __func, __arg); + if (ret == 0) + { + __t->data = (std::uintptr_t)pid; + return 0; + } + return -1; +} + +extern "C" int __ARM_TPL_thread_id_compare(__ARM_TPL_thread_id __tid1, + __ARM_TPL_thread_id __tid2) +{ + if (__tid1 > __tid2) + return 1; + else if (__tid1 < __tid2) + return -1; + else + return 0; +} + +extern "C" __ARM_TPL_thread_id __ARM_TPL_thread_get_current_id() +{ + return (__ARM_TPL_thread_id)pthread_self(); +} + +extern "C" __ARM_TPL_thread_id __ARM_TPL_thread_get_id( + const __ARM_TPL_thread_t *__t) +{ + return (__ARM_TPL_thread_id)((*(pthread_t *)__t->data)); +} + +extern "C" int __ARM_TPL_thread_join(__ARM_TPL_thread_t *__t) +{ + pthread_join((*(pthread_t *)__t->data), RT_NULL); + return 0; +} + +extern "C" int __ARM_TPL_thread_detach(__ARM_TPL_thread_t *__t) +{ + pthread_detach((*(pthread_t *)__t->data)); + return 0; +} + +extern "C" void __ARM_TPL_thread_yield() +{ + rt_thread_yield(); +} + +extern "C" int __ARM_TPL_thread_nanosleep(const __ARM_TPL_timespec_t *__req, + __ARM_TPL_timespec_t *__rem) +{ + return nanosleep(__req, rem); +} + +extern "C" unsigned __ARM_TPL_thread_hw_concurrency() +{ + return 1; +} + +extern "C" int __ARM_TPL_tls_create(__ARM_TPL_tls_key *__key, + void (*__at_exit)(void *)) +{ + pthread_key_t key; + + if (pthread_key_create(&key, __at_exit) == 0) + { + *__key = key; + return 0; + } + return -1; +} + +extern "C" void *__ARM_TPL_tls_get(__ARM_TPL_tls_key __key) +{ + return pthread_getspecific(__key); +} + +extern "C" int __ARM_TPL_tls_set(__ARM_TPL_tls_key __key, void *__p) +{ + if (pthread_setspecific(__key, (void*)__p) != 0) + { + return -1; + } + return 0; +} diff --git a/components/cplusplus/cpp11/armclang/tpl.h b/components/cplusplus/cpp11/armclang/tpl.h new file mode 100644 index 0000000000..70c9503cec --- /dev/null +++ b/components/cplusplus/cpp11/armclang/tpl.h @@ -0,0 +1,56 @@ +/* + * 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 +#ifndef __cplusplus +void ARMTPLInit(); +#else +#include + +#define ARM_TPL_MAX_DELAY 1000 +#define ARM_TPL_THREAD_STACK_SIZE 4096 + +enum arm_tpl_mutex_type +{ + NORMAL, + RECURSIVE, +}; + +struct arm_tpl_mutex_struct +{ + rt_mutex_t mutex; + arm_tpl_mutex_type type; +}; + +struct arm_tpl_thread_struct +{ + rt_thread_t task; + void *(*func)(void *); + void *arg; + rt_sem_t join_sem; + rt_sem_t detach_sem; +}; + +class arm_tpl_cv +{ +public: + arm_tpl_cv(); + ~arm_tpl_cv(); + void wait(rt_mutex_t lock, bool recursive); + int timedwait(rt_mutex_t lock, bool recursive, unsigned int timeout_ms); + void signal(); + void broadcast(); +private: + rt_sem_t s; + rt_sem_t h; + rt_mutex_t x; +}; + +#endif diff --git a/components/cplusplus/cpp11/atomic_8.c b/components/cplusplus/cpp11/atomic_8.c new file mode 100644 index 0000000000..64d3311b4a --- /dev/null +++ b/components/cplusplus/cpp11/atomic_8.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-04-27 peterfan Add copyright header. + */ + +#include +#include +#include + +/* +* override gcc builtin atomic function for std::atomic, std::atomic +* @see https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html +*/ +uint64_t __atomic_load_8(volatile void *ptr, int memorder) +{ + volatile uint64_t *val_ptr = (volatile uint64_t *)ptr; + register rt_base_t level; + uint64_t tmp; + level = rt_hw_interrupt_disable(); + tmp = *val_ptr; + rt_hw_interrupt_enable(level); + return tmp; +} + +void __atomic_store_8(volatile void *ptr, uint64_t val, int memorder) +{ + volatile uint64_t *val_ptr = (volatile uint64_t *)ptr; + register rt_base_t level; + level = rt_hw_interrupt_disable(); + *val_ptr = val; + rt_hw_interrupt_enable(level); +} + +uint64_t __atomic_exchange_8(volatile void *ptr, uint64_t val, int memorder) +{ + volatile uint64_t *val_ptr = (volatile uint64_t *)ptr; + register rt_base_t level; + uint64_t tmp; + level = rt_hw_interrupt_disable(); + tmp = *val_ptr; + *val_ptr = val; + rt_hw_interrupt_enable(level); + return tmp; +} + +bool __atomic_compare_exchange_8(volatile void *ptr, volatile void *expected, uint64_t desired, bool weak, int success_memorder, int failure_memorder) +{ + volatile uint64_t *val_ptr = (volatile uint64_t *)ptr; + volatile uint64_t *expected_ptr = (volatile uint64_t *)expected; + register rt_base_t level; + bool exchanged; + level = rt_hw_interrupt_disable(); + if (*val_ptr == *expected_ptr) + { + *val_ptr = desired; + exchanged = true; + } + else + { + *expected_ptr = *val_ptr; + exchanged = false; + } + rt_hw_interrupt_enable(level); + return exchanged; +} + +#define __atomic_fetch_op_8(OPNAME, OP) \ +uint64_t __atomic_fetch_##OPNAME##_8(volatile void *ptr, uint64_t val, int memorder) {\ + volatile uint64_t* val_ptr = (volatile uint64_t*)ptr;\ + register rt_base_t level;\ + uint64_t tmp;\ + level = rt_hw_interrupt_disable();\ + tmp = *val_ptr;\ + *val_ptr OP##= val;\ + rt_hw_interrupt_enable(level);\ + return tmp;\ +} + +__atomic_fetch_op_8(add, +) +__atomic_fetch_op_8(sub, -) +__atomic_fetch_op_8( and, &) +__atomic_fetch_op_8( or, |) +__atomic_fetch_op_8(xor, ^) diff --git a/components/cplusplus/cpp11/emutls.c b/components/cplusplus/cpp11/emutls.c new file mode 100644 index 0000000000..576888f16f --- /dev/null +++ b/components/cplusplus/cpp11/emutls.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-04-27 peterfan Add copyright header. + */ + +/* ===---------- emutls.c - Implements __emutls_get_address ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + */ + +#include +#include +#include +#include + +#define COMPILE_TIME_ASSERT(x) + +extern int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)); +extern int pthread_key_delete(pthread_key_t key); +extern void *pthread_getspecific(pthread_key_t key); +extern int pthread_setspecific(pthread_key_t key, const void *value); + +/* Default is not to use posix_memalign, so systems like Android + * can use thread local data without heavier POSIX memory allocators. + */ +#ifndef EMUTLS_USE_POSIX_MEMALIGN +#define EMUTLS_USE_POSIX_MEMALIGN 0 +#endif + +/* For every TLS variable xyz, + * there is one __emutls_control variable named __emutls_v.xyz. + * If xyz has non-zero initial value, __emutls_v.xyz's "value" + * will point to __emutls_t.xyz, which has the initial value. + */ +typedef struct __emutls_control +{ + size_t size; /* size of the object in bytes */ + size_t align; /* alignment of the object in bytes */ + union + { + uintptr_t index; /* data[index-1] is the object address */ + void *address; /* object address, when in single thread env */ + } object; + void *value; /* null or non-zero initial value for the object */ +} __emutls_control; + +static __inline void *emutls_memalign_alloc(size_t align, size_t size) +{ + void *base; +#if EMUTLS_USE_POSIX_MEMALIGN + if (posix_memalign(&base, align, size) != 0) + abort(); +#else +#define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void *)) + char *object; + if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL) + abort(); + base = (void *)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES)) & ~(uintptr_t)(align - 1)); + + ((void **)base)[-1] = object; +#endif + return base; +} + +static __inline void emutls_memalign_free(void *base) +{ +#if EMUTLS_USE_POSIX_MEMALIGN + free(base); +#else + /* The mallocated address is in ((void**)base)[-1] */ + free(((void **)base)[-1]); +#endif +} + +/* Emulated TLS objects are always allocated at run-time. */ +static __inline void *emutls_allocate_object(__emutls_control *control) +{ + /* Use standard C types, check with gcc's emutls.o. */ + typedef unsigned int gcc_word __attribute__((mode(word))); + typedef unsigned int gcc_pointer __attribute__((mode(pointer))); + COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word)); + COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer)); + COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void *)); + + size_t size = control->size; + size_t align = control->align; + if (align < sizeof(void *)) + align = sizeof(void *); + /* Make sure that align is power of 2. */ + if ((align & (align - 1)) != 0) + abort(); + + void *base = emutls_memalign_alloc(align, size); + if (control->value) + memcpy(base, control->value, size); + else + memset(base, 0, size); + return base; +} + +static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER; + +static size_t emutls_num_object = 0; /* number of allocated TLS objects */ + +typedef struct emutls_address_array +{ + uintptr_t size; /* number of elements in the 'data' array */ + void *data[]; +} emutls_address_array; + +static pthread_key_t emutls_pthread_key; + +static void emutls_key_destructor(void *ptr) +{ + emutls_address_array *array = (emutls_address_array *)ptr; + uintptr_t i; + for (i = 0; i < array->size; ++i) + { + if (array->data[i]) + emutls_memalign_free(array->data[i]); + } + free(ptr); +} + +static void emutls_init(void) +{ + if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0) + abort(); +} + +/* Returns control->object.index; set index if not allocated yet. */ +static __inline uintptr_t emutls_get_index(__emutls_control *control) +{ + uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE); + if (!index) + { + static pthread_once_t once = PTHREAD_ONCE_INIT; + pthread_once(&once, emutls_init); + pthread_mutex_lock(&emutls_mutex); + index = control->object.index; + if (!index) + { + index = ++emutls_num_object; + __atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE); + } + pthread_mutex_unlock(&emutls_mutex); + } + return index; +} + +/* Updates newly allocated thread local emutls_address_array. */ +static __inline void emutls_check_array_set_size(emutls_address_array *array, + uintptr_t size) +{ + if (array == NULL) + abort(); + array->size = size; + pthread_setspecific(emutls_pthread_key, (void *)array); +} + +/* Returns the new 'data' array size, number of elements, + * which must be no smaller than the given index. + */ +static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) +{ + /* Need to allocate emutls_address_array with one extra slot + * to store the data array size. + * Round up the emutls_address_array size to multiple of 16. + */ + return ((index + 1 + 15) & ~((uintptr_t)15)) - 1; +} + +/* Returns the thread local emutls_address_array. + * Extends its size if necessary to hold address at index. + */ +static __inline emutls_address_array * +emutls_get_address_array(uintptr_t index) +{ + emutls_address_array *array = pthread_getspecific(emutls_pthread_key); + if (array == NULL) + { + uintptr_t new_size = emutls_new_data_array_size(index); + array = calloc(new_size + 1, sizeof(void *)); + emutls_check_array_set_size(array, new_size); + } + else if (index > array->size) + { + uintptr_t orig_size = array->size; + uintptr_t new_size = emutls_new_data_array_size(index); + array = realloc(array, (new_size + 1) * sizeof(void *)); + if (array) + memset(array->data + orig_size, 0, + (new_size - orig_size) * sizeof(void *)); + emutls_check_array_set_size(array, new_size); + } + return array; +} + +void *__emutls_get_address(void *control) +{ + uintptr_t index = emutls_get_index((__emutls_control *)control); + emutls_address_array *array = emutls_get_address_array(index); + if (array->data[index - 1] == NULL) + array->data[index - 1] = emutls_allocate_object((__emutls_control *)control); + return array->data[index - 1]; +} diff --git a/components/cplusplus/cpp11/figures/Snipaste_2021-09-02_16-00-09.png b/components/cplusplus/cpp11/figures/Snipaste_2021-09-02_16-00-09.png new file mode 100644 index 0000000000000000000000000000000000000000..0e2381b5d9084eeffeb29fba0a60da45641ad60e GIT binary patch literal 24214 zcmbTeWmFv7)-~KDH~~U%3l`iRf&>i&3GN=;g3~yh;0_6{f#BA`wb5XK;O-FI8h81s zbMCqKeed(Uf4&}r!RVr@cGcQ@tu@zNa}%!oUIr7L1RVqdVZM`Im?^*OnkmYL#i?5Fa0WTP6IOK_&*MLubY@AvC;>Mg zD9#WlrfZTIn6?S>R`k@U{*J}{oYf<;yYtSOVUng%F%9p>XJtPkCF@E-1WAc8ZEQBw zTznpv$CP{C^vv1C{==ce&2yh4kGTE)!ImwN>{L(7O>XWdqRq%s@Xxx_PT8!>SWimJ0{?#1H0sp-^(y|7hVDxIeuGHf9YS91?v&wGPgjVNG|VA;Py7A)PnH~3kYS#;NJylp|9 z?XAC`iUpm2sjGYu>M{9qaBPo_bk6@S7)N%)x&LP>xeS|vd0O}~NS)R%2zW+3(F^IA zh4%i_c7-k<=X^y(-1!KA}?doZIW{;der|kh!Hl0@9$Q9qBYnvJ04hh;JmBH zqr^n%<^grzU&nxvEc7R{LMF&HZv?-pl|53z879vEiQ6X z*+O4q-L3@BkYSIjovfR|s=1%s>d`2;tV_-puD0`fg&e?A`0lac%}&<1!uERzm{7=YBezik zf)Qpt>TT>BU*to#dOn)RGKk?>H1Fe2p$LgK+07D9Zl?<<_!G854D#1F$$Y7InG6YD z-9=JGRHPA-%j6dYUJ0hT(aLBme z;yZ%z)F);R*9im2vkYOQ2KUWGu_AQFl{+w^B`oBE0!9?So5!JOZuk(MW}1TS5lO$S zGhE%V7=f%1sC|G0t|-$b5ahl)AU+(RoT? zyZbp8LDnTZLo!jy8h6X?Ieht9Lk(bO&FJ|{vlxGE5pEf}Yor9rn~4hh5|k1QclQZ` z1_+0NSw=79yGJAP+}mLkR!hgt0d>_ABexz-A%7PnPxje^1J9H9yCn* zt9^^Cba-!2D6}W8*4_GD$XR&Ub;##L?sx`FvG&x+!oQGCE#6k?Bdmu%0kybXP>)%# zV|%}F8bk)XTsk?ax)1PQQ&`y`%ek;myUT-Wdn(v)yOUfxvRZALG?(Q?-<$Fg};dGlSYG4x-*B;RF|Qdj?ML?0S$A-$Ef2L*$YK>%iaJ>fi}T zweq&}Aysc7a0pxvg-*0kMtORY1YACJR~PE}`y!xCfQH=nv!UkYcs(Xrq6$r~5oMR9Csv_$k~cXWnIM zh3Z%GM3ajYa`VCCYebTnNMzJISj)-)VFBsihvHwc#fQT~?guKj*Sf$m11x|fZw8OX z)Wk`B!1PN=ak2b;irL!Hlid`@Hr|7pTeptm?DGu%Ym%^?zDH>)@#QN;;7mr!pR`r` zil%-LT-@a4?`0hJW7ESWZQJ7JW#G^2$Mq+Kl%d*7uc+DDOmwK0{JgSTA!;!$UY48w z)+SThHA%0bz>DCxp27hroc=!ukcgACj_?L#6M?-v^JyvC`;+P*go zkwO57!j2uJ^x2}$9ppW8`LvE&>%iR`j2|nfJX7%&tar>A&C-FQar!9OW3Od zxM5@@df(?Bg*9_gb*aNr{5QyLEm2%o6GJk+E}vAWvAN@C{K-}XEWg^tQYIf8BMSqV zX;P5_xGmqPXB#u9u&1o!mw4h(r~5TTv#y=>DF0w(iZPKbXix=$O+otiEUTR3l05+O z01GD}TTH3u`Tskdqa2s~Z{eIO5v;|+V7PN|WXz(_d^ML%z1v3xB=AvSaw%Rri|-+J z4ZnR3%YcT}%noR@aXX&)tm9%;R~F~<$JEp@fI3_lRtCGr+dp}7)7aXXK;#segTunC zn!;D-&lkw4waR&)(T&`44Y}3i{Mh%60tsI}G%I-%dL8nT%{^X>%prmDZ1#iix$7HH zGGQORy^AM8c@Y6ySAsPylDuF>!ro2i(}WAS`+uj7Eec6(jJSr@$`4@LqncguDstgTcIiSV2~>P#Q^S#9$*JdbND z>Iw0J$7j?v&4uCquVVAuqP$TWM#RAKy458eFs_wu_(rKDJf??ze*RA=cdr3*0yXvL z@GE!dadK9aG#Nb7NvWB%oM%}nMv$}qIp0j18W)}d`oBxT0ViyXHB7jPG?2lNuaPohke)kg09^z36qT8bTz6TMep*X%3JKWsi0mt?zvD5$lzuB zd#)9G9y-XiJ#ZpU^rj|8pl+@_U z2lWo>WEX5P;#VJ7ykFj$4bJ!zJ}J?Fz%QRx@t>yUe-dyt;(|-y(aOzrOc`_!{smfC zlwdiv6wpE^X13fnDz0Te*+DyX>0GQgtnzZ2TmdQfnMnev4 zQ!`pFklCQ4SDOH~k$%9kReE?7`y44ZQVTVfWS=tjQ_v3)ng-5&wZnxi-1x&guoUta z-nT9$G8oiyB5Nbf?dxMxzGKtAX_}f3LuxO1keUszJ(3?`7%hdV-JuI2)C)AkooJVX85XTU$sODcZLs^}mCz?n>8W7rGj((cGb2$2LW8r=p9dAP^mY#^dvR~?5{g>;B@f!_&@hG)bPdg+Kk9~dZTPM?gI?GbYJ73# zeW{h z>fh0P%-9Zi`bO0qW{D5^Bgf(Pq9r$JF6k=`G%_%O&sg&&S5bWOe^oaXIH|+LWWOLX z#W(Mjz0)oledYTLSl;%|A2V%NceFwr6qNk-Q~Qd!HbDSCBx#xB9M;sfT7~B zc4BH~>^$a`s$FP5ZQH)1;66b`RbGMst@C3=g@TM{N5|rQu~!wJiFx8wgO~1W`DiZ` z36&S?l)58R<7+2(^GOgH^>5_e!Zm7miaFA5Z6kgh-fF>Yq)!yNb@Jgw;uPBZ*6sl14BmPSu6#i;UA;=M9Ko-<#kZW~})J(+r* zq-E?SYbFI{^L)g!naGxW>5Ar|w0R!8V$9RDfDcD$TKPAcI@*)Y4P@@}X7_;_bqQh9 z&fAqO@wa>tVO2N}(vHEE5Kf_|?IX$D=5+Di$B;{P+!za=Dq@*x5T?7Ez(w1tA2x~w#b%a;9aN7p2h__mJtMcd{1Hddo1 zaB9 z#DEIqM?0RgL|Fq=o!35BGa!9#O~$e9zqICF0)8EwwzXYqF#_n?oNbGaXST~vPGN*qdR|wPRDL(xt3j@d28+jjK=%@q zmCI@z|9ioU7m-~^lHKTb4%t&`CKnhU>!kSRucxSs-|1N)Hk*l4grLOQvRCV?Z;|Fr z_L2KNVw4kjUaYY=UoIJ%X*AU5pJhbP9{BlVK9$wm6v^F6ZuGj7(IDYz+$9&{i|FjO z_7rfm!;`-x7vpn3B&}cM@WZp->$>h@^Zr6py12A)E4e(NWAFB}wXp|x3|XcQ+Uh20 zQe1f(d=V&(-}=V=bU?qB!{cqu#QS@!k_S1pKz|}ne($Z?xlhQC9Iv~ym-6MgM%M*1 zm%)AE3Zd-zKTlQjQ;LYfZd%reeb$}p&IOX@_btX#I(60=)P9BhM8*(%jX9OBb?6xE zf~vI$tR}qL%Bm=wOQp#=RvBAt4gq&ERAQF|JxI@rOWk>mUF0TZY?y9BjSGfhHv^f# z!hxWA7Z%;?RBTJuQnHT|Js*Ukb|_QviCgGJ`(H_fFSM0nhy~^hz^cVPjUpN1E* znxFg6#eVU*Ha*UKCeN19sg<*Poi~7!z|Js#6*CMEx`iUh+h5W5w`gtMv;Qg`mRIC? zc!8=lv4uap!pk{FqL(zO^NV0lY+rIRBRXe_q`2M{@f))P<6LLhL&*g2uIAX!mkya# z2n3ONYKqFDYB=Oy>*$odbLFC#($y4MC^8m`3LHKD*0(@3bZ#T}3Tzxdf~(FM>?!T?smENWeWYQFfXv%CH%~|<_lD)Dvm~i&BXww(L6Li| zv35kuAXOcd(!tuQ3*%K+!ywoz6v5I9htuVW!)Hmg1+I{40u8G5W8LR7o-wWBw^ zhXCJIql8?bCcG!c>O@!bW2g!FNA>UIJ%b~yPf?)IcfPs)s9(3o9{;R+MEw`&W7E{s zZ}q-C<@2s6HnI{$WfZ`5s>E`bx`Iwq*-Z^)c zD3`Irzd;+U--Y20npW-~`s` zPjY*m3$JsW+zyw^v4O?>hw0aM4$~O7`tMz}Hmqczm&haEi|rVhOc?m>CRYGQ8>;yb zxj3@^@|Apo1YeE)K*>P>l^fTOinHGNnT-hZF(j-{`Es} z=Fh(*X%2*_fjCk3=GosNmGF0FbLi>ErNPi=bmS&eX?oNoCU^Pt&^NG|%F~N^{f95$Uz)vtttwxN(kG3^e2~9If4rew$pJ81zwHSdn@SY_-2O#bdv8e)BO^9{@z5zl zY~N$jw<972O)aI!M+gZWm+eJHKLwqbOytDWbjExTB|i&&`XLmm21}BWN_ajd|JoKK zW3u?1I$d3GArH?wUqFX~p7vfyH;-wUmok5Af{yRHRv6TGAyA zlCbQO7&qXtB)d0(*!#A8DP?1AKaJTLA~sucjax>{NZY%P-&zx|#KOr! z%Em~vlm_sYkpHyDq+2@`U1&`R|;*UkOJ<5xF;O9SqASgUjv*=q{3YlF<-0=?8 z`5THd)-H_~e0i6O5`fPS={S6#w2Vo;-bPEh<|U2v0-qza11`<{(eO8E=ivBR+>yid z9spx5<=*JpJY{EqLob5|ioPY*b<#8_V;Oi##?3Hmnj9fuc0J1u08O_jMURAcZ?K6F zDPfy&Iib&84ViFku>6W@>A;t1UC}+rYJs?@eV=_A(K~%Cp>}1t=*e3e+N;CNl+fLT zwCFMfk51H71`6=r39H)?>TMe4B=q5z18{jg+LH8mQrC9hd%a!EcWRp&pR~yG8Z=@6 zClGRQw-YhJhPKin6-$tC8e_+4G|g7dfAr5;)~qcWosG;ze|(3pSxaW9`o*>qOJUA| zVXR4C%s*e~;7c#2P0Of7y`?8V+2vW_$ALJQeNDOCuTK^)L0ocm7CNLia&+v)NrTL+ z(^fK-`S)Mh=YbNY*>}W$v_NfB2>`abznh-iE&F({z$n6*M? zR}^fUuLBybiDuJV-gwNrkC5Aam%gB5lJe595-eayMnPCb@}WvA9b-p+HixMQGP@0R z+`^wamS=@l3Lw5JKxB*$Js>DGxOkU#`v_mksWlGhM7`tWg=NoG$BDm?KWQe}9U!lG z`Hkn}$fE7nqJJaJFY_JBwu&FsboG=JsX%91Y5Uzr5PfK152^h{X3i6>LLT-+R9+Np zP~bshfkJ3?cVf)p>(a)$Z`yMKw`uo1=z4zx-6d0P$>Yx>r|392=)o4_29~_oo<<#u zM%FeQUpqAtzhyB%;MXyauiC}Kq&`Wf{2NOzLrr%VL^8Avj}8lJ*By7?3fU=kd2Xcp z2B(D#mLfv9WIam}9l!S=+6QX9(vTL9wEkA^HU3^+k`_H95XnCJF9^#J zQ@NA*AC%j5=dCdA+&CcMiNJ}^z}El3?uM6}Y_TTbo1kD4ApdAqQQ^1q{P*KTr_4~}9J?g}ci#)~otATe-etzWpL zA%%>CMw2P(LvO%M%O^JHlwQb6t~aWzI@;JM_4ukQSQva>L&i4z%rfIQeTYiUT;|^0 zB*8Q6j5AVw^;K&z0MGv3?o0Ss7JkukLz))CTDwG$3Ls$55nozPr7Cn;8RU^iI0^IT8IIDkPR#Wf!M@V4Dh5nbC z%gZ-UilwXoC`~8&FDR`=3}h=NtGR0x>Iq_@*I^ z-t7tm1!{q2FMR&tJ1%hHLGiLu!FPRCitR3yk}>s5J~f?0oKPIka-z7tI{G zb%D`02rBcOv@G!GNj1!hE|#H{Ki49`QpKn82JuxcqF`iM_n4(r=JU6hk6kwbETp@?t z1O>|8q^zZ?kt3-nQQiDqbq*~8+wG{_kUAGxc59Y5aq|q)a~kF7?@5c3aeTii)Wv0S;e z7sQ~Ey&W;!k1}09QnijQ;y>zhdh+v_t2jiG&~LZCe|4Z;j#|oX6j&|0M9x%z^S0dq zC8wmJ#GJUyLjIKNI+0}qHM*PMat?fno!DAi3ixaSVKL4Y$I=8B~%+77l+`N^3qHfTTkLHd&vjRIf3B|91>eR+4sRBu8dP2{J#1yRX zE_aYQIh^z3=@=H@E{fDaFP_GIV$xI6O!21YKb$m}elfp|B(o+0eO|f3rxbs!Yektk zeCa+MX6-8+?8*9m0K?gw%F-7nV^W+Vt=h_yFT*>((DohlM@=ue4Uj@go}u%0IIcsc zjv9XEOdYJ6(~#iY$o~Ve-|a)5HJt0whJpe*nL=rrr}w=TRKrlK|4%60dL}FwdKgN) zciFP^of|R+;;F@KWIP~4FV)3LwtQVmBWnuI+|;bj|m64DbI z@U9sz5&A1ZGylvmP(cV~rR2pO+kieHB#rm#l0BbXz^g{OCw-yBvdsAe510cUSqWP&FO1#aJWp zS2sFlvj!Do*PfRYl7jO#7|%{luUCZ|#5_NZW)rS7+HDa}3u&5Y$di^WdCT4-69Zu4 zX#uh%AxPUsZ|*{OFYvwK{)TE+vTjh?CoNnLE$7B>+-I$mR@HbjrHiv-D$;r?k^-|M z1Ub4y(O5J4jRhAgYHIyC4(RaPz>t0^<7}!YSZ?xlsIUqJmobJq7(PHSCGuWCalTt=#x0$+?S8v?;oxz*&2-d9h+57i1MTZDXECtBL=bMQ_b5;9U zKu~x1X0IWa#MX}(k~tI;amVqJc3no~G#G4GQeSghF>mv;WzG3rECxeKT#~d`NH_$g zlV{-W7`Mx2c`CuvoJmOgT#7MY%RJvoxS*)a96TzxZA-dJ=JTzUTZ@@#f>7sJ43c7~ zX!5G#*p};mhtfw;?s$50T36Zmu`8|Th*^X|A%mi6CXH{gp}|QI~gM^@olfCl&g;o!yQ0 zPY>k3+u7RGYCi!|Y4l!0WNe_~SwULQsJ4RUKzhxGQi$O36Ha!o5ot-5FTKFT=cHgzZ zZ;MT^Yo}7aUE7oz!`UVjz8et_0DaQcGqRp30M(L+`PePS2SNk08^bzmf*M}Bcbg*I zC-WJF9k?L++WLtXdB2|3PR)F8te$9i@*C8&SJph`c{%e|&omPAu;z!5Hv74~;PK_D z*vMe1T*#mr8LdS4vv$}|c;Mqh*hlE&+Q6m{OqrYaPZFJzaFubkP#mQ^M48LLXp) z+6VW46i_klmk8|N9b9s4kn1&Gt1q1}saMF;SaYj^$Ma#S>70+yr)V~Ruy(puD^-XL zw_bANo{u#A6dR>+D(Y2dg3-E{m`*)g$#_@qMc#wh05b{18e zDx(mzgiF={oH@CGuY-a->3OczM2H@D8Ocy)BiNEhH~oPel@Ef5Ch5y&p$0h%eDsQ^ z1~a2yN{AoTvOwjSyvI#0bEJ1Ge(ThC{*2ubwu&aLd7W1E2I9&AwU|3w!jb$;mq>$COJ+0 zfgRdRksjdD%Xtf{CuR)jm(Ll_HdJGkna>l~_G}!AG4+vf@~5kn|7wmVAL=}aF1GkKoUBC2VZi;}+o zFtA}CdQ$lZ=X2^;5XL46>E}CW%=IvP=}t}S6lNK+&TFkN8rH(3HMa6=R9|HG1gaMW z!X`T7YJvG?_-HRmOsgOhS%G}XngP$?tS9ze;0y+Rt$>co-vL`ITZ^JDOh37?4-YS! zc^kmVYvo^=0zd6Sc-}?p?a1oGJ1EYN7+3F)Jpb;SjGLU>)3go3>)_@N-vO6TK{@?^ zLlCkMI5@>sm)B879rEnj3jW`i(x6E(RG$$P2QZQ63>j2mYF>dKrFH?Z>EL1`sGqfS zExcY(I0zOFGb>x^?DJWsqDP-%P9zUczy9M@S?CyW!*@*Vr>5C#o(}jl|N4WZ$Dh4? z8zv&A5^S0F2b0U*Ik;)*t^W<$PqmJ1FhWq?hrGl<)n^O#L{ib7%x$2OVJNLBsGbM| z*uE@A8I!8fg;pM**>Ih8^P-~%-zWc-Xf#UkcdXXAE>!N$5qrNh`IPED8-Mw0gRCK- zIdz3BP+I=}k=+7v>|0KNJghu>j*%!H@o(-`+f1uyax2mNnG*>FGON4@Ctn-EWN0r! zEK&yuQGB@E?eKyD*2jrea<|csvc7m)bv}0-dPJoa;gss-_dCI`8*tLv#22mb>6scR zrs96Hw4JbAL`XTxon2jCXif?+;h39ElS_-=oHxx0?QuLh)CHsByg^V#)|0V+7!O-VL+zK@}VuRj1lK zeyaz^w(mG~skRl}cs;$7k=*6NJvItRwPd$))HXX@)D~MA^lvEgBx;vda0(35W9x!; ztZ*s;#?VodKeS1e-5?;+N0|c{HgteHb22TfoHbhus2yE-859furbfB1G?OV!7<4m| z_#2I6yoP%AO}xu5bM^eqwUySD4F-VxGYL(atLg+u7v~vP6CUJ5RFOQeq|{Bj`$poJ zku~~*tbgbZ8t0seEy=}RHb_e76i)fDG_h_YFs5?7nNwK~Zb{F-5m*?+ zuKjrFKh}bNE)u|WDNpd>E*BwDI;jE& zDJXwqOu~)*b*7cDto7WPx@NxIo<=x_D-at$U$Hp<0g8V7Mc0Sp&srp_7eC@1g3e2NBOtGTU{o@8~%8UES5!W!&X! zJLOcq3PL-q6(D>}>4ss0U|ymHNpA9?_JJ6cUp|i&Y=}@5_EB#3#UH;f#oHw<@VFdm zbkO%Fv(5-KYVdg{Lb-(!MZ{YA9k9=NNH?U1fST7h&Peov&L}^e$z_>=abrYveynbq zL=y}5lao%;+J%O;h6yLHtRfF&VKmA7k}dfsvQQ$_N|}l-rKW~FPn}OBQHl{FS36Z& zw=BEHM}gg0##=AN(|IMY}ydVGS;XD1eDE--g03`{) z6nAFSH%<3Kml%v5d30G0^q4(80;bOr3V?yWg{Vd~deti4yION3YUIri37< z-a+;P;C~fAYtx><)d5ZX5TC$hQkrQymfgik6p-XCR#}5*w1e#5gk*7n6VH+pU6rw* zde6Tu6a!dCc*EAX*nTz%cD=nmBc8`w!TcR|u$Osxt}7qjB`}+d-@A3Z2QrF!3)$=2`>G4$+qyP^=kryc=F3X#=_}y78rjooDky= zJ*TF4L<_k;%zpl9og=|IwF{0=F7x#tc0NmM;}MMk(C0GuniX=Q4T`Hbi)W`gsr>LA zZV)_jG-m>!1!cht2Kv(-B{g@GNfnZd-|mH~HI+oU(=>E{m#{i&hJs;)0UhqA;q&@K zik^W7n~SzsLi`(;FSp5%^5#BTjjv`AfaymokRAB9|2$?5-z8-zjW_xLiP zhz-zjL}W=Z#NYm_8>$q|DzZ)J{9kMh(3s3fA2H*fc^x7#%r@>M6LTAC)28P2jr`o; zyLLR#+O%Ndh9m;~w%;(m>!#k6+=~%a!+vol4 zr?f zB(9G_@w9~$)PW|xj)gqHse8T2=VvatOA#59DHa0gcXS=HrP!lsBE+(gby8Fll~a!p zKI2JJ+g7WZa2{jW$W5* zG0a;l-*zkVuHDMEjEIAms0q~mCr;|Zh|9m1bbhdj>-otHt}&m52AU1K$FXI4zvm~= ztgY#=;XC)Tq$o!rL|o?xvQFu`<4Wc(pZUPg)A;5nql$Nq1?j>D9K=v!#cWe_Nl`h# zjhc#O8Cl35`BNL{JIa~vjQN^olW<{! zu-Wt&;d(|T7zac9G=+O>TkpMtW#!T+TnrCds^BMIxA!~S^4N5l?~S3tgrBlhH(gcf zA~!zxu#nTVVJXsPaI8AKYdNgIJGA{GvhB3v{^~+eNtkq0yU%04G4xP}<(}`sY}QvJ zkP~%?#^Lna@WPR9o;cHJ9b90~LoB~O0XDvs@4XN{6YsIjr1=hWBFOf+#!xGbRlIIn zbXJ@j7t*|xV(dhuvT(RDJq^jftuyk|V$XBFURCtOuAzt;-H$s?Y~z3V*v&oMV{rrA zHIEqRHHsoYNgb+uoY^BBI3Bc8H%^)h)K9|&YA;Blu+8$ceV?`8oMXx>wcZ7zc;y=* zMXC4inR0rM$BV>HnWGSEnZr#$OPsIX`Uf6q|ENVbT zLEIui+J{055U!+Q~>(SC^T2G0HDe%<;)D4P@5?6mcdYL_+5c(o2UU1dap{4E@tnZY?f*}vLC?Qi=K8VKKg0hb{t$9w2GX>G|pNNa4a2L zylNbg+xA&Ic@J*e`n)W%t@!B`@S+eO`@4Dm#mh49c#79gF2O(6V0UE0`hMf6fF6{O zVph1x`8KRaItlTYNfAd2JeI1y7^W^n9R*W!93`v+gOo3be%h}w2L)JC94(d>awVZ7 zXo{uE$mo{YJLXdZ6mY{B`;`@;KlB@y&@kO89JgD-3L*B?e2T z@WkX__g&A^)~8SvlS(^coiS_{svg?*W$p6;#eBr7g_}fkl!uJ#*b;0r#RqL z(l~~kQ#2zHk*nL7FKUK-lvY@iT_8|dQ}pmMC7{&puI^)$5QFukdrh`-%(R|Vg!QUs z{?@>THAw#`-kpE^PW$*XtF@Fm>jy9%1{o@+)m__@;e8Uw0P+HM8j*k3=?}D>iTw$p zH@@ZIpQ1~Qk=@JJD}LV|P1%CP0cE<1PuuDJ?Y-Y+Lg$#L>*Ls&2i|5uiex@V&=9?7 zILv2-c<#DSogxm;3h8NDM^3~Yl5G_Ga= zZH9>}en~te*4NTz!WRphABK0_!Ed4)LaE{(XIB=`H2Z;Dsm_dkDv-+XKcT4TxH76B zK}3vd;e2A2w}B*T>@lW2o9_3(YdYfn+bj^-f7xlwV;CFCe}R9u`=HV5UwJy~NbP;f z-b=IdjM8`=Ww8T zV9>7WK0IQlhki?iz_)EmSQITACQ6SpNho#8b(W{h-h3c|he(vR%;S;Edzn^~(_3%8 zry%&!?7Mk|NcsvG4lEM3_3|?vphsERQciULF;oSjd!&P-u`6eHDRW)86@X7G(mpAr7W^Zr}2{+~o57<|S{s-U@JqM@+SJuAy7}3lfa@`r^ZDhkf@SVL9IozZAan zO9hhfq?$?iELrXcfV#a}<}L}Gptm}7u15f540U(K-P6-{9K2v9dy?@dxYAMy&R0^A z6UiE0^XOj|9dp}12LnYnR@>S&R(DTof6fPsFx4@s+GWJTuD;JPyW6PuKKcA_N+GDLu+ot08z#|!pUdrnR|Hv z>ofHVSuA~)UUZxKYFd1hZEV;`v;U!{ZERxY?CwKxrW`*qfCK4H#DD(j+XSD43Jipm74!{oem< zNmytjv#Xj;7Sb1aTl}K7cC#Tes?~y&uh}aqVB%>`jz>7;0Z^jy6KXVgIX~%DLv-k?!_%DdWa`S0$B-nm|BSx zplGALdcOvjc|Q$kNl$DOf=d=>r#p4*&$B73ri1WhlQ{bl77HEnPs2mXdN)vRRL<7Bg)8HvZ+}xd}rJ=7#tmd0;b72S=BSnk;;QvH#!Q zyKW&;a}ekyF8u!j{4I)mEe|whcCEu*SL&rImmZegL~R?3N&=!VHrpW3Qp+nW zQcpzwqR~}m`74Y2TJqnxT_zH5oY|lc>sA%wPd_vm_UKLn$M@1K@oHh0J&&k>EQ_@+ zMM^S{Fj4atGO*Rn1ise<{`nspO#df5SCDdE28We8NGeg#(Vbxd`?F*zfbFQVZ+$i{ zK|e}lq)!*u2HLu1C_>4AzcF;ffqkPtgZrc7hiAM>VMa?VbqAfH6uTrqL|4%Vwx>`N zn@nzjQ1eNH{42VmOOL1ge^=7o`I~#VqbvzQ!0;mKxE)Z_t!w%c1YFHg9D}oQ>O>gs z_HY?=>9YjsMbFvSLb!xapS*7?1&0A=S9ZhCCNK=IDRr_VvRr-|pu~(s;I6kF0Rw`^)W+Cy$DLD#mwkt5c!&A%vCirq zAtp1-I|_IpPWZ;GCupUj7-9lN$XklxIhlc$A58Rr15*@HDSwU? z5cVS0iK?Pi?he8qdT z@fQ8z6cca#Co(xHj{g)gXj-2&Mc$Yxz$u4~6Uar~SU^%%c|JBC-`&3$pKO_P^%nH$ zSnX=Jyeu|6jDZ$@Cu6|CpqoYP+UMBh9qd8~V$Xw6U>$|YVWE!AP=VcFEwTa7uahfGOSlp$ zX*Z7qnw1aQWlc$WesE6YuLn{7_oJl?;<{L(_*va=&a|3?(cgo@tesZ~hfQM=O7XwcFzFtT+AFpUL097b2x zyljt%Bu4EHhQXAm*bC9-@;{zFGCqvEc%jGuF%P~KKCQ}J9KYTkHxdeT+AblUTLrw-b5PWx~ ziYuzoVgSVFohy`CQ#9(7Vx?!Y^O5uSeOve?{OdM3IdCQ-{LBQ@PmT_P554CC?h-yL zy;oPJ3BLG9rH&sIfE6sI0=ojxZzp^`=5CG22g&#c&{|(DQVAckur*2*-HTQfV2id%E+1RY76p!Rzik;m_m+_W&b*ptM9Pf%WuKL~6JRaMIZ|AQ>@s z?0~x|gd-ve&#_{FC4&eb7`HP-4{=ZHXvy=q`AuhPbtiQB$Ip$c@vm3EEufM>EJFVa zSi9YW^@jnB6yF>GQ#?_@+bu!t65ij&d;BH?>jU0(0*LLoDXE;2SG{tp+yh59D#CZq zM9tg3y=kXSZa-F9%Z~kH=Xh%Pkn-6n!S>k3tBF8*2tG~L{{Py!(s(G_zCES;PPZ*( zO-vL*sD!djq7)$%k*$pshV09jk|j$-Qdjf06MBRUQk zxIVG|x+iB%l7(Go5qw)D;mw@kxxpmh>4%~mXe%P8TB4Ht=)ibGYs*7Q_m6<9Q=BCG==74{!W#+yV~qfWIUt{(^@<(iU!_SY>${GB2w%agxInv^Qd$?smJ z3-XaO<{Q6pkol&Z8=)7sENwBQ7MOQ}W!vWdKjY@dDS%)!>gr5vtWOS@vAE<#5Y#rH zKN4-}$w%jMqvR?3SkK8x)`sz2ZcRgU*7Re}H@n?u@s9vh@81Li3u@W#T}T``#X-B> z81$W(h`8?jm|UyMorEo>Bm>5tfW}-r_Q@4C=4+X@_Dz;v|L!nR);Zr?{+st~EDcyM z+rW}5d1j0nyIvQYs^rH!_+{fhAWTNwtDnOKd5m8D6F@l!pn8V}Y98jv$rU-(d;Wb+ z8z#q`J)1x2MJ}d+c6tI^0Sp2Ujv&w_zCv-W^N-A8nNfT>T|_81IcKAM%>Q5aEC#eI z0vtBNn;Ha~MsDQ9w$3$0huw&X|8ftzWvK$BUtrLxa*U72WXB(zE0R%c{gZPo$~SNQEJH+HK=5IFzpWU%dEx%aR#bf{(rYYo4LcYKWg)xf=^7Cn(Z>8z$#e&d5pt zzP9eL;U6gGr^AWE%r|TPZ_zH;jKVh+b0aDiMdqtgBkTNTs_v4n>Q?Q z^G!_1ZfNBGJow)sYl4o_oP#qiAz@o9SSoby3uJvY8<_ritjH2LWA8-)q*3k?U-xE* z?%pCrBP3i^YN9=hn6gig6S zXFenoG)OPyow0(&(3ZXG;qd@8Dk%U76{~)t1*{Do|G}QO#RBcl*Gx5lq~BIQZTV5% z^3(n05+^|x?GlGX?2_?qNS2;7v7Y>~3*Q9P9TX^r=?zra!S9hf_wEHakqB=l8;LOy zJE$Z&m~y@nn9rd^xL5}vkqv#rJB%R+19}6C+`o74-+_R|S~0b(IQNe1*cv>`P=s=( zHvGKzY6$)&;6e;s#Od(|_<6ih&PV}knt$3g#ro?R3L$qzdn<^`;HMbr9iJT=DI)GY z1@msoeqH^$&$1rojB6tMx8P6#;rJ;vEdVPb{>rJ(Ja{!!k%U+FMeKk^eF(Vg3b-T1f*IV6xdtA zG{wfeD_7H}xl06>NyHN8F>|lHLaqwfv|jL?^PVVxHP=?pxw)<9aZq-H4}gI*u>4J- z>&|mZWznva+@)2w30*>;HgM#Cxi1)u;?(EUOQU1tW~lafm#AzLVDBBcfNf(+CL|ix z#8)(-k%xT|V$9crz)=AT=Jw#A*hsqY#EZ(gocPvDeGhhx)c^%q6eNMlEu!GY?}$dv z7Z(T#5z9#=w;35gq!bT=s5luN6Bw4OZ&Vv4aQg%}oAes+$gy@%G4r#mrDIwPSqYAi zqsQcjkjX6UQVP%orGtHl`PqMpJft2+EvXci)c7q6>=_h=K%=i>G6((=m!NsFx?7uT zln@jkfkWVHVcWsiZp5P4xg56*q2OTJKB0e&sM%p$g0yJc%v#L6x?&Afx;h|28(Xka zs4#jhY> z8WN7V8jTpHoq zb3X(Cr}Cge0aEsy2mmBE$LMi}*0whVBHcW5CP;t@kU2E!OkqsUsdvy8V5DFF;&>i;TdKbYq}@zyPmSY;J&j>bo)_#95Z@O`X*J3P|RC)B0mKj1tvfZK+{w%#0OA0NFYPpjavl1AxiTFKoMQ#Pj$c{KZR{KQ4V?n zY(oP<4QT7m*NSn7lHWY+TO-5dS%Pq!2POCMl!u!}?Tb#!kNGZ3{hjBwN}pc1vikIhCmA2{dP_QDwj^*AKF<5_3d z%VTL$capVg0_WyWEGx(`c&DM9JZl(E z$YHL$mLzwS=hP9%+bPxxe2WWR>9xp6)qqkqoNI)=x6OUy!mS5&M_!?$%1-8^xRgs& zI{a6-HY8asLGT;4_PNM=8u`3RzNg#lMh?+gbLRur!L)5_&#`&;?C!7837xbv5GjW} z(r=JqVPQC~Vm>OQ6&rvTgAluKSGz*$o9&M(GV3+($nNvEAQ1jT$03j% zz+dqp+Y!;t9C`wJghu5{LD!V!yOS)aE- zAZw^crbhUHVGist1R|LBMB@LQR?a#d6#C4V)UzN6r2fqd_}DSw)Z;^@n2(MIN^}V1 zf${BDPyhb1q{YKJPLO|xw(b=Ky&dPg*6^v+@LiHE?Xum#FQlITRMP+Azq{sf^c&L5 zbJ;@Q4rdI~gEqM~qCxEqT>jCcE2H<`o>YS~fDPWuh_TYHyI-OnQ0hHbdsea9MM&^7 zrL8W{vM;if9e-9qtLF;IsKjgfCmZU5ze%lSc>a0nP%*cg z^|>6LUCp=|l)ATm5MF!-vreA9_m>5v?Qr%QF$qt+Aa5iNKTO)EV$w_h$e*14MB?I+ z*ZpdQp~{5@Hq>4{6yEo>5%~#6H*-P$$)xxXIEImx9R;#?FT>R_Lu+%F;G3K2=qML| zF7R-IGqd1m@rnAR%Q3&3jFBTox3scDFI;bX#*; z`QU(f@u)6uBBBmWe=gV*1mn=$W^shOqXIe9a77hGt^EQ`853Mh*hTc<5$UPg^^-4~ zwX%*X{Sdrg$%yxY+;$8PR_7h94EesAQ=ED{{h6lC~SFi(PPw9wmrms^luei4t`D2;=M;zPQXGb{%Gv}qbQ+BVKwf38`-}1Rw7ofD8P_{@4WAh{Gy)ffDw>d*TIo(ug zMXztEyKZBVqGe@7*l1VYr{SD~UcheNCF$N1hS>*9mb&7eQj33ZxO~b`JiDFY;@{yLH~xXtv7X|MFSx;cQ8+N$X*89mZtYrm`zgK+>JxUH$FmRq{AqLQnu+>SY4Ad< znSHVE;o(cTxiorQ(71kqTsZae;4gN>X#sO4hD5d_a~eu>ah>c;k=slDGa*n$|F7~F zsMJW!1t>3clt#x&6uT_DiNHVbSc})?43*C5G+A30ug=l@EW@T@)I6VoWR&gQVLRkv z(TR8V`h9+ZD;0@~{bw`eJ-HHbWvKR3P4vV8L-vwMp_Snx>EjsgskL_0(+>1yY5{7M zRKzN3bPPdL3(|XK1crqxtJGE754p6m22wsg|K*4dubgd&P<@3AGn=Kn?JPuU zAXhc}_^gpj3kW_>@zGnke+1(XYuNhR= zXaQw*T)<`GyR3=mbae2Q+KRUa5aHonAu`aR?_--8>4^ef*DhVQ|FM~{@l*Wl$ECo4 z>AdBt_W`T7$!#O|#hx*pNVl@C!-lR2W8ar0&OuGZ)L&(4W20J!Z^kvDJEa?c_(^2! z@3dIw&XBru5UaEuANAc zUggqq^sfwPFP8BU{xy3d7P^8KL+2BlTJ=0oR9)SwtPFeqkb&~R%g=I}wPx+O-&G7T ztD}+(uXDyTA+-!yw|5(5*=9m!8lL<&O%$F*gwZ&AVUBBL`aNBdFRyhqUDmH#)Kr(` z9nb%YGkG#=n5s$CSM*#~qb?f0EPyRER>6K&%yN&7Y!Cg!>WWi?yIl=79d*(!n%;Mj$aw`f z)t}Jb6F$#Tv_vq)2;RfRjfD|jN;=c9ltGE_ygR5-7{!>n!z{%ADthE|J3!4t3>8&y zTy|*qWJSQDie-DwtD#p`LQzfLpo+4Syi9!Nc$Ts_X^H2S7M45X4X{R)*vN0+(w6KN z9y%*%c_WG#O@XWG0-DUFjPlkLSv^Tibxm!>tn)DIW3`puby6$FrUN(m0v8ul4^;UO zH%wtf-g^($Rm}w0kv=BEV7+P9p(V)5XUw_(>84#xDy-%nVn8GAYo>c3Jqn#5H&}qO z9Y~sA(^m~5++c1LglCD*v5SuCsWJ7-Di=NRu0-_a^W$ScwRFvNC09p&TS=T*afrV) zR<4lksu!riBgU3{NH#mPdM@(LaOCkB^;EcnrXj0O{z&MCpnu$>&6%fi#ax}wxdim&L?+VEL%B6;VQwNw(B>2Zl!sh6Yh{W#;~xDF^u%24 literal 0 HcmV?d00001 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 +#include +#include +#include + +#include + +#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 duration; + typedef std::chrono::time_point 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 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 + +#include +#include +#include +#include +#include + +#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 &lock); + + void notify_one() noexcept + { + pthread_cond_signal(&_m_cond); + } + + void notify_all() noexcept + { + pthread_cond_broadcast(&_m_cond); + } + + template + void wait(unique_lock &lock, Predicate pred) + { + while (!pred()) + wait(lock); + } + + template + cv_status wait_until(unique_lock &lock, + const chrono::time_point &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(abs_time); + auto nano_secs = chrono::duration_cast(abs_time - secs); + + struct timespec c_abs_time = {static_cast(secs.time_since_epoch().count()), + static_cast(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 + bool wait_until(unique_lock &lock, + const chrono::time_point &abs_time, + Predicate pred) + { + while (!pred()) + if (wait_until(lock, abs_time) == cv_status::timeout) + return pred(); + return true; + } + + template + cv_status wait_for(unique_lock &lock, + const chrono::duration &rel_time) + { + return wait_until(lock, real_time_clock::now() + rel_time); + } + + template + bool wait_for(unique_lock &lock, + const chrono::duration &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 _m_mtx; + + // so that Lockable automatically unlocks when waiting and locks after waiting + template + 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()) {} + ~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 lk(*_m_mtx); + _m_cond.notify_one(); + } + + void notify_all() noexcept + { + lock_guard lk(*_m_mtx); + _m_cond.notify_all(); + } + + template + void wait(Lock &lock) + { + shared_ptr mut = _m_mtx; + unique_lock lk(*mut); + unlocker auto_lk(lock); // unlock here + + unique_lock lk2(std::move(lk)); + _m_cond.wait(lk2); + } // mut.unlock(); lock.lock(); + + template + void wait(Lock &lock, Predicate pred) + { + while (!pred()) + wait(lock); + } + + template + cv_status wait_until(Lock &lock, + const chrono::time_point &abs_time) + { + shared_ptr mut = _m_mtx; + unique_lock lk(*mut); + unlocker auto_lk(lock); // unlock here + + unique_lock lk2(std::move(lk)); + return _m_cond.wait_until(lk2, abs_time); + } + + template + bool wait_until(Lock &lock, + const chrono::time_point &abs_time, + Predicate pred) + { + while (!pred()) + if (wait_until(lock, abs_time) == cv_status::timeout) + return pred(); + return true; + } + + template + cv_status wait_for(Lock &lock, + const chrono::duration &rel_time) + { + return wait_until(lock, real_time_clock::now() + rel_time); + } + + template + bool wait_for(Lock &lock, + const chrono::duration &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 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& 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 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 +#include +#include +#include +#include + +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; + using unique_lock = std::unique_lock; +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 + std::future_status + wait_for(const std::chrono::duration &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 + std::future_status + wait_until(const std::chrono::time_point &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 +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(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(v); } +}; + +} // namespace detail + +template +class shared_future { +}; + + +template +class future { + using state_type = std::shared_ptr>; +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 share() noexcept { return std::shared_future(); } + + R get() { return state_->get(); } + + bool valid() const noexcept { return state_->valid(); } + + void wait() const { state_->wait(); } + + template + std::future_status + wait_for(const std::chrono::duration &rel_time) const { + return state_->wait_for(rel_time); + } + + template + std::future_status + wait_until(const std::chrono::time_point &abs_time) const { + return state_->wait_until(abs_time); + } + +private: + state_type state_; +}; + + +template <> +class future { + using state_type = std::shared_ptr>; +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 share() noexcept { return std::shared_future(); } + + void get() { state_->get(); } + + bool valid() const noexcept { return state_->valid(); } + + void wait() const { state_->wait(); } + + template + std::future_status + wait_for(const std::chrono::duration &rel_time) const { + return state_->wait_for(rel_time); + } + + template + std::future_status + wait_until(const std::chrono::time_point &abs_time) const { + return state_->wait_until(abs_time); + } + +private: + state_type state_; +}; + + +template +class promise { + using state_type = std::shared_ptr>; +public: + promise() : state_(new detail::shared_state()) {} + + 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 get_future() { return std::future(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 { + using state_type = std::shared_ptr>; +public: + promise() : state_(new detail::shared_state()) {} + + 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 get_future() { return std::future(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 +void swap(std::future &lhs, std::future &rhs) noexcept { + lhs.swap(rhs); +} + +template +void swap(std::promise &lhs, std::promise &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 + +#include +#include +#include +#include + +#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 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 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 + unique_lock(mutex_type& m, const chrono::time_point& abs_time) noexcept + : pm(std::addressof(m)), owns(pm->try_lock_until(abs_time)) + { } + + template + unique_lock(mutex_type& m, const chrono::duration& 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 + bool try_lock_for(const chrono::duration& 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 + bool try_lock_until(const chrono::time_point& 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 + void swap(unique_lock& x, unique_lock& y) + { + x.swap(y); + } + + template + int try_lock(L0& l0, L1& l1) + { + unique_lock 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 + int try_lock(L0& l0, L1& l1, L2& l2, L3&... l3) + { + int r = 0; + unique_lock 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 + 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 u0(l0); + i = try_lock(l1, l2, l3...); + if (i == -1) + { + u0.release(); + return; + } + } + ++i; + sched_yield(); + break; + case 1: + { + unique_lock 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 + void lock(L0& l0, L1& l1) + { + while (true) + { + { + unique_lock u0(l0); + if (l1.try_lock()) + { + u0.release(); + break; + } + } + sched_yield(); + // wait and try the other way + { + unique_lock u1(l1); + if (l0.try_lock()) + { + u1.release(); + break; + } + } + sched_yield(); + } + } + + template + 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 + 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 once_functor; + extern void set_once_functor_lock_ptr(unique_lock*); + + extern "C" void once_proxy(); // passed into pthread_once + + template + 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 functor_lock(get_once_mutex()); + + auto call_wrapper = std::bind(std::forward(func), std::forward(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 once_functor; + + mutex& get_once_mutex() + { + static mutex once_mutex; + return once_mutex; + } + + inline unique_lock*& get_once_functor_lock_ptr() + { + static unique_lock* once_functor_mutex_ptr = nullptr; + return once_functor_mutex_ptr; + } + + void set_once_functor_lock_ptr(unique_lock* 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 once_call = std::move(once_functor); + + // no need to hold the lock anymore + unique_lock* 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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_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; + + friend bool operator==(thread::id x, thread::id y) noexcept; + + friend bool operator<(thread::id x, thread::id y) noexcept; + + template + friend basic_ostream& + operator<<(basic_ostream& out, thread::id id); + }; + + thread() noexcept = default; + thread(const thread&) = delete; + thread& operator=(const thread&) = delete; + ~thread(); + + template + explicit thread(F&& f, Args&&... args) + { + start_thread(make_invoker_ptr(std::bind( + std::forward(f), + std::forward(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 + struct invoker : public invoker_base + { + Callable func; + + invoker(Callable&& F) : func(std::forward(F)) { } + + void invoke() { func(); } + }; + + template + shared_ptr> make_invoker_ptr(Callable&& F) + { + return std::make_shared>(std::forward(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 + inline basic_ostream& + operator<<(basic_ostream& 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 + { + typedef size_t result_type; + typedef thread::id argument_type; + size_t operator()(const thread::id& id) const noexcept + { + return hash()(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 + inline void sleep_for(const chrono::duration& rel_time) + { + if (rel_time <= rel_time.zero()) // less than zero, no need to sleep + return; + auto milli_secs = chrono::duration_cast(rel_time); + // the precision is limited by rt-thread thread API + rt_thread_mdelay(milli_secs.count()); + } + + template + inline void sleep_until(const chrono::time_point& 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(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 + +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)); +} diff --git a/components/cplusplus/cpp11/thread_local_impl.cpp b/components/cplusplus/cpp11/thread_local_impl.cpp new file mode 100644 index 0000000000..43761c1e62 --- /dev/null +++ b/components/cplusplus/cpp11/thread_local_impl.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 +#include + +typedef void (*destructor) (void *); + +extern "C" +int __cxa_thread_atexit_impl(destructor dtor, void* obj, void* dso_symbol) +{ + pthread_key_t key_tmp; + if (pthread_key_create(&key_tmp, dtor) != 0) + abort(); + pthread_setspecific(key_tmp, obj); + return 0; +} + +#if defined(__GNUC__) && !defined(__ARMCC_VERSION)/*GCC*/ +#include + +extern"C" +int __cxxabiv1::__cxa_thread_atexit(destructor dtor, void *obj, void *dso_handle) +{ + return __cxa_thread_atexit_impl(dtor, obj, dso_handle); +} +#endif diff --git a/components/libc/compilers/common/none-gcc/sys/types.h b/components/libc/compilers/common/none-gcc/sys/types.h index e9f44f7762..8dfffcef97 100644 --- a/components/libc/compilers/common/none-gcc/sys/types.h +++ b/components/libc/compilers/common/none-gcc/sys/types.h @@ -25,6 +25,7 @@ typedef signed int ssize_t; /* Used for a count of bytes or an error #else typedef long signed int ssize_t; /* Used for a count of bytes or an error indication. */ #endif +typedef long suseconds_t; /* microseconds. */ typedef unsigned long useconds_t; /* microseconds (unsigned) */ typedef unsigned long dev_t; diff --git a/components/libc/compilers/common/sys/time.h b/components/libc/compilers/common/sys/time.h index c2320429e0..95605d47c7 100644 --- a/components/libc/compilers/common/sys/time.h +++ b/components/libc/compilers/common/sys/time.h @@ -48,9 +48,10 @@ rt_int8_t rt_tz_is_dst(void); #ifndef _TIMEVAL_DEFINED #define _TIMEVAL_DEFINED #if !(defined(_WIN32)) -struct timeval { - long tv_sec; /* seconds */ - long tv_usec; /* and microseconds */ +struct timeval +{ + time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* and microseconds */ }; #endif #endif /* _TIMEVAL_DEFINED */ diff --git a/components/libc/pthreads/pthread.c b/components/libc/pthreads/pthread.c index 79104d1fd5..3df51caca6 100644 --- a/components/libc/pthreads/pthread.c +++ b/components/libc/pthreads/pthread.c @@ -61,7 +61,7 @@ pthread_t _pthread_data_create(void) memset(ptd, 0x0, sizeof(_pthread_data_t)); ptd->canceled = 0; - ptd->cancelstate = PTHREAD_CANCEL_DISABLE; + ptd->cancelstate = PTHREAD_CANCEL_ENABLE; ptd->canceltype = PTHREAD_CANCEL_DEFERRED; ptd->magic = PTHREAD_MAGIC; @@ -90,9 +90,30 @@ void _pthread_data_destroy(pthread_t pth) { RT_DECLARE_SPINLOCK(pth_lock); + extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; _pthread_data_t *ptd = _pthread_get_data(pth); if (ptd) { + /* destruct thread local key */ + if (ptd->tls != RT_NULL) + { + void *data; + rt_uint32_t index; + for (index = 0; index < PTHREAD_KEY_MAX; index ++) + { + if (_thread_keys[index].is_used) + { + data = ptd->tls[index]; + if (data && _thread_keys[index].destructor) + _thread_keys[index].destructor(data); + } + } + + /* release tls area */ + rt_free(ptd->tls); + ptd->tls = RT_NULL; + } + /* remove from pthread table */ rt_hw_spin_lock(&pth_lock); pth_table[pth] = NULL; @@ -103,13 +124,17 @@ void _pthread_data_destroy(pthread_t pth) rt_sem_delete(ptd->joinable_sem); /* release thread resource */ - if (ptd->attr.stackaddr == RT_NULL && ptd->tid->stack_addr != RT_NULL) + if (ptd->attr.stackaddr == RT_NULL) { /* release thread allocated stack */ - rt_free(ptd->tid->stack_addr); + if (ptd->tid) + { + rt_free(ptd->tid->stack_addr); + } } /* clean stack addr pointer */ - ptd->tid->stack_addr = RT_NULL; + if (ptd->tid) + ptd->tid->stack_addr = RT_NULL; /* * if this thread create the local thread data, @@ -221,6 +246,12 @@ int pthread_create(pthread_t *pid, pthread_attr_init(&ptd->attr); } + if (ptd->attr.stacksize == 0) + { + ret = EINVAL; + goto __exit; + } + rt_snprintf(name, sizeof(name), "pth%02d", pthread_number ++); /* pthread is a static thread object */ @@ -269,7 +300,7 @@ int pthread_create(pthread_t *pid, /* initial this pthread to system */ if (rt_thread_init(ptd->tid, name, pthread_entry_stub, ptd, stack, ptd->attr.stacksize, - ptd->attr.schedparam.sched_priority, 5) != RT_EOK) + ptd->attr.schedparam.sched_priority, 20) != RT_EOK) { ret = EINVAL; goto __exit; @@ -460,7 +491,7 @@ void pthread_exit(void *value) if (_thread_keys[index].is_used) { data = ptd->tls[index]; - if (data) + if (data && _thread_keys[index].destructor) _thread_keys[index].destructor(data); } } @@ -507,14 +538,21 @@ int pthread_kill(pthread_t thread, int sig) { #ifdef RT_USING_SIGNALS _pthread_data_t *ptd; + int ret; ptd = _pthread_get_data(thread); if (ptd) { - return rt_thread_kill(ptd->tid, sig); + ret = rt_thread_kill(ptd->tid, sig); + if (ret == -RT_EINVAL) + { + return EINVAL; + } + + return ret; } - return EINVAL; + return ESRCH; #else return ENOSYS; #endif @@ -707,3 +745,4 @@ int pthread_cancel(pthread_t thread) return 0; } RTM_EXPORT(pthread_cancel); + diff --git a/components/libc/pthreads/pthread.h b/components/libc/pthreads/pthread.h index 8639c1604b..177b2539c5 100644 --- a/components/libc/pthreads/pthread.h +++ b/components/libc/pthreads/pthread.h @@ -265,6 +265,11 @@ int pthread_barrier_init(pthread_barrier_t *barrier, int pthread_barrier_wait(pthread_barrier_t *barrier); +int pthread_setspecific(pthread_key_t key, const void *value); +void *pthread_getspecific(pthread_key_t key); +int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)); +int pthread_key_delete(pthread_key_t key); + #ifdef __cplusplus } #endif From f07507a91310bc5696a08f5bbf6ab8679cfbcf73 Mon Sep 17 00:00:00 2001 From: liukangcc Date: Fri, 17 Sep 2021 14:57:42 +0800 Subject: [PATCH 2/3] [update] Conflicting files --- components/libc/compilers/common/none-gcc/sys/types.h | 4 +++- components/libc/pthreads/pthread.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/libc/compilers/common/none-gcc/sys/types.h b/components/libc/compilers/common/none-gcc/sys/types.h index 8dfffcef97..f7f563035c 100644 --- a/components/libc/compilers/common/none-gcc/sys/types.h +++ b/components/libc/compilers/common/none-gcc/sys/types.h @@ -12,6 +12,8 @@ #define __SYS_TYPES_H__ #include +#include +#include typedef int32_t clockid_t; typedef int32_t key_t; /* Used for interprocess communication. */ @@ -34,4 +36,4 @@ typedef unsigned int u_int; typedef unsigned char u_char; typedef unsigned long u_long; -#endif +#endif \ No newline at end of file diff --git a/components/libc/pthreads/pthread.c b/components/libc/pthreads/pthread.c index 3df51caca6..b0bf39dff6 100644 --- a/components/libc/pthreads/pthread.c +++ b/components/libc/pthreads/pthread.c @@ -61,7 +61,7 @@ pthread_t _pthread_data_create(void) memset(ptd, 0x0, sizeof(_pthread_data_t)); ptd->canceled = 0; - ptd->cancelstate = PTHREAD_CANCEL_ENABLE; + ptd->cancelstate = PTHREAD_CANCEL_DISABLE; ptd->canceltype = PTHREAD_CANCEL_DEFERRED; ptd->magic = PTHREAD_MAGIC; From b51602b1db901e46fd1fec4d76c669b31a538079 Mon Sep 17 00:00:00 2001 From: liukangcc Date: Sat, 18 Sep 2021 09:56:56 +0800 Subject: [PATCH 3/3] [update] Add a blank line at the end --- components/libc/compilers/common/nogcc/sys/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/libc/compilers/common/nogcc/sys/types.h b/components/libc/compilers/common/nogcc/sys/types.h index f7f563035c..5672f54a4d 100644 --- a/components/libc/compilers/common/nogcc/sys/types.h +++ b/components/libc/compilers/common/nogcc/sys/types.h @@ -36,4 +36,4 @@ typedef unsigned int u_int; typedef unsigned char u_char; typedef unsigned long u_long; -#endif \ No newline at end of file +#endif