mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-11-09 20:45:41 +08:00
[update] support armclang and c++11.
This commit is contained in:
1 parent
dca7dcb42a
commit
a3541b2a24
27 files changed
+2595
-12
No files matched your search
@@ -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
|
||||
|
||||

|
||||
|
||||
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'
|
||||
```
|
||||
@@ -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
|
||||

|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 |
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in new issue
Block a user