POLL机制
poll机制:管理多个描述符也是进行轮询,根据描述符的状态进行处理。
poll调用(应用层)
一、应用层:
函数原型:int poll(struct pollfd *fd,nfds_t nfds,int timeout);
函数功能:监视并等待多个文件描述符的属性变化
参数解释:
1、fds:指向一个结构体数组的第0个元素的指针,每个数组元素都是一个struct pollfd结构,用于指定测试某个给定的fd的条件
2、nfds:表示fds结构体数组的长度
3、timeout:表示poll函数的超时时间,单位是毫秒
函数返回值:
1、返回值小于0,表示出错
2、返回值等于0,表示poll函数等待超时
3、返回值大于0,表示poll由于监听的文件描述符就绪返回,并且返回结果就是就绪的文件描述符的个数。
pollfd结构体:
struct pollfd
{
int fd;
short events;
short revents;
}
(1)fd:每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符
(2)events:表示告诉操作系统需要监测fd的时间(输入、输出、错误),每一个时间有多个取值。
(3)revents:revents域是文件描述符的操作结果事件,内核在调用返回时设置这个域。events域中请求的任何事件都可能在revents域中返回。
events&revents的取值如下:
|
|
events |
revents |
事件 |
描述 |
可作为输入 |
可作为输出 |
POLLIN |
数据可读(包括普通数据&优先数据) |
是 |
是 |
POLLOUT |
数据可写(普通数据&优先数据) |
是 |
是 |
POLLRDNORM |
普通数据可读 |
是 |
是 |
POLLRDBAND |
优先级带数据可读(linux不支持) |
是 |
是 |
POLLPRI |
高优先级数据可读,比如TCP带外数据 |
是 |
是 |
POLLWRNORM |
普通数据可写 |
是 |
是 |
POLLWRBAND |
优先级带数据可写 |
是 |
是 |
POLLRDHUP |
TCP连接被对端关闭,或者关闭了写操作,由GNU引入 |
是 |
是 |
POPPHUP |
挂起 |
否 |
是 |
POLLERR |
错误 |
否 |
是 |
POLLNVAL |
文件描述符没有打开 |
否 |
是 |
注意:每个结构体的 events 域是由用户来设置,告诉内核我们关注的是什么,而 revents 域是返回时内核设置的,以说明对该描述符发生了什么事件
二、内核实现:
1. poll > sys_poll > do_sys_poll >poll_initwait,poll_initwait函数注册一下回调函数__pollwait,它就是我们的驱动程序执行poll_wait时,真正被调用的函数。
2. 接下来执行file->f_op->poll,即我们驱动程序里自己实现的poll函数
它会调用poll_wait把自己挂入某个队列,这个队列也是我们的驱动自己定义的;
它还判断一下设备是否就绪。
3. 如果设备未就绪,do_sys_poll里会让进程休眠一定时间
4. 进程被唤醒的条件有2:一是上面说的“一定时间”到了,二是被驱动程序唤醒。驱动程序发现条件就绪时,就把“某个队列”上挂着的进程唤醒,这个队列,就是前面通过poll_wait把本进程挂过去的队列。
5. 如果驱动程序没有去唤醒进程,那么chedule_timeout(__timeou)超时后,会重复2、3动作,直到应用程序的poll调用传入的时间到达。