• 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就可以了。

  • 相关阅读:
    浅析Java CompletionService
    经验总结13--EF配置
    消息摘要算法-HMAC算法
    03012_预处理对象executeQuery方法(实现数据库的查询)
    GO学习笔记:函数defer
    GO学习笔记:函数传值与传指针
    GO学习笔记:函数作为值、类型
    GO学习笔记:函数Panic和Recover
    GO学习笔记:import
    GO学习笔记:struct类型
  • 原文地址:https://www.cnblogs.com/flintlovesam/p/5137616.html
Copyright © 2020-2023  润新知