scull_p_read()函数分析

 1 /*
 2  * Data management: read and write
 3  */
 4 
 5 static ssize_t scull_p_read (struct file *filp, char __user *buf, size_t count,
 6                 loff_t *f_pos)
 7 {
 8     struct scull_pipe *dev = filp->private_data;
 9 
10     if (down_interruptible(&dev->sem))
11         return -ERESTARTSYS;
12 
13     while (dev->rp == dev->wp) { /* nothing to read */
14         up(&dev->sem); /* release the lock */
15         if (filp->f_flags & O_NONBLOCK)
16             return -EAGAIN;
17         PDEBUG(""%s" reading: going to sleep
", current->comm);
18         if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp)))
19             return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
20         /* otherwise loop, but first reacquire the lock */
21         if (down_interruptible(&dev->sem))
22             return -ERESTARTSYS;
23     }
24     /* ok, data is there, return something */
25     if (dev->wp > dev->rp)
26         count = min(count, (size_t)(dev->wp - dev->rp));
27     else /* the write pointer has wrapped, return data up to dev->end */
28         count = min(count, (size_t)(dev->end - dev->rp));
29     if (copy_to_user(buf, dev->rp, count)) {
30         up (&dev->sem);
31         return -EFAULT;
32     }
33     dev->rp += count;
34     if (dev->rp == dev->end)
35         dev->rp = dev->buffer; /* wrapped */
36     up (&dev->sem);
37 
38     /* finally, awake any writers and return */
39     wake_up_interruptible(&dev->outq);
40     PDEBUG(""%s" did read %li bytes
",current->comm, (long)count);
41     return count;
42 }

while循环在拥有设备信号量时测试缓冲区,所以函数进入之后立即down_interruptible来获取信号量。如果其中有数据,则就不进入while循环,如果其中没有数据,那么进入循环。然后释放信号量,这是因为随后要休眠必须要释放信号量。释放信号量之后,要快速检查用户请求是否是非阻塞IO,如果是那就立刻返回,否则wait_event_interruptible休眠。

当wait_event_interruptible返回那就说明有人已经唤醒我们了,有可能是进程收到一个信号,如果这个没有被阻塞的信号到达了,那就返回-ERESTARTSYS让内核的上层处理这个事件,通常由VFS内部使用,VFS或者重启系统调用,或者返回给用户空间-EINTR。

但是,就算不是信号唤醒的,我们还是无法保证是否有数据可以获得。其他进程可能也在等待数据,而且很可能赢得竞争并拿走了数据。所以我们重新获取了信号量,并让while再次检查是否有数据可读。

如果写指针回绕,那么只读到end就可以了。

原文地址:https://www.cnblogs.com/flintlovesam/p/5137616.html