一、用户空间的poll和select测试函数
在使用者两个函数之前,需要先安装scullpipe设备,下面是他们的测试代码和注释:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/poll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
int fd0, fd1, fd2, fd3;
struct pollfd poll_fd[4];
char buf[100];
int retval;
/*如果没有指定参数,或者参数不等于read和wtite,打印提示信息*/
if(argc != 2 || ((strcmp(argv[1], "read") != 0) && (strcmp(argv[1], "write") != 0)))
{
printf("usage: ./poll_test read|write\n");
return -1;
}
fd0 = open("/dev/scullpipe0", O_RDWR); //打开设备scullpipe0
if ( fd0 < 0)
{
printf("open scullpipe0 error\n");
return -1;
}
fd1 = open("/dev/scullpipe1", O_RDWR); //打开设备scullpipe1
if ( fd1 < 0)
{
printf("open scullpipe1 error\n");
return -1;
}
fd2 = open("/dev/scullpipe2", O_RDWR); //打开设备scullpipe2
if ( fd2 < 0)
{
printf("open scullpipe2 error\n");
return -1;
}
fd3 = open("/dev/scullpipe3", O_RDWR); //打开设备scullpipe3
if ( fd3 < 0)
{
printf("open scullpipe3 error\n");
return -1;
}
if(strcmp(argv[1], "read") == 0) //如果是read
{
poll_fd[0].fd = fd0;
poll_fd[1].fd = fd1;
poll_fd[2].fd = fd2;
poll_fd[3].fd = fd3;
poll_fd[0].events = POLLIN | POLLRDNORM; //检查是否可读,一般为固定搭配
poll_fd[1].events = POLLIN | POLLRDNORM;
poll_fd[2].events = POLLIN | POLLRDNORM;
poll_fd[3].events = POLLIN | POLLRDNORM;
retval = poll(poll_fd, 4, 10000); //监测poll_fd数组里面的4个文件,并设置超时时间为10,000毫秒
}
else
{
poll_fd[0].fd = fd0;
poll_fd[1].fd = fd1;
poll_fd[2].fd = fd2;
poll_fd[3].fd = fd3;
poll_fd[0].events = POLLOUT | POLLWRNORM; //检查是否可写
poll_fd[1].events = POLLOUT | POLLWRNORM;
poll_fd[2].events = POLLOUT | POLLWRNORM;
poll_fd[3].events = POLLOUT | POLLWRNORM;
retval = poll(poll_fd, 4, 10000);
}
if (retval == -1) //poll返回一个负数,说明poll调用出错
{
printf("poll error!\n");
return -1;
}
else if (retval) //poll函数如果返回一个正数,代表内核返回了状态(保存在pollfd.revents中)的文件描述符的个数
{
if(strcmp(argv[1], "read") == 0)
{
if(poll_fd[0].revents & (POLLIN | POLLRDNORM))
{
printf("/dev/scullpipe0 is readable!\n");
memset(buf, 0, 100);
read(fd0, buf, 100);
printf("%s\n", buf);
}
if(poll_fd[1].revents & (POLLIN | POLLRDNORM))
{
printf("/dev/scullpipe1 is readable!\n");
memset(buf, 0, 100);
read(fd1, buf, 100);
printf("%s\n", buf);
}
if(poll_fd[2].revents & (POLLIN | POLLRDNORM))
{
printf("/dev/scullpipe2 is readable!\n");
memset(buf, 0, 100);
read(fd2, buf, 100);
printf("%s\n", buf);
}
if(poll_fd[3].revents & (POLLIN | POLLRDNORM))
{
printf("/dev/scullpipe3 is readable!\n");
memset(buf, 0, 100);
read(fd3, buf, 100);
printf("%s\n", buf);
}
}
else
{
if(poll_fd[0].revents & (POLLOUT | POLLWRNORM))
{
printf("/dev/scullpipe0 is writable!\n");
}
if(poll_fd[1].revents & (POLLOUT | POLLWRNORM))
{
printf("/dev/scullpipe1 is writable!\n");
}
if(poll_fd[2].revents & (POLLOUT | POLLWRNORM))
{
printf("/dev/scullpipe2 is writable!\n");
}
if(poll_fd[3].revents & (POLLOUT | POLLWRNORM))
{
printf("/dev/scullpipe3 is writable!\n");
}
}
}
else //如果poll返回0,表明是因为超时而返回的
{
if(strcmp(argv[1], "read") == 0)
{
printf("No data within ten seconds.\n");
}
else
{
printf("Can not write within ten seconds.\n");
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
fd_set rfds, wfds;
int fd0, fd1, fd2, fd3;
char buf[100];
int retval;
/* Wait up to ten seconds. */
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;
if(argc != 2 || ((strcmp(argv[1], "read") != 0) && (strcmp(argv[1], "write") != 0)))
{
printf("usage: ./select_test read|write\n");
return -1;
}
fd0 = open("/dev/scullpipe0", O_RDWR);
if ( fd0 < 0)
{
printf("open scullpipe0 error\n");
return -1;
}
fd1 = open("/dev/scullpipe1", O_RDWR);
if ( fd1 < 0)
{
printf("open scullpipe1 error\n");
return -1;
}
fd2 = open("/dev/scullpipe2", O_RDWR);
if ( fd2 < 0)
{
printf("open scullpipe2 error\n");
return -1;
}
fd3 = open("/dev/scullpipe3", O_RDWR);
if ( fd3 < 0)
{
printf("open scullpipe3 error\n");
return -1;
}
if(strcmp(argv[1], "read") == 0)
{
FD_ZERO(&rfds);
FD_SET(fd0, &rfds);
FD_SET(fd1, &rfds);
FD_SET(fd2, &rfds);
FD_SET(fd3, &rfds);
retval = select(fd3 + 1, &rfds, NULL, NULL, &tv);
}
else
{
FD_ZERO(&wfds);
FD_SET(fd0, &wfds);
FD_SET(fd1, &wfds);
FD_SET(fd2, &wfds);
FD_SET(fd3, &wfds);
retval = select(fd3 + 1, NULL, &wfds, NULL, &tv);
}
if (retval == -1)
{
printf("select error!\n");
return -1;
}
else if (retval)
{
if(strcmp(argv[1], "read") == 0)
{
if(FD_ISSET(fd0, &rfds))
{
printf("/dev/scullpipe0 is readable!\n");
memset(buf, 0, 100);
read(fd0, buf, 100);
printf("%s\n", buf);
}
if(FD_ISSET(fd1, &rfds))
{
printf("/dev/scullpipe1 is readable!\n");
memset(buf, 0, 100);
read(fd1, buf, 100);
printf("%s\n", buf);
}
if(FD_ISSET(fd2, &rfds))
{
printf("/dev/scullpipe2 is readable!\n");
memset(buf, 0, 100);
read(fd2, buf, 100);
printf("%s\n", buf);
}
if(FD_ISSET(fd3, &rfds))
{
printf("/dev/scullpipe3 is readable!\n");
memset(buf, 0, 100);
read(fd3, buf, 100);
printf("%s\n", buf);
}
}
else
{
if(FD_ISSET(fd0, &wfds))
{
printf("/dev/scullpipe0 is writable!\n");
}
if(FD_ISSET(fd1, &wfds))
{
printf("/dev/scullpipe1 is writable!\n");
}
if(FD_ISSET(fd2, &wfds))
{
printf("/dev/scullpipe2 is writable!\n");
}
if(FD_ISSET(fd3, &wfds))
{
printf("/dev/scullpipe3 is writable!\n");
}
}
}
else
{
if(strcmp(argv[1], "read") == 0)
{
printf("No data within ten seconds.\n");
}
else
{
printf("Can not write within ten seconds.\n");
}
}
return 0;
}
下面是测试结果图:
二、驱动程序的poll
用户空间的poll和select都会调用到驱动程序的poll,下面是scullpipe驱动程序的poll实现
/*****************************************************************************************/
/*poll函数应该实现两个功能:
一是把能标志轮询状态变化的等待队列加入到poll_table中,这通过调用poll_wait函数实现。
二是返回指示能进行的I/O操作的标志位。
poll函数的第二个参数poll_table,是内核中用来实现poll,select系统调用的结构体,对于驱动开发者来说,
不必关心其具体内容,可以把poll_table看成是不透明的结构体,只要拿过来使用就可以了。驱动程序通过poll_wait函数,
把能够唤醒进程,改变轮询状态的等待队列加入到poll_table中。该函数定义如下:
void poll_wait (struct file *, wait_queue_head_t *, poll_table *);
对于poll函数的第二个功能,返回的标志位与用户空间相对应,最常用的标志位是POLLIN | POLLRDNORM和POLLOUT | POLLWRNORM,
分别标志可进行非阻塞的读和写操作。*/
/*******************************************************************************************/
static unsigned int scull_p_poll(struct file *filp, poll_table *wait)
{
struct scull_pipe *dev = filp->private_data;
unsigned int mask = 0;
/*
* The buffer is circular; it is considered full
* if "wp" is right behind "rp" and empty if the
* two are equal.
*/
down(&dev->sem);
/*调用poll_wait函数将读等待队列加入到poll_table中*/
poll_wait(filp, &dev->inq, wait);
/*调用poll_wait函数将写等待队列加入到poll_table中*/
poll_wait(filp, &dev->outq, wait);
/*如果有内容可读,设置可读标志位**/
if (dev->rp != dev->wp)
mask |= POLLIN | POLLRDNORM; /* readable */
if (spacefree(dev))
/*如果有空间可写,设置可写标志位*/
mask |= POLLOUT | POLLWRNORM; /* writable */
up(&dev->sem);
/*将标志位返回*/
return mask;
}
参考博客:http://blog.csdn.net/liuhaoyutz/article/details/7401418