技术开发 频道

Linux驱动开发必看:详解神秘内核

  旧的信号量接口

  互斥体接口代替了旧的信号量接口(semaphore)。互斥体接口是从-rt树演化而来的,在2.6.16内核中被融入主线内核。

  尽管如此,但是旧的信号量仍然在内核和驱动程序中广泛使用。信号量接口的基本用法如下:

#include <asm/semaphore.h>  /* Architecture dependent header */

/* Statically declare a semaphore. To dynamically
   create a semaphore, use init_MUTEX()
*/
static DECLARE_MUTEX(mysem);

down(
&mysem);    /* Acquire the semaphore */

/* ... Critical Section code ... */

up(
&mysem);      /* Release the semaphore */

  1. 案例1:进程上下文,单CPU,非抢占内核

  这种情况最为简单,不需要加锁,因此不再赘述。

  2. 案例2:进程和中断上下文,单CPU,非抢占内核

  在这种情况下,为了保护临界区,仅仅需要禁止中断。如图2-4所示,假定进程上下文的执行单元A、B以及中断上下文的执行单元C都企图进入相同的临界区。

图2-4 进程和中断上下文进入临界区

  由于执行单元C总是在中断上下文执行,它会优先于执行单元A和B,因此,它不用担心保护的问题。执行单元A和B也不必关心彼此会被互相打断,因为内核是非抢占的。因此,执行单元A和B仅仅需要担心C会在它们进入临界区的时候强行进入。为了实现此目的,它们会在进入临界区之前禁止中断:

Point A:    
  local_irq_disable();  
/* Disable Interrupts in local CPU */
  
/* ... Critical Section ...  */
  local_irq_enable();  
/* Enable Interrupts in local CPU */

   但是,如果当执行到Point A的时候已经被禁止,local_irq_enable()将产生副作用,它会重新使能中断,而不是恢复之前的中断状态。可以这样修复它:

unsigned long flags;

Point A:
  local_irq_save(flags);    
/* Disable Interrupts */
  
/* ... Critical Section ... */
  local_irq_restore(flags);  
/* Restore state to what it was at Point A */

  不论Point A的中断处于什么状态,上述代码都将正确执行。

0
相关文章