内核杂记

来源:互联网 发布:真丝枕巾 知乎 推荐 编辑:程序博客网 时间:2024/05/18 22:55

#define is_power_of_2(x)        ((x) != 0 && (((x) & ((x) -1)) == 0)) 判断是否为2的幂

 

#include <asm/system.h>
"void rmb(void);"
"void wmb(void);"
"void mb(void);"
这些函数在已编译的指令流中插入硬件内存屏障;具体的插入方法是平台相关的。rmb(读内存屏障)保证了屏障之前的读操作一定会在后来的读操作执行之前完wmb 保证写操作不会乱序,mb 指令保证了两者都不会。这些函数都是 barrier函数的超集。解释一下:编译器或现在的处理器常会自作聪明地对指令序列进行一些处理,比如数据缓存,读写指令乱序执行等等。如果优化对象是普通内存,那么一般会提升性能而且不会产生逻辑错误。但如果对I/O操作进行类似优化很可能造成致命错误。所以要使用内存屏障,以强制该语句前后的指令以正确的次序完成。其实在指令序列中放一个wmb的效果是使得指令执行到该处时,把所有缓存的数据写到该写的地方,同时使得wmb前面的写指令一定会在wmb的写指令之前执行。

 

内存屏障
MB(memory barrier,
内存屏障) :x86采用PC(处理机)内存一致性模型,使用MB强加的严格的CPU内存事件次序,保证程序的执行看上去象是遵循顺序一致性(SC)模型,当然,即使对于UP,由于内存和设备见仍有一致性问题,这些Mb也是必须的。在当前的实现中,wmb()实际上是一个空操作,这是因为目前IntelCPU系列都遵循处理机一致性,所有的写操作是遵循程序序的,不会越过前面的读写操作。但是,由于 Intel CPU系列可能会在将来采用更弱的内存一致性模型并且其他体系结构可能采用其他放松的一致性模型,仍然在内核里必须适当地插入wmb()保证内存事件的正确次序。

见头文件include/asm/system.h
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
#define rmb() mb()
#define wmb() __asm__ __volatile__ ("": : :"memory")

此外,barrier实际上也是内存屏障。
include/linux/kernel.h:
#define barrier() __asm__ __volatile__("": : :"memory")
内存屏障也是一种避免锁的技术。
它在进程上下文中将一个元素插入一个单向链表:
new->next=i->next;
wmb();
i->next=new;
同时,如果不加锁地遍历这个单向链表。或者在遍历链表时已经可以看到new,或者new还不在该链表中。Alan Cox书写这段代码时就注意到了这一点,两个内存写事件的顺序必须按照程序顺序进行。否则可能newnext指针将指向一个无效地址,就很可能出现 OOPS!

不论是gcc编译器的优化还是处理器本身采用的大量优化,如Write buffer, Lock-up free, Non-blocking reading, Register allocation, Dynamic scheduling, Multiple issues等,都可能使得实际执行可能违反程序序,因此,引入wmb内存屏障来保证两个写事件的执行次序严格按程序顺序来执行。

原创粉丝点击