poll机制
所有的系统调用,基于都可以在它的名字前加上“sys_”前缀,这就是它在内核中对应的函数。比如系统调用open、read、write、poll,与之对应的内核函数为:sys_open、sys_read、sys_write、sys_poll。
对于系统调用poll或select,它们对应的内核函数都是sys_poll。分析sys_poll,即可理解poll机制。
执行过程:
poll > sys_poll > do_sys_poll > poll_initwait
1.do_sys_poll函数位于fs/select.c文件中
do_sys_poll中有个循环for(;;){
...}
退出循环的条件是:(count非0,超时、有信号等待处理)
1.count非0---在do_pollfd函数中:调用驱动中的poll函数,驱动程序中的Poll函数的工作 有两个,一个就是调用poll_wait 函数,把进程挂到等待队列中去,另一个是确定相关的fd是否有内容可 读,如果可读,就返回1,否则返回0,如果返回1 ,do_poll函数中的count++。
2.超时:让本进程休眠一段时间,注意:应用程序执行poll调用后,如果条件不满足,进程就会进入休眠。休眠到指定时间被系统唤醒。
3.有信号等待处理:(未懂)
驱动中:
static unsigned drv_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; poll_wait(file, &button_waitq, wait); // 不会立即休眠--把进程挂到队列当中 if (ev_press) mask |= POLLIN | POLLRDNORM; return mask; //若返回0则进行休眠 }
file_operations:
.poll = drv_poll,
中断内:
ev_press = 1; /* 表示中断发生了 */
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
测试程序中:
int main(int argc, char **argv) { int fd; unsigned char key_val; int ret; struct pollfd fds[1]; fd = open("/dev/buttons", O_RDWR); if (fd < 0) { printf("can't open!\n"); } fds[0].fd = fd; fds[0].events = POLLIN; //普通或优先级带数据可读 while (1) { ret = poll(fds, 1, 5000); //用poll机制定时5000ms,超时唤醒 if (ret == 0) // ret==mask { printf("time out\n"); 每5000ms输出一次 } else { read(fd, &key_val, 1); printf("key_val = 0x%x\n", key_val); } } return 0; }
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
参数说明:
fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;
timeout:是poll函数调用阻塞的时间,单位:毫秒;
struct pollfd {
int fd; /*文件描述符*/
short events; /* 等待的需要测试事件 */
short revents; /* 实际发生了的事件,也就是返回结果 */
};
与select()十分相似,当返回正值时,代表满足响应事件的文件描述符的个数,如果返回0则代表在规定时间内没有事件发生。如发现返回为负则应该立即查看 errno,因为这代表有错误发生。
如果没有事件发生,revents会被清空,所以你不必多此一举。
poll函数可用的测试值:
常量
|
说明
|
POLLIN
|
普通或优先级带数据可读
|
POLLRDNORM
|
普通数据可读
|
POLLRDBAND
|
优先级带数据可读
|
POLLPRI
|
高优先级数据可读
|
POLLOUT
|
普通数据可写
|
POLLWRNORM
|
普通数据可写
|
POLLWRBAND
|
优先级带数据可写
|
POLLERR
|
发生错误
|
POLLHUP
|
发生挂起
|
POLLNVAL
|
描述字不是一个打开的文件
|
例如fds[0].events = POLLIN; /*将测试条件设置成普通或优先级带数据可读*/
然后 int pollresult = poll(fds,xx,xx); //这样就可以监听fds里面文件描述符了,当满足特定条件就返回,并将结果保存在revents中。