• Nonblock I/O 及其使用


    这是个很有趣的topic,而且这个东东影响到了kernel/driver和application之间的交互。

    首先要来说下这个概念的东东。 当应用程序被block后,这个程序就进入了sleep状态。有可能会block的地方有:

    1. open

    2. read

    3. write

    一般情况下,文件的读写是阻塞的,可以通过fcntl()函数来设置为非阻塞读写。且这一点需要driver的配合 

    好,来看看一个实际的例子的片段。

    driver部分:如果该文件设置了O_NONBLOCK,则直接返回-EAGAIN。

    static ssize_t scull_p_read (struct file *filp, char __user *buf, size_t count,
                    loff_t *f_pos)
    {
        struct scull_pipe *dev = filp->private_data;

        if (down_interruptible(&dev->sem))
            return -ERESTARTSYS;

        while (dev->rp == dev->wp) { /* nothing to read */
            up(&dev->sem); /* release the lock */
            if (filp->f_flags & O_NONBLOCK)
            {
                PDEBUG("nonblock version read\n" );
                return -EAGAIN;
            }
     

            PDEBUG("\"%s\" reading: going to sleep\n", current->comm);
            if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp)))
                return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
            /* otherwise loop, but first reacquire the lock */
            if (down_interruptible(&dev->sem))
                return -ERESTARTSYS;
        }
        /* ok, data is there, return something */
        if (dev->wp > dev->rp)
            count = min(count, (size_t)(dev->wp - dev->rp));
        else /* the write pointer has wrapped, return data up to dev->end */
            count = min(count, (size_t)(dev->end - dev->rp));
        if (copy_to_user(buf, dev->rp, count)) {
            up (&dev->sem);
            return -EFAULT;
        }
        dev->rp += count;
        if (dev->rp == dev->end)
            dev->rp = dev->buffer; /* wrapped */
        up (&dev->sem);

        /* finally, awake any writers and return */
        wake_up_interruptible(&dev->outq);
        PDEBUG("\"%s\" did read %li bytes\n",current->comm, (long)count);
        return count;
    }

    application部分:

    使用fcntl()设置了O_NONBLOCK,这样在read的时候,就会立即返回。

    而且再判断了返回值,EAGAIN表示需要再试。

    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <errno.h>

    char buffer[4096];

    int main(int argc, char **argv)
    {
        int delay = 1, n, m = 0;
        int fd;

        if (argc > 1)
            delay=atoi(argv[1]);
        fd = open("/dev/scullpipe0",O_RDWR );
        fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK); 

        while (1) {
            n = read(fd, buffer, 4096);
            printf("return value from read is %d\n", n);
            if (n >= 0)
                m = write(1, buffer, n); /* stdout */
            if ((n < 0 || m < 0) && (errno != EAGAIN ))
                break;
            sleep(delay);
        }
        perror(n < 0 ? "stdin" : "stdout");
        exit(1);
    }

    大部分转载 小部分自写
  • 相关阅读:
    工厂模式
    日历控件激发的事件(在呈现日时激发)
    在HTML页面里调用CS页面里的全局变量.
    DbDataAdapter填充(Fill)DataSet的情况
    IDataAdapter 接口
    一些HTML的知识!
    HTML页面里给DataGrid控件添加项!
    如何在网页中每小时更新一次数据?
    在windows下编译objectc语言
    Android牟利之道(四)如何推广你的产品,即你的APP
  • 原文地址:https://www.cnblogs.com/8586/p/1935241.html
Copyright © 2020-2023  润新知