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

  • 相关阅读:
    【linux]】lighttpd的日志格式
    【vi】awk为指定行的指定字段添加一个单词
    【Android】命令行操作-启动应用程序
    CCS设置第一个li的元素与其他li样式不同
    nginx+tomcat 下POST响应参数过大无法显示完整及文件下载服务遇到过大文件无法下载解决办法
    有重复行,查询时只保留最新一行的sql
    Android定时执行和停止某任务
    MySQL每天自动增加分区
    <html:option获取文本值
    easyui datagrid 增删改查示例
  • 原文地址:https://www.cnblogs.com/flintlovesam/p/5137616.html
Copyright © 2020-2023  润新知