多次读取单个写入会导致Linux字符驱动程序出现死锁?

时间:2015-02-20 19:09:45

标签: linux linux-kernel

我正在开发基于字符设备驱动程序的示例Linux模块(使用misc驱动程序以方便使用),我发现了一些不寻常的行为。

我有文件操作的打开,读取,写入和释放功能,我的misc设备名为test_device

我的设备有一个环形缓冲区,可以存储来自写入系统调用的数据,而读取系统调用可以读取数据。如果缓冲区已满,则调用write系统调用的进程将休眠,如果缓冲区为空,则调用read系统调用的进程将休眠。

有一个信号量(计数1,如互斥量),以避免多次读取,从而避免竞争条件。这对单个读取和单个写入过程没有任何问题,效果很好

现在我使用命令

打开设备作为2个读取实例
cat /dev/test_device 
正如预期的那样,第二个猫进程会睡觉。我有一个编写过程

ls > /dev/test_device

ls命令甚至不会调用open系统调用。任何人都可以向我解释开放系统调用失败的原因。

代码列在下面

static int hr_open(struct inode *inode, struct file *file)
{
    pr_info("process %i (%s) enters open\n", current->pid, current->comm);
    if (file->f_mode & FMODE_READ) down_interruptible(&rd_sem);

    pr_info("process %i (%s) leaves open\n", current->pid, current->comm);

    return 0;
}

static int hr_release(struct inode *inode, struct file *file)
{
    pr_info("process %i (%s) enters release\n", current->pid, current->comm);
    if (file->f_mode & FMODE_READ) up(&rd_sem);

    pr_info("process %i (%s) leaves release\n", current->pid, current->comm);

    return 0;
}

static ssize_t hr_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
    pr_info("process %i (%s) enters read\n", current->pid, current->comm);

    if (wait_event_interruptible(wq_rd, head != tail))
        return -ERESTARTSYS;    

    if (put_user(buff[head], buffer)) 
        return -EFAULT;

    head = (head + 1) % BUFF_SIZE;

    wake_up_interruptible(&wq_wr);
    pr_info("process %i (%s) leaves read\n", current->pid, current->comm);

    return 1;
}

static ssize_t hr_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
    pr_info("process %i (%s) enters write\n", current->pid, current->comm);

    if (wait_event_interruptible(wq_wr, tail != ((head + 1) % BUFF_SIZE)))
        return -ERESTARTSYS;    

    if (get_user(buff[tail], buffer)) 
        return -EFAULT; 

    tail = (tail + 1) % BUFF_SIZE;

    wake_up_interruptible(&wq_rd);
    pr_info("process %i (%s) leaves write\n", current->pid, current->comm);

    return 1;
}

1 个答案:

答案 0 :(得分:0)

我在你的代码中注意到你将信号量锁打开并在发布功能中释放它。我通常不建议在一个函数中持一个锁并释放另一个函数,因为它可能导致锁定问题或死锁。

    static int hr_open(struct inode *inode, struct file *file)
    {
    ...    
        if (file->f_mode & FMODE_READ) down_interruptible(&rd_sem);
    ...
    }

    static int hr_release(struct inode *inode, struct file *file)
    {
     ...

       if (file->f_mode & FMODE_READ) up(&rd_sem);

     ...
    }

我的建议是在读写功能中移动信号量锁(向下和向上)。