这个Linux设备驱动程序代码中是否需要一个螺旋锁?

时间:2015-03-04 19:14:48

标签: linux-kernel linux-device-driver embedded-linux

以下Linux设备驱动程序代码是否安全,或者我是否需要使用自旋锁保护对interrupt_flag的访问?

static DECLARE_WAIT_QUEUE_HEAD(wq_head);
static int interrupt_flag = 0;

static ssize_t my_write(struct file* filp, const char* __user buffer, size_t length, loff_t* offset)
{
   interrupt_flag = 0;   
   wait_event_interruptible(wq_head, interrupt_flag != 0);
}

static irqreturn_t handler(int irq, void* dev_id)
{
   interrupt_flag = 1;
   wake_up_interruptible(&wq_head);
   return IRQ_HANDLED;
}

基本上,我在my_write()中启动一些事件并等待中断以表明它已完成。

如果是,我需要使用哪种形式的spin_lock()?我认为spin_lock_irq()是合适的,但是当我尝试这个时,我收到了关于启用中断的IRQ处理程序的警告。

没有wait_event_interruptible评估interrupt_flag != 0条件吗?这意味着锁定应该在读取标志时保持,对吗?

2 个答案:

答案 0 :(得分:2)

是的,你需要一把锁。使用给定的示例(使用int并且未提及特定的arch),访问interrupt_flag时可能会中断进程上下文。从IRQ返回后,它可能会继续,interrupt_flag可能会处于不一致状态。

试试这个:

static DECLARE_WAIT_QUEUE_HEAD(wq_head);
static int interrupt_flag = 0;
DEFINE_SPINLOCK(lock);

static ssize_t my_write(struct file* filp, const char* __user buffer, size_t length, loff_t* offset)
{
   /* spin_lock_irq() or spin_lock_irqsave() is OK here */
   spin_lock_irq(&lock);
   interrupt_flag = 0;
   spin_unlock_irq(&lock);

   wait_event_interruptible(wq_head, interrupt_flag != 0);
}

static irqreturn_t handler(int irq, void* dev_id)
{
   unsigned long flags;

   spin_lock_irqsave(&lock, flags);
   interrupt_flag = 1;
   spin_unlock_irqrestore(&lock, flags);

   wake_up_interruptible(&wq_head);
   return IRQ_HANDLED;
}

恕我直言,代码必须在不做任何与拱形或编译器相关的假设的情况下编写(如Gil Hamilton回答中的'正确对齐的整数)。

现在,如果我们可以更改代码并使用atomic_t而不是int标志,那么就不需要锁定。

答案 1 :(得分:2)

在给出的示例中不需要锁定。在存储标志之后和加载之前需要内存屏障 - 以确保标志的可见性 - 但wait_event_ *和wake_up_ *函数提供了这些。请参阅本文档中标题为“睡眠和唤醒功能”的部分:https://www.kernel.org/doc/Documentation/memory-barriers.txt

在添加锁之前,请考虑受保护的内容。如果您要设置两个或多个单独的数据,并且需要确保另一个cpu / core没有看到不完整的中间状态(在您启动之后但在完成之前),则通常需要锁定。在这种情况下,保护标志值的存储/加载没有意义,因为正确对齐的整数的存储和加载总是原子的。

因此,根据您的驱动程序正在执行的操作,您很可能需要锁定,但您提供的代码段不需要锁定。