Comments (12)
就目前的C/C++标准来看也没有要求编译器在遇到aligned memory access时必须生成单条汇编指令,比如对int32的赋值完全可以生成4条int8 store来完成。
所以标准 C 给出了 c11 atomic 的补丁。
void rt_tz_set(int32_t offset_sec)
{
rt_base_t level;
level = rt_hw_interrupt_disable();
_current_tz_offset_sec = offset_sec;
rt_hw_interrupt_enable(level);
}
类似这种代码,符合标准 C 的严谨写法应该是。
static _Atomic(int32_t) _current_tz_offset_sec = \
RT_LIBC_TZ_DEFAULT_HOUR * 3600U + RT_LIBC_TZ_DEFAULT_MIN * 60U + RT_LIBC_TZ_DEFAULT_SEC;
/* return current timezone offset in seconds */
void rt_tz_set(int32_t offset_sec)
{
atomic_store_explicit(&_current_tz_offset_sec, offset_sec, memory_order_relaxed);
}
int32_t rt_tz_get(void)
{
return atomic_load_explicit(&_current_tz_offset_sec, memory_order_relaxed);
}
在 C11 标准下,这一对 LOAD/STORE 操作是强制原子性的。只要能编译,就一定不会差错。至于 Linux 使用的 WRITE ONCE 的同等 API,是在 C11 标准之前的,非标准化,旧的实现。对于 RTT 完全没有必要抛开标准化的 API,去定义一套新的实现。如果非要支持不能使用 C11 的平台,RTT 内核也没必要遵循 Linux 内核的那套标准,完全可以完善一下现在的 rtatomic.h
,皈依标准化的路径。这对于大量的 C/C++ 程序员而言,都是更加熟悉和亲切的。
而当前 rtatomic.h
欠缺的功能太多了。限制了不同数据类型操作,也没有显式内存次序等非常重要的内容。对于高频操作,默认使用最强的内存次序代价是非常高的。在 RV64 平台 c908/c906 下,这类指令的周期是没有确定性的。在 aarch64 平台下,实际测试下来,其指令周期是运算指令的数百倍。换而言之对于实时系统伤害很大。
最后提一句,上述 C11 atomic 的写法最后生成的指令流在 aarch64 平台下和 _current_tz_offset_sec = xxx
不会有任何区别 。C11 atomic 只是显式保证了正确性。而 合理的 的使用(符合业务逻辑的显式内存次序)才能保证这种正确性不会带来额外的代价。因为如果你用的是 rt_atomic_store/load 就会得到截然不同的结果。这也是我为什么说 rt atomic 缺乏内存次序是非常严重的设计漏洞。
上面两个是 C11 atomic,下面两个是采用了 volatile。
rt_tz_set:
adrp x1, .LANCHOR0
add x1, x1, :lo12:.LANCHOR0
str w0, [x1]
ret
rt_tz_get:
adrp x0, .LANCHOR0
add x0, x0, :lo12:.LANCHOR0
ldr w0, [x0]
ret
rt_tz_setx:
adrp x1, .LANCHOR0
add x1, x1, :lo12:.LANCHOR0
str w0, [x1, 4]
ret
rt_tz_getx:
adrp x0, .LANCHOR0
add x0, x0, :lo12:.LANCHOR0
ldr w0, [x0, 4]
ret
from rt-thread.
感谢回复!
int32对齐时的原子性在arm,x86平台上是显而易见的
我认同这一点,但我觉得应该仅限于手写汇编代码使用单条指令完成赋值时。因为较真一点的话这一点只在arch的文档中有规定,例如aarch64上在这里,但是其并没有规定C/C++代码的原子性。
就目前的C/C++标准来看也没有要求编译器在遇到aligned memory access时必须生成单条汇编指令,比如对int32的赋值完全可以生成4条int8 store来完成。
虽然不见得哪个编译器真会这么犯病,但是anyway我们写的代码是C而不是汇编嘛,我觉得还是应该尊重一下标准的。
至于您提到的linux,我印象中在必要时是会采用WRITE_ONCE/READ_ONCE两个宏(其实是对volatile的封装)
来实现,不会直接赋值。
from rt-thread.
为什么rtt要将atomic和内存墙绑定在一起,而不是显示地提供内存墙的api呢?类似于linux的smp_mb_before_atomic。我理解,这样将是否在atomic操作加内存墙的权利交给开发人员可以提高整体的性能。
建议是再加一个memory_order的参数
+1。标准 C 更加通用。没必要自己又玩一套。反而让人觉得只会抄 Linux。
可以有一个 rt_atomic_load_explicit()
from rt-thread.
我认为这个观点是正确的 只要是赋值 绝对不能当做是原子操作,这个行为与编译器、CPU架构很多因素都有关,很有可能大部分情况运气好,没有什么问题。但是作为操作系统,不能有这种假设。
from rt-thread.
你不说我都没注意,他评论那个位置的临界区原来是我加的,我都不知道什么时候被删了😂
from rt-thread.
赋值不是原子性的,需要rt_atomic_store,例如
void rt_tick_set(rt_tick_t tick)
{
rt_atomic_store(&(rt_tick), tick);
}
from rt-thread.
from rt-thread.
嗯,int32对齐时的原子性在arm,x86平台上是显而易见的。你提到的那篇文章阐述的也是在32为平台对64为变量赋值的原子性。至于32位平台对一个对齐的32位数据进行赋值,在我目前接触的arch来看是必然原子的。如果这条不成立,那linux也得乱套了
from rt-thread.
至于您提到的linux,我印象中在必要时是会采用WRITE_ONCE/READ_ONCE两个宏(其实是对volatile的封装)来实现,不会直接赋值。
#define __READ_ONCE_SIZE \
({ \
switch (size) { \
case 1: *(__u8 *)res = *(volatile __u8 *)p; break; \
case 2: *(__u16 *)res = *(volatile __u16 *)p; break; \
case 4: *(__u32 *)res = *(volatile __u32 *)p; break; \
case 8: *(__u64 *)res = *(volatile __u64 *)p; break; \
default: \
barrier(); \
__builtin_memcpy((void *)res, (const void *)p, size); \
barrier(); \
} \
})
static __always_inline void __write_once_size(volatile void *p, void *res, int size)
{
switch (size) {
case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
default:
barrier();
__builtin_memcpy((void *)p, (const void *)res, size);
barrier();
}
}
我比较认同这种做法,使用volatile修饰,让编译器来生成赋值代码,而不是使用atomic系列api,目前rtt的atomic类型会强制上升到cpu位数(32/64)并且可能会存在部分架构(比如m0核)的性能问题(软件模拟原子)
from rt-thread.
为什么rtt要将atomic和内存墙绑定在一起,而不是显示地提供内存墙的api呢?类似于linux的smp_mb_before_atomic。我理解,这样将是否在atomic操作加内存墙的权利交给开发人员可以提高整体的性能。
rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr)
{
rt_atomic_t ret;
__asm__ volatile (
" ldr %0, %1\n"
" dmb ish"
: "=r" (ret)
: "Q" (*ptr)
: "memory");
return ret;
}
from rt-thread.
为什么rtt要将atomic和内存墙绑定在一起,而不是显示地提供内存墙的api呢?类似于linux的smp_mb_before_atomic。我理解,这样将是否在atomic操作加内存墙的权利交给开发人员可以提高整体的性能。
建议是再加一个memory_order的参数
from rt-thread.
为什么rtt要将atomic和内存墙绑定在一起,而不是显示地提供内存墙的api呢?类似于linux的smp_mb_before_atomic。我理解,这样将是否在atomic操作加内存墙的权利交给开发人员可以提高整体的性能。
建议是再加一个memory_order的参数
+1。标准 C 更加通用。没必要自己又玩一套。反而让人觉得只会抄 Linux。
可以有一个
rt_atomic_load_explicit()
赞同
from rt-thread.
Related Issues (20)
- 在rtthread studio建立v5.1.0的工程不能用 HOT 1
- [bsp/rk3568]:使用v5.1.0版本无法正常启动 HOT 4
- qemu-vexpress-a9 中使用c++出错 HOT 4
- rt_object_get_information函数优化问题 HOT 5
- n32g452xx BSP包中关于USART2重映射2的宏定义编译报错问题
- pm.c中notify、_pm_device_suspend/_pm_device_resume传参不对称,是bug还是设计如此? HOT 1
- [Bug] calc_random() 返回应该是有符号随机数
- [Bug] bsp/cvitek, adc driver is not completed HOT 3
- [Feature] 希望能将 formating 工具加到仓库的 tools 中 HOT 9
- [Feature] Add milk-v duo bsp to ci-build
- [Bug] pm.c文件中函数_pm_change_sleep_mode()调用函数rt_timer_check()存在问题 HOT 2
- [Bug] musl gcc can not work HOT 10
- [Feature] 优化 cvitek 固件打包的处理 HOT 7
- [Bug] Not compiled for Allwinner D1H. HOT 12
- [Bug] RTT Studio不支持DefineGroup中LOCAL_CCFLAGS等编译选项
- POSIX接口测试
- [Bug] bsp/cvitek 大核无法支持 float 指令 HOT 10
- 官方ART-Pi media io不工作 HOT 2
- _thread_detach_from_mutex 释放互斥量
- [Bug] musl gcc link error HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rt-thread.