如何在linux内核中的列表条目上使用自旋锁?

时间:2010-08-31 14:58:03

标签: linux-kernel spinlock

我正在为linux内核开发一个补丁。我必须使用几个 列表,我必须保护'以防止并发修改 多核机器。我正在尝试使用自旋锁来达到这个目标,但是 有些东西我无法理解。我必须锁定一个条目 list(我正在使用linux默认的链表实现)和它 可能会发生一个进程调用一个系统调用来删除一个元素 列表,而因为某些元素被锁定的相同元素 实际上正在进行修改。如果我插入一个螺旋锁 在列表条目内,如果进程设法删除它会发生什么 有人在上面旋转锁定?我应该锁定整个清单吗? 我正在寻找一段可以解释如何处理这个问题的代码 情况。

例如,此代码不起作用(请参阅最后一行的注释 代码):

   struct lista{
    int c;
    spinlock_t lock;
    struct list_head;
}

spinlock_t list_lock;
struct lista lista;


//INSERT
struct lista* cursor;
struct lista* new = (struct lista*) kmalloc(sizeof(struct lista),GFP_KERNEL);

/*do something*/
spin_lock(&list_lock);     //Lock on the whole list
list_for_each_entry(cursor,&lista.list,list){
    if (cursor->c == something ){
        ...
        spin_unlock(&list_lock)  //unlock
        spin_lock(&cursor->lock) // Lock on list entry
        list_add(&new->list, &lista.list);
        spin_unlock(&cursor->lock)  // unlock of the list entry
        ...
    }
}


//REMOVAL
struct lista* cursor;

spin_lock(&list_lock);  
list_for_each_entry(cursor,&lista.list,list){
    if (cursor->c == something ){
        ...
        spin_unlock(&list_lock)  //unlock
        spin_lock(&cursor->lock) // Lock on list entry
        list_del(&cursor.list,&lista.list);
        spin_unlock(&cursor->lock)  // unlock of the list entry
        kfree(cursor);  //WHEN THE ENTRY IS FREED SOMEONE COULD HAVE TAKEN THE LOCK SINCE IT IS UNLOCKED
        ...
    }
}
你能帮帮我吗?

4 个答案:

答案 0 :(得分:3)

在您删除该项目之前,请勿释放list_lock

你最终可能会遇到一个稍微尴尬的程序:

  1. 获取列表锁定(这将阻止其他传入的线程)
  2. 获取项目锁定,释放项目锁定(这确保所有早期线程都已完成)
  3. 删除项目
  4. 发布清单锁定。
  5. 变体:使用读写器锁进行列表锁定。

    寻找修改列表项的线程会使读取器锁定;这允许多个线程并行地在列表上操作。

    寻找删除列表项的线程采用编写器锁;这等待所有读者退出并阻止它们直到你释放它们。在这种情况下,您仍然必须保持列表锁定,直到您完成删除项目

    通过这种方式,您可以避免上面的第2步。这似乎在概念上更清晰,因为您不需要解释看起来毫无意义的锁定/释放。

答案 1 :(得分:0)

你几乎肯定不应该使用自旋锁,除非有来自硬IRQ上下文的并发访问。改用互斥锁。

列表中最简单的选项就是在操作时锁定整个列表。不要担心每个项目的锁定,除非你发现你需要它的列表锁定有足够的争用(在这种情况下,你可能想要看看使用RCU,无论如何)。

答案 2 :(得分:0)

您的列表头不需要是struct lista,它应该只是struct list_head。请注意,您继续使用&lista.list,这应该只是list_head名为“列表”或其他内容。例如,请参阅drivers/pci/msi.c中的代码,注意dev->msi_list只是list_head,而不是struct msi_desc

您无法安全地删除列表锁定,然后获取光标锁定。删除列表锁定之后但在获得光标锁定之前,可能会有其他人进来并释放光标。你可以玩弄锁,但非常容易出错。

对于整个列表,你几乎肯定只需要一个锁,而且没有每个项锁。除非您需要从中断上下文中操作列表,否则列表锁应该是mutex

答案 3 :(得分:0)

如果你不处理设备和/或内核的关键部分,其中必须使用自旋锁(因为它禁用抢占和中断(根据请求)),那么Y 2使用自旋锁,这将不一定关闭你的先发制人中断。 在列表中使用信号量或互斥量不是列表项看起来更好的解决方案。