Kernel wmb/mb宏的作用

内存屏障主要解决的问题是编译器的优化和CPU的乱序执行。
编译器在优化的时候,生成的汇编指令可能和c语言程序的执行顺序不一样,在需要程序严格按照c语言顺序执行时,需要显式的告诉编译不需要优化,这在linux下是通过barrier()宏完成的,它依靠volidate关键字和memory关键字,前者告诉编译barrier()周围的指令不要被优化,后者作用是告诉编译器汇编代码会使内存里面的值更改,编译器应使用内存里的新值而非寄存器里保存的老值。
同样,CPU执行会通过乱序以提高性能。汇编里的指令不一定是按照我们看到的顺序执行的。linux中通过mb()系列宏来保证执行的顺序。具体做法是通过mfence/lfence指令(它们是奔4后引进的,早期x86没有)以及x86指令中带有串行特性的指令(这样的指令很多,例如linux中实现时用到的lock指令,I/O指令,操作控制寄存器、系统寄存器、调试寄存器的指令、iret指令等等)。简单的说,如果在程序某处插入了mb()/rmb()/wmb()宏,则宏之前的程序保证比宏之后的程序先执行,从而实现串行化。wmb的实现和barrier()类似,是因为在x86平台上,写内存的操作不会被乱序执行。
实际上在RSIC平台上,这些串行工作都有专门的指令由程序员显式的完成,比如在需要的地方调用串行指令,而不像x86上有这么多隐性的带有串行特性指令(例如lock指令)。所以在risc平台下工作的朋友通常对串行化操作理解的容易些。

linux mb()/rmb()/wmb()

在阅读linux 2.6.23内核代码中遇到mb()/rmb()/wmb() 这几个宏,不明白如何使用,

在分析其汇编代码后,大概的了解了这和内存屏障有关,代码如下:

#define X86_FEATURE_XMM2 (032+26) / Streaming SIMD Extensions-2 */

#define mb() alternative(“lock; addl $0,0(%%esp)”, “mfence”, X86_FEATURE_XMM2)
#define rmb() alternative(“lock; addl $0,0(%%esp)”, “lfence”, X86_FEATURE_XMM2)

#ifdef CONFIG_X86_OOSTORE
/* Actually there are no OOO store capable CPUs for now that do SSE,
but make it already an possibility. */
#define wmb() alternative(“lock; addl $0,0(%%esp)”, “sfence”, X86_FEATURE_XMM)
#else
#define wmb() asm volatile ("": : :“memory”)
#endif

/*

  • Alternative instructions for different CPU types or capabilities.
  • This allows to use optimized instructions even on generic binary
  • kernels.
  • length of oldinstr must be longer or equal the length of newinstr
  • It can be padded with nops as needed.
  • For non barrier like inlines please define new variants
  • without volatile and memory clobber.
    /
    #define alternative(oldinstr, newinstr, feature)
    asm volatile (“661:\n\t” oldinstr “\n662:\n”
    “.section .altinstructions,“a”\n”
    " .align 4\n"
    " .long 661b\n" /
    label /
    " .long 663f\n" /
    new instruction /
    " .byte %c0\n" /
    feature bit /
    " .byte 662b-661b\n" /
    sourcelen /
    " .byte 664f-663f\n" /
    replacementlen /
    “.previous\n”
    “.section .altinstr_replacement,“ax”\n”
    “663:\n\t” newinstr “\n664:\n” /
    replacement */
    “.previous” :: “i” (feature) : “memory”)

内存屏障主要解决的问题是编译器的优化和CPU的乱序执行。
编译器在优化的时候,生成的汇编指令可能和c语言程序的执行顺序不一样,在需要程序严格按照c语言顺序执行时,需要显式的告诉编译不需要优化,这在linux下是通过barrier()宏完成的,它依靠volidate关键字和memory关键字,前者告诉编译barrier()周围的指令不要被优化,后者作用是告诉编译器汇编代码会使内存里面的值更改,编译器应使用内存里的新值而非寄存器里保存的老值。
同样,CPU执行会通过乱序以提高性能。汇编里的指令不一定是按照我们看到的顺序执行的。linux中通过mb()系列宏来保证执行的顺序。具体做法是通过mfence/lfence指令(它们是奔4后引进的,早期x86没有)以及x86指令中带有串行特性的指令(这样的指令很多,例如linux中实现时用到的lock指令,I/O指令,操作控制寄存器、系统寄存器、调试寄存器的指令、iret指令等等)。简单的说,如果在程序某处插入了mb()/rmb()/wmb()宏,则宏之前的程序保证比宏之后的程序先执行,从而实现串行化。wmb的实现和barrier()类似,是因为在x86平台上,写内存的操作不会被乱序执行。
实际上在RSIC平台上,这些串行工作都有专门的指令由程序员显式的完成,比如在需要的地方调用串行指令,而不像x86上有这么多隐性的带有串行特性指令(例如lock指令)。所以在risc平台下工作的朋友通常对串行化操作理解的容易些。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值