linux wake_up_interruptible() having no effect



我正在为操作系统类编写一个"昏昏欲睡"的设备驱动程序。

它的工作方式是,用户通过read()/write()访问设备。当用户像这样向设备写入:write(fd, &wait, size)时,设备将休眠wait值的以秒为单位的时间。如果等待时间到期,则驱动程序的写入方法返回0,程序结束。但是,如果用户在进程睡眠在等待队列上时从驱动程序中读取,那么驱动程序的写入方法会立即返回,返回的是睡眠进程在超时发生之前等待的秒数。

另一个问题是创建了该设备的10个实例,并且这10个设备中的每一个都必须彼此独立。因此,对设备1的读取必须只唤醒设备1上的休眠进程。

已经提供了很多代码,我主要负责为驱动程序编写read()write()方法。

我试图解决保持设备相互独立的问题的方法是包括两个大小为10的全局静态阵列。类型wait_head_queue_t之一和类型Int之一(布尔标志)。当我通过open()打开设备时,这两个阵列都会初始化一次。问题是,当我调用wake_up_interruptible()时,什么都没有发生,并且程序在超时时终止。这是我的写作方法:

ssize_t sleepy_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){
struct sleepy_dev *dev = (struct sleepy_dev *)filp->private_data;
ssize_t retval = 0;
int mem_to_be_copied = 0;
if (mutex_lock_killable(&dev->sleepy_mutex))  
{ 
return -EINTR; 
}
// check size
if(count != 4)  // user must provide 4 byte Int
{
return EINVAL; // = 22
}
//  else if the user provided valid sized input...
else
{
if((mem_to_be_copied = copy_from_user(&long_buff[0], buf, count))) 
{ 
return -EFAULT; 
}
// check for negative wait time entered by user
if(long_buff[0] > -1)// "long_buff[]"is global,for now only holds 1 value
{
proc_read_flags[MINOR(dev->cdev.dev)] = 0;  //****** flag array
retval = wait_event_interruptible_timeout(wqs[MINOR(dev->cdev.dev)],   proc_read_flags[MINOR(dev->cdev.dev)] == 1, long_buff[0] * HZ) / HZ;
proc_read_flags[MINOR(dev->cdev.dev)] = 0; // MINOR numbers for each
// device correspond to array indices 
// devices 0 - 9
// "wqs" is array of wait queues
}
else
{
printk(KERN_INFO "user entered negative value for sleep timen");
}
}
mutex_unlock(&dev->sleepy_mutex);
return retval;}

与本主题中的许多示例不同,我在调用wait_event_interruptible_timeout()之前立即将标志切换回零,因为标志值似乎在程序的后续运行之间徘徊。这是我阅读方法的代码:

ssize_t sleepy_read(struct file *filp, char __user *buf, size_t count, 
loff_t *f_pos){
struct sleepy_dev *dev = (struct sleepy_dev *)filp->private_data;
ssize_t retval = 0;
if (mutex_lock_killable(&dev->sleepy_mutex))
return -EINTR;
// switch the flag
proc_read_flags[MINOR(dev->cdev.dev)] = 1; // again device minor numbers
// correspond to array indices 
// TODO:   this is not waking up the process in write!
// wake up the queue
wake_up_interruptible(&wqs[MINOR(dev->cdev.dev)]);
mutex_unlock(&dev->sleepy_mutex);
return retval;}

我尝试测试程序的方式是有两个主.c,一个用于向设备写入,另一个用于从设备读取,我只是在虚拟盒子中的ubuntu安装中的单独控制台中./a.out它们。另一件事是,按照现在的设置方式,在超时发生之前,写入或读取a.outs都不会返回。我为代码的格式参差不齐而道歉。我不知道这里到底发生了什么,所以任何帮助都将不胜感激!谢谢

您的写入方法在等待事件时保持sleepy_mutex。因此,read方法在mutex_lock_killable(&dev->sleepy_mutex)上等待,而互斥对象被写入程序解锁。只有当写入程序的超时超过,并且写入方法返回时,才会发生这种情况。这是你观察到的行为。

通常,wait_event*在任何关键部分之外执行。这可以通过使用此类宏的_lock后缀变体来实现,或者简单地用spinlock获取/释放对包装此类宏的cond参数:

int check_cond()
{
int res;
spin_lock(&lock);
res = <cond>;
spin_unlock(&lock);
return res;
}
...
wait_event_interruptible(&wq, check_cond());

不幸的是,当条件检查应该用互斥锁保护时,不能使用wait_event-家族宏。在这种情况下,您可以将wait_wake()函数与手动条件检查代码一起使用。或者重写您的代码,而不需要围绕条件检查进行互斥锁/解锁。

为了实现"如果是睡眠,读者唤醒作者"功能,您可以采用该答案中的代码https://stackoverflow.com/a/29765695/3440745.

书写器代码:

//Declare local variable at the beginning of the function
int cflag;
...
// Outside of any critical section(after mutex_unlock())
cflag = proc_read_flags[MINOR(dev->cdev.dev)];
wait_event_interruptible_timeout(&wqs[MINOR(dev->cdev.dev)],
proc_read_flags[MINOR(dev->cdev.dev)] != cflag, long_buff[0]*HZ);

读卡器代码:

// Mutex holding protects this flag's increment from concurrent one.
proc_read_flags[MINOR(dev->cdev.dev)]++;
wake_up_interruptible_all(&wqs[MINOR(dev->cdev.dev)]);

最新更新