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

    除了阻塞之外,内核还提供了非阻塞(即轮询)策略.具体的程序表现为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()的补充与优化.




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值