使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问,这两个系统调用最终又会引发设备驱动中的poll()函数被执行,所以我们的问题就集中到了如何编写设备驱动中的poll()函数就可以了。先来看看设备驱动中的poll()函数原型:
unsigned int (*poll)(struct file *filp, struct poll_table *wait);
这个函数要进行下面两项工作。首先,对可能引起设备文件状态变化的等待队列调用poll_wait(),将对应的等待队列头添加到poll_table.然后,返回表示是否能对设备进行无阻塞读写访问的掩码。在上面提到了一个poll_wait()函数,它的原型:
void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);
经过以上驱动程序的poll()函数应该返回设备资源的可获取状态,即POLLIN,POLLOUT,POLLPRI,POLLERR,POLLNVAL等宏的位"或"结果.
常量说明
POLLIN普通或优先级带数据可读
POLLRDNORM普通数据可读
POLLRDBAND优先级带数据可读
POLLPRI高优先级数据可读
POLLOUT普通数据可写
POLLWRNORM普通数据可写
POLLWRBAND优先级带数据可写
POLLERR发生错误
POLLHUP发生挂起
POLLNVAL描述字不是一个打开的文件
基于前面阻塞/非阻塞的文章sample中添加poll函数,并重写app测试程序。
fellowmisc.c
#include <linux/poll.h>
unsigned int fellowmisc_poll(struct file *filep, poll_table *wait)
{
unsigned int mask = 0;
struct fellowmisc_dev *devp = (struct fellowmisc_dev*)filep->private_data;
poll_wait(filep, &(devp->inq), wait);//将inq加入到poll_table中。
poll_wait(filep, &(devp->outq), wait);//将outq加入到poll_table中。
if (devp->free > 0)//有空余空间,可写
{
mask |= POLLOUT | POLLWRNORM;
}
if (devp->buffer_size - devp->free > 0)//buffer有数据,可读。
{
mask |= POLLIN | POLLRDNORM;
}
return mask;
}
static const struct file_operations fellowmisc_fops ={
.owner = THIS_MODULE,
.open = fellowmisc_open,
.release = fellowmisc_release,
.unlocked_ioctl = fellowmisc_ioctl,
.read = fellowmisc_read,
.write = fellowmisc_write,
.poll = fellowmisc_poll,
};
app.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include "fellowmisc.h"
int main(int argc, char **argv)
{
int fd = -1;
int ret = 0;
fd_set rfds, wfds;
fd = open("/dev/fellowmisc", O_RDWR);
if (fd < 0)
{
printf("open fail:%s
", strerror(errno));
return -1;
}
while (1)
{
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(fd, &rfds);
FD_SET(fd, &wfds);
select(fd + 1, &rfds, &wfds, NULL, 0);
if (FD_ISSET(fd, &rfds))
{
printf("Device can be read now
");
char readdata[8];
memset(readdata, 0, sizeof(readdata));
if (ret = read(fd, readdata, sizeof(readdata))< 0)
{
printf("read fail:%s
", strerror(errno));
}
else
{
printf("readdata:%s, ret= %d
", readdata, ret);
}
}
if (FD_ISSET(fd, &wfds))
{
printf("Device can be written now
");
char writedata[8] = "abcdefg";
if ((ret = write(fd, writedata, sizeof(writedata)))< 0)
{
printf("write fail:%s
", strerror(errno));
}
else
{
printf("writedata:%s, ret: %d
", writedata, ret);
}
}
}
close(fd);
return 0;
}