zoukankan      html  css  js  c++  java
  • 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就可以了。

  • 相关阅读:
    【leetcode】Sum Root to Leaf Numbers(hard)
    【leetcode】First Missing Positive(hard) ☆
    【leetcode】Next Permutation(middle)
    【好玩的应用】QQ连连看辅助工具
    【leetcode】Binary Tree Preorder Traversal (middle)★
    【leetcode】Reverse Words in a String(hard)☆
    【leetcode】Same Tree(easy)
    【leetcode】Factorial Trailing Zeroes(easy)
    【leetcode】Maximum Gap(hard)★
    Behavioral模式之Chain of Responsibility模式
  • 原文地址:https://www.cnblogs.com/flintlovesam/p/5137616.html
Copyright © 2011-2022 走看看