曲径通幽论坛

标题: barrier() [打印本页]

作者: beyes    时间: 2010-12-29 22:01
标题: barrier()
定义

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

说明
__volatile__ 告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。

在内嵌汇编中,指令部分为空,输出位置为空,输入位置为空,但它用 memory 强制gcc编译器假设 RAM 所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,cache中的数据用于去优化指令,而避免去访问内存。。这个用法就是防止内存屏障

内核的 kernel/sched.c 中的 context_switch() 函数里有一处用法:

* Here we just switch the register state and the stack. */
switch_to(prev, next, prev);
barrier();
/*
* this_rq must be evaluated again because prev may have moved
* CPUs since it called schedule(), thus the 'rq' on its stack
* frame will be invalid.
*/
finish_task_switch(this_rq(), prev);

context_switch() 函数负责从当前进程切换到另一个进程环境,但当前进程需要修改某些内核数据结构,而这些修改也需要反映到另外一个进程中,因此这里插入 barrier()  ,以保证内存变量和对应的寄存器的一致。

switch_to 代码
#define switch_to(prev,next,last) do {     \
unsigned long esi,edi;      \
asm volatile("pushfl\n\t"  /* Save flags */ \
       "pushl %%ebp\n\t"     \
       "movl %%esp,%0\n\t" /* save ESP */  \
       "movl %5,%%esp\n\t" /* restore ESP */ \
       "movl $1f,%1\n\t"  /* save EIP */  \
       "pushl %6\n\t"  /* restore EIP */ \
       "jmp __switch_to\n"    \
       "1:\t"      \
       "popl %%ebp\n\t"     \
       "popfl"      \
       :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \     
        "=a" (last),"=S" (esi),"=D" (edi)   \
       :"m" (next->thread.esp),"m" (next->thread.eip), \
        "2" (prev), "d" (next));    \
} while (0)




补充:
CPU越过内存屏障后,将刷新自己对存储器的缓冲状态。这条语句(barrier())实际上不生成任何代码,但可使gcc在 barrier()之后刷新寄存器对变量的分配。 也就是说,barrier()宏只约束gcc编译器,不约束运行时的CPU行为。




欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2