谈起内存屏障,大家感觉这个"玩意儿"很虚,不太实际,但是内核代码中又广泛地可以看到起身影。内存屏障,英文barrier,这个"玩意儿"它还不太好去定义它。barrier,中文翻译为栅栏,栅栏大家都见过,现实生活中就是防止他人或者动物非法闯入而用来进行隔离用的工具。再进一步,既然是防止闯入,那就是要保护栅栏内的东西。所以在linux 内核中,内存屏障用于保护内存的访问。
1、什么需要保护
下面来谈谈内存屏障到底保护什么。
比如cpu0执行 a = 1 这条指令时,假设a所在cache line已经在cpu1的 L1 cache中,cpu0 先要获取a所在的cache line到cpu0的L1cache中,由于是写操作,需要改写a的值,需要再总线上发送invalid消息让其他cpu使无效其cache中a的值,等待其他cpu应答后,cpu0才能改写a的值,这样才能保证cache一致性。
等待其他cpu上使无效消息的应答期间造成了cpu0的无效等待,浪费时间。于是cpu设计者开始修改CPU设计,出现了使无效队列以及write buffer这些内部部件用来加速cpu的执行。具体内容读者可以查阅其他文章。
提升CPU执行效率(硬件层面)和编译器的优化使得指令重排序(软件层面)给程序员带来了负担,需要程序去进行进行内存访问顺序的维护及保序。
2、ARM提供的指令
ARM提供了如下指令来进行内存屏障的处理:
DMB:Data Memory Barrier,数据存储屏障
DSB:Date Synchronization Barrier,数据同步屏障
ISB:Instruction Synchronization Barrier,指令同步屏障
DMB和DSB的一个本质区别,DMB针对的是memory的load/store之间;DSB强调的是同类或不同类事物的先后完成。
Data Memory Barrier (DMB) ensures that all explicit memory accesses that appear in program order before the DMB instruction are observed
before any explicit memory accesses that appear in program order after the DMB instruction.
数据内存屏障(DMB)确保DMB指令之前的所有显式内存访问在DMB指令开始之后的任何显式内存访问之前被观察到。且DMB指令不影响处理上执行的任何其他指令的顺序。
Data Synchronization Barrier (DSB),No instruction in program order after this instruction executes until this instruction completes.
数据同步屏障(DSB)完成后,其后面的指令才可执行。可见DSB影响了其他指令的执行。
Instruction Synchronization Barrier (ISB) flushes the pipeline in the processor, so that all instructions following the ISB are fetched from cache or memory,
after the instruction has been completed.
指令同步屏障(ISB)冲刷处理器中的流水线,以便在ISB完成后,从缓存或内存中提取ISB之后的所有指令。可见ISB严重影响后续指令的执行。
3、linux内核实现
arch/arm/include/asm/barrier.h/*isb,dsb,dmb汇编指令*/
#define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory")
#define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory")
#define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory")/*barrier:编译优化屏障,阻止编译器为了性能优化而进行指令重排*/
#define barrier() __asm__ __volatile__("": : :"memory")/*内存屏障(包括读和写),用于SMP和UP*/
#define mb() do { dsb(); outer_sync(); } while (0)
/*读内存屏障,用于SMP和UP*/
#define rmb() dsb()
/*写内存屏障,用于SMP和UP*/
#define wmb() do { dsb(st); outer_sync(); } while (0)/*osh:outer shareable domain*/
#define dma_rmb() dmb(osh)
#define dma_wmb() dmb(oshst)/*用于SMP场合的内存屏障。*/
/*ish:inner shareable domain,在ish范围内客观测到结果*/
#define smp_mb() dmb(ish)
/*用于SMP场合的读内存屏障*/
#define smp_rmb() smp_mb()
/*用于SMP场合的写内存屏障*/
/*waits only for stores to complete, and only to the inner shareable domain.*/
#define smp_wmb() dmb(ishst)