非阻塞(轮询)I/O操作poll()和select()

来源:互联网 发布:雨人软件是什么 编辑:程序博客网 时间:2024/06/08 21:55

    除了阻塞之外,内核还提供了非阻塞(即轮询)策略.具体的程序表现为poll、select和epoll系统调用.上层应用程序最常见的是select()函数.而对应的底层函数即为poll()函数.

1.poll()简介:

    poll()函数原型如下:

unsigned int (*poll)(struct file *filp,poll_table *wait)
    各参数如下:

filp:对应用户空间打开的文件描述符;wait:内核自动填充的,目前"拿来主义"即可.

2.poll()函数的实际使用:

    在驱动实现poll()函数,只需要下面两点即可达到目的:

1).将程序里面的队列头加入wait队列;2).根据实际的设备情况返回掩码.
    其中,第1)步是通过函数poll_wait()实现的.其原型如下:

void poll_wait(struct file *,wait_queue_head_t *,poll_table *);
   第一个参数是用户空间打开的文件描述符;第二个参数是我们驱动自定义的等待队列头;第三个参数内核自动填充.

    上述第2)步对应的掩码见<linux/poll.h>,其掩码对于poll()的调用的意义是返回设备的情况,如数据是否就绪完毕.


3.实例:

    在poll()系统调用中,对应的用户空间的函数一般是select()函数,底层是poll()函数.如下:

    UserSpace:

    ret = select(fd + 1, &rds, NULL, NULL, NULL);    if (ret < 0)    {        printf("select error!\n");        exit(1);    }    if (FD_ISSET(fd, &rds))        read(fd, Buf, sizeof(Buf));
    select()会调用到底层的poll()函数,通过返回的掩码会知道是否有数据可读,如果有数据可读,即进行读数据动作.

    KernelSpace:

unsigned int mem_poll(struct file *filp, poll_table *wait){    struct mem_dev  *dev = filp->private_data;    unsigned int mask = 0;    poll_wait(filp, &dev->inq,  wait);    if (have_data)         mask |= POLLIN | POLLRDNORM;    return mask;}
    可见,驱动里面的poll()实现很清晰分两步走:一是加入wait队列;二是根据具体情况返回相应的掩码.


4.读数据之poll()和read():

    read()函数是比较重要级的函数,当输入缓冲区有数据,就算还不完整完全的数据,read()函数的返回也会有所延迟;当缓冲区没数据时,read()会阻塞,除非设置了O_NONBLOCK,而poll()只是汇报了数据的状态.


5.写数据之poll()和write():

    当写数据的时候,输出缓冲区已满的情况下,write()会阻塞,除非标志了O_NONBLOCK.而poll()会报告文件不可写.


6.poll()的意义:

    poll()比较轻量级,它可以立即向用户空间汇报底层设备的情况,上层可以根据其返回值而对数据的读写时机进行把握,是对write()和read()的补充与优化.