zl程序教程

您现在的位置是:首页 >  系统

当前栏目

reactos操作系统实现(15)

操作系统 实现 15 reactos
2023-09-14 09:10:38 时间
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去执行后面的代码。