微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

reactos操作系统实现(15)

ReactOS 里有这么一段初始化代码,如下:

#001 AppcpuInit:

#002 /* Loop until we can release the freeze lock */

#003 do

#004 {

#005 /* Loop until execution can continue */

#006 while (*(volatile PKSPIN_LOCK*)&KiFreezeExecutionLock == (PVOID)1);

#007 } while(InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock,0));

1行是指明开始应用cpu的初始化,主要与引导cpu的初始化区分开来。比如在多核的cpu里,对于操作系统的初始化,只能让一个cpu来工作,不可以多个cpu一起来引导操作系统的,否则就是乱七八糟。也许你会想使用中断来屏蔽中断,但再仔细地一想,使用指令CLI只能关闭其中一个cpu的中断,并没有办法关闭其它cpu的中断响应,因此只能使用自旋锁来解决这个问题。

6代码判断自旋锁KiFreezeExecutionLock是否被其它cpu锁住,如果置为1,表明已经被其它cpu锁住,在这里等到其它cpu释放为止。

7代码调用函数InterlockedBitTestAndSet来设置自旋锁KiFreezeExecutionLock。为了更好地理解自旋锁,有必要来查看这个函数代码,如下:

static __inline__ BOOLEAN

InterlockedBitTestAndSet(IN LONG volatile *Base,

IN LONG Bit)

{

#if defined(_M_IX86)

LONG OldBit;

__asm__ __volatile__("lock "

"btsl %2,%1/n/t"

"sbbl %0,%0/n/t"

:"=r" (OldBit),"+m" (*Base)

:"Ir" (Bit)

: "memory");

return OldBit;

#else

return (_InterlockedOr(Base,1 << Bit) >> Bit) & 1;

#endif

}

上面函数1个参数Base是自旋锁的指针地址,也就是要测试和设置的内存地址。第2个参数Bit是用来说明测试和设置内存地址Base的那一位的值。

lock指令是用来锁住cpu的访问内存的总线,这样只让一个cpu访问内存,达到占有这把锁的唯一性。lock为指令前缀,可以使LOCK引脚变成逻辑0,在LOCK引脚有效期间,禁止外部总线上的其它处理器存取带有LOCK前缀指令的存储器操作数。

"btsl %2,%1这行语句,就是使用btsl指令来把%1地址Base的值)的第%2参数Bit)位拷贝到CF标志上,然后再把把%1地址Base的值)的第%2参数Bit)位设置为1

sbbl %0,%0这行语句,就是指令sbb是带借位减法指令,它利用了CF位上记录的借位值。

指令格式:sbb 操作对象1,操作对象2

功能:操作对象1=操作对象1-操作对象2-CF

按指针的运作,就是%0 - %0 – CF,经过这样运算后放回到%0。如果CF的值为1,那么返回值OldBit的值就是-1。如果CF的值为0,那么返回值OldBit的值就是0。因此返回值就反映了自旋锁内存地址Base的第Bit位的值。

通过上面的分析,可以看到就是先把内存Base地址的指定的位值设置到返回值里,然后再设置相应的值为1。因此这行语句InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock,0),就是把KiFreezeExecutionLock的第0位的值返回,并设置它为1。如果这个函数返回1,表明这个自旋锁有cpu正在使用,继续等待下去,直到这位值返回0为止。当然返回值时,这个函数也已经把这位置为1了,其它cpu读取出来的值永远为1。这样就锁住其它cpu去执行后面的代码

原文地址:https://www.jb51.cc/react/308533.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐