在SylixOS驱动代码中,常会看到KN_SMP_WMB()指令,追踪该指定到最后查到的是它会在编译前转换成__asm__ __volatile__ ("" : : : "memory")命令,那这句话的意思是什么呢?

__asm__ __volatile__ ("" : : : "memory")是内嵌汇编指令,代码的功能是实现内存屏障。

__asm__:表示后面的代码为内嵌汇编指令。

__volatile__:表示编译器不能优化该段代码(若没有__volatile__声明,GCC进行编译时会根据自己的判断决定是否将这段内嵌汇编指令优化掉)。

("" : : : "memory"):表示括号里面的为汇编指令,

__asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify)

总共有四部分(汇编语句:输出部分:输入部分:描述修改部分)

下面通过一个例子说明。

static __inline int wsn_DisableInterrupt(void)

{

register int retval, temp;

__asm__ volatile (

"mrs %0, cpsr\n"

"\torr %1, %0, #0xC0\n"

"\tmsr cpsr_c, %1\n"

: "=r" (retval), "=r" (temp));

barrier(0);

return retval;

}

1. "mrs %0, cpsr\n" 将cpsr状态寄存器的值传给%0(mrs:状态寄存器到通用寄存器的传送指令, %0:指令中的操作数可以使用占位符引用C语言变量,%0对应c变量retval,表示将cpsr中的值传给retval)

2. "\torr %1, %0, #0xC0\n" 将%0与0xC0值做orr或运算,即置位操作,并赋值给%1。CPSR的I、F位置1,关中断(orr:将%0与0xC0做或运算,结果保存给%1, #0xC0:立即数0x1100 0000置位)

3. "\tmsr cpsr_c, %1\n" 将%1的值传给cpsr_c状态寄存器(msr:通用寄存器到状态寄存器的传送指令, cpsr_c对应cpsr寄存器的0-7位,即cpsr寄存器中的I,F位被置1,禁止IRQ,FIQ中断)

4. : "=r" (retval), "=r" (temp)); 按先后顺序,将%0中内容输出到retval,%1中内容输出到temp。(:表示下一部分输出部分, "=r":表示使用一个通用寄存器, retval:表示c语言中已定义的变量)

转回__asm__ __volatile__ ("" : : : "memory")命令

最后一部分英文介绍为Clobber/Modify,

有时候,你想通知GCC当前内联汇编语句可能会对某些寄存器或内存进行修改,希望GCC在编译时能够将这一点考虑进去。那么你就可以在Clobber/Modify域声明这些寄存器或内存。因为你在Input/Output操作表达式所指定的寄存器,或当你为一些Input/Output操作表达式使用"r","g"约束,让GCC为你选择一个寄存器时,GCC对这些寄存器是非常清楚的——它知道这些寄存器是被修改的,你根本不需要在Clobber/Modify域再声明它们。但除此之外,GCC对剩下的寄存器中哪些会被当前的内联汇编修改一无所知。所以如果你真的在当前内联汇编指令中修改了它们,那么就最好在Clobber/Modify中声明它们,让GCC针对这些寄存器做相应的处理。否则有可能会造成寄存器的不一致,从而造成程序执行错误。

例如:

__asm__ ("mov R0, #0x34" : : : "R0");

寄存器R0出现在"Instruction List中",并且被mov指令修改,但却未被任何Input/Output操作表达式指定,所以你需要在Clobber/Modify域指定"R0",以让GCC知道这一点。否则有可能会造成寄存器的不一致,从而造成程序执行错误。

如果一个内联汇编语句的Clobber/Modify域存在"memory",那么GCC会保证在此内联汇编之前,如果某个内存的内容被装入了寄存器,那么在这个内联汇编之后,如果需要使用这个内存处的内容,就会直接到这个内存处重新读取,而不是使用被存放在寄存器中的拷贝。因为这个时候寄存器中的拷贝已经很可能和内存处的内容不一致了。

有了上面的知识就不难理解Memory修改描述符了,Memory描述符告知GCC:

1)不要将该段内嵌汇编指令与前面的指令重新排序;也就是在执行内嵌汇编代码之前,它前面的指令都执行完毕

2)不要将变量缓存到寄存器,因为这段代码可能会用到内存变量,而这些内存变量会以不可预知的方式发生改变,因此GCC插入必要的代码先将缓存到寄存器的变量值写回内存,如果后面又访问这些变量,需要重新访问内存。

总结:

KN_SMP_WMB();

#define KN_SMP_WMB() armDmb()

#define armDmb() __asm__ __volatile__ ("" : : : "memory")

主要是保证程序的执行遵循顺序一致性。有的时候你写代码的顺序,不一定是最终执行的顺序,这个是处理器有关的。 之前保存在cache中的内容再次被使用时都需要到这个内存处重新读取。

附:

编译器优化介绍

内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问。另外在现代CPU中指令的执行并不一定 严格按照顺序执行,没有相关性的指令可以乱序执行,以充分利用CPU的指令流水线,提高执行速度。以上是硬件级别的优化。再看软件一级的优化:一种是在编 写代码时由程序员优化,另一种是由编译器进行优化。编译器优化常用的方法有:将内存变量缓存到寄存器;调整指令顺序充分利用CPU指令流水线,常见的是重 新排序读写指令。对常规内存进行优化的时候,这些优化是透明的,而且效率很好。由编译器优化或者硬件重新排序引起的问题的解决办法是在从硬件(或者其他处 理器)的角度看必须以特定顺序执行的操作之间设置内存屏障(memory barrier),Linux 提供了一个宏解决编译器的执行顺序问题。

void Barrier(void)

这个函数通知编译器插入一个内存屏障,但对硬件无效,编译后的代码会把当前CPU寄存器中的所有修改过的数值存入内存,需要这些数据的时候再重新从内存中读出。

SylixOS -- KN_SMP_WMB()内存屏障函数解析相关推荐

  1. JVM内存模型、指令重排、内存屏障概念解析

    在高并发模型中,无是面对物理机SMP系统模型,还是面对像JVM的虚拟机多线程并发内存模型,指令重排(编译器.运行时)和内存屏障都是非常重要的概念,因此,搞清楚这些概念和原理很重要.否则,你很难搞清楚哪 ...

  2. 彻底搞懂内存屏障(上)

    1.从一个示例代码说起 探讨内存屏障的问题基本都会从如下代码作为示例讲解: //假设a和b初始化为0 ,CPU 0执行foo函数,CPU 1执行bar函数.我们再进一步假设a变量 //在CPU 1的c ...

  3. SylixOS内存屏障

    按序执行 vs 乱序执行 在早期处理器中,处理器的指令执行顺序与代码编写顺序是保持一致的,这种执行顺序称为按序执行.但是如果某一条指令需要等待之前指令的执行结果,那么该指令之后的所有的指令均需要等待. ...

  4. 内存拷贝函数memcpy相关解析(C语言)

    memcpy方法解析 内存拷贝函数的一般用法 memcpy()函数的拷贝原理分析 以深浅拷贝为例分析memcpy的拷贝原理 用memcpy()函数与不用memcpy()函数进行拷贝数据的区分 内存拷贝 ...

  5. 全网最硬核 Java 新内存模型解析与实验 - 3. 硬核理解内存屏障(CPU+编译器)

    个人创作公约:本人声明创作的所有文章皆为自己原创,如果有参考任何文章的地方,会标注出来,如果有疏漏,欢迎大家批判.如果大家发现网上有抄袭本文章的,欢迎举报,并且积极向这个 github 仓库 提交 i ...

  6. 解析原理和实战Linux中如何正确地使用内存屏障

    圈里流传着一句话"珍爱生命,远离屏障",这足以说明内存屏障是一个相当晦涩和难以准确把握的东西.使用过弱的屏障,会导致软件不稳定.使用过强的屏障,会引起性能问题.所以工程上,追求恰到 ...

  7. 多核环境下的内存屏障指令

    文件: 内存屏障机制及内核相关源代码分析.pdf 大小: 70KB 下载: 下载 本来不打算立刻写关于这次 软件开发大会 的事情.太多可以写的东西,反而不知道怎么写起.今天才有机会上网到处转转,转到 ...

  8. 搞懂Linux内存屏障(值得收藏)

    1.编译器 编译器将符合人类思考的逻辑(c代码)翻译成了符合CPU运算规则的汇编指令,编译器了解底层CPU的思维模式,因此,它可以在将c翻译成汇编的时候进行优化(例如内存访问指令的重新排序),让产出的 ...

  9. C++ 从双重检查锁定问题 到 内存屏障的一些思考

    文章目录 1. 问题描述 2. DCLP 的问题 和 指令执行顺序 2.1 Volatile 关键字 2.2 C++11 的内存模型 3. C++11内存模型 解决DCLP问题 3.1 内存屏障和获得 ...

  10. # 内存屏障:骇客的硬件视角(1)

    翻译自内存屏障 那么到底是什么让CPU的设计大师们着了魔,要把内存屏障这个鬼东西强行塞给了毫不知情的多处理器系统的软件开发者? 简单点说,就是因为内存访问顺序的重排会带来更好的性能.同步原语的正确操作 ...

最新文章

  1. 3.1 普通型生成函数
  2. 利润中心与其他模块的集成
  3. 随手看的一本书《java微服务》,测试成功了其中的第一个样例
  4. dbcp连接池配置详解_JDBC第四篇【数据库连接池、DbUtils框架、分页】(修订版)
  5. 回顾2007展望2008
  6. Web2.0创业者面临艰难选择:出售还是发展
  7. 安装keil5时,注册机在解压后消失的解决以及使用注册机破解keil5时,无法破解
  8. I2C 总线协议详解
  9. 斗鱼VS虎牙,谁才是直播之王?一文带你看看两家平台 的竞品报告
  10. 回顾备忘—Android系统hal层相关系统粗概
  11. SparkStreaming概述
  12. android 获取邮箱账号,android获取google邮箱
  13. 什么是端口映射?如何设置端口映射?
  14. 湘潭大学信息安全课作业答案4
  15. html5微相册,微信开发 微信H5开发 微信小程序 微报名 微相册 微**
  16. 黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难——讲义
  17. 夺命雷公狗—玩转SEO---52---浅谈人工智能在SEO中的应用之机器学习,内链布局篇...
  18. 【Python】 将图片绘制到Excel表格中
  19. 代码覆盖率工具BullseyeCoverage研究
  20. c++的几个刷题网站(不只有c++)

热门文章

  1. kerberos认证下kafka报错Bootstrap broker host:ip (id: -1 rack: null) disconnected
  2. Android studio开发app实现仿微信滑动切换界面
  3. Docker 中文文档(译)
  4. H26x 编解码 - GOP 模式
  5. mysql默认数据库名_mysql默认数据库
  6. C++函数参数的缺省值
  7. 基于数电的交通灯控制器
  8. oracle 新增字段 影响,Oracle 之 表新增字段后修改字段顺序
  9. 对分法求非线性方程的根
  10. 黑帽SEO的作弊手法: