在操作IO设备时,读取设备状态或者数据时,如果采用轮询方式,会占用大量的CPU资源,这种方式肯定是不可取,所以需要在内核驱动支持异步通知方式,等到设备准备好,再通知应用程序,其他时间应用程序应当处于休眠状态,让出CPU。本篇介绍poll的使用方法。
1)首先定义一个wait_queue_head_t,并对其进行初始化
struct xxx_dev{
wait_queue_head_t irq_wq;
struct mutex mutex;
int flag;
}
struct xxx_dev *dev;
//在设备初始化时,对等待队列头以及互斥信号量进行初始化
init_waitqueue_head(&dev->irq_wq);
mutex_init(&dev->mutex);
2)实现poll函数
static unsigned int xdma_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
struct xxx_dev *dev= (struct xxx_dev *)file->private_data;
mutex_lock(&dev->mutex);
wait_event_interruptible(dev->irq_wq, dev->flag != 0);
poll_wait(file, &dev->irq_wq, wait);
if (dev->flag == 1 )
{
mask |= POLLIN | POLLRDNORM;
}
mutex_unlock(&dev->mutex);
return mask;
}
3)在中断或者需要唤醒等待队列时:
wake_up_interruptible(&dev->irq_wq);
应用程序在使用时,可以有多种方式:select,poll,epoll。select和poll功能和实现原理相似。当多路复用的文件数量比较庞大。io流量频繁时,一般不太适合使用select()和poll(),此种情况下select()和poll()的性能较差,比较适合使用epoll。epoll的最大好处是不会随着fd数目增长而降低效率,select()会随着fd的数量增大性能下降明显。
1)select:
fd_set rfds;
while (1)
{
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
select(fd + 1, &rfds, NULL, NULL, NULL);
if (FD_ISSET(fd, &rfds))
{
...
}
}
2)poll:
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN; //请求类型是 普通或优先级带数据可读
while (1)
{
int ret = poll(&fds, 1, 10000); //一个poll, 定时5000ms,进入休眠状态
if (ret == 0) //超时
{
printf("time out \r\n");
}
else if (ret > 0) //poll机制被唤醒,表示有数据可读
{
...
}
}