[update] support armclang and c++11.

This commit is contained in:
liukangcc
2021-09-16 09:51:33 +08:00
parent dca7dcb42a
commit a3541b2a24
27 changed files with 2595 additions and 12 deletions
+12
View File
@@ -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
+12 -1
View File
@@ -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')
+49
View File
@@ -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'
```
+48
View File
@@ -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'
```
@@ -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 <arm-tpl.h>
#include <sys/time.h>
#include <rtthread.h>
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;
}
@@ -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 <arm-tpl.h>
#include "tpl.h"
#include <new>
#include <cstdint>
#include <stdatomic.h>
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<uintptr_t>(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<arm_tpl_cv *>(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;
}
@@ -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 <arm-tpl.h>
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;
}
@@ -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 <arm-tpl.h>
#include <cstdint>
#include <stdatomic.h>
#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<uintptr_t>(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;
}
@@ -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 <arm-tpl.h>
#include "tpl.h"
#include <cstdio>
#include <pthread.h>
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;
}
+56
View File
@@ -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 <rtthread.h>
#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
+88
View File
@@ -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 <rthw.h>
#include <stdint.h>
#include <stdbool.h>
/*
* override gcc builtin atomic function for std::atomic<int64_t>, std::atomic<uint64_t>
* @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, ^)
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+59
View File
@@ -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;
};
File diff suppressed because it is too large Load Diff
@@ -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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+52
View File
@@ -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();
}
}
}
File diff suppressed because it is too large Load Diff
+94
View File
@@ -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;
}
}
+29
View File
@@ -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));
}
@@ -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 <pthread.h>
#include <cstdlib>
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 <cxxabi.h>
extern"C"
int __cxxabiv1::__cxa_thread_atexit(destructor dtor, void *obj, void *dso_handle)
{
return __cxa_thread_atexit_impl(dtor, obj, dso_handle);
}
#endif
@@ -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;
+4 -3
View File
@@ -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 */
+47 -8
View File
@@ -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);
+5
View File
@@ -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