Linux poll机制

一、在用户空间应用程序向驱动程序请求数据时,有以下几种方式:

1.不管查询,条件不满足的情况下就是死循环,非常耗cpu

2.休眠唤醒的方式,如果条件不满足,应用程序则一直睡眠下去

3.poll机制:如果条件不满足,休眠指定的时间,休眠时间内条件满足唤醒,条件一直不满足时间到达自动唤醒

4.异步通知:应用程序注册信号处理函数函数,驱动程序发信号。类似于QT的信号与槽机制

二、函数

2.1.函数原型

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

2.2.事件类型events可以为下列值:

POLLIN:有数据可读
POLLRDNORM:有普通数据可读,等效于POLLIN
POLLRDBAND:有优先数据可读
POLLPRI:有紧迫数据可读
POLLOUT:写数据不会导致阻塞
POLLWRNORM:写普通数据不会导致阻塞
POLLWRBAND:写优先数据不会导致阻塞
POLLMSG:SIGPOLL消息可用
POLLER:指定的文件描述符发生错误
POLLHUP:指定的文件描述符挂起事件
POLLNVAL:无效的请求,打不开指定的文件描述符

2.3.返回值

有事件发生,返回events域不为0的文件描述符个数(也就是说事件发生,或者错误报告),超时返回0,失败返回-1,并设置errno为错误类型

三、linux内核poll实现机制

从应用程序调用poll()函数开始,一直到调用drivers_poll函数,期间的过程很复杂,捡主要的内容列出来:

app:poll

|

drv:sys_poll

|

do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, struct timespec *end_time)

|

poll_initwait(&table);//实际效果:令函数指针table.pt.qproc = __pollwait,这个函数指针最后会传递给poll_wait函数调用中的wait->qproc

|

-do_poll(nfds, head, &table, end_time);

|

_for(;;)

{

    for (;pfd != pfd_end; pfd++) { //可以监测多个驱动设备所产生的事件

        if (do_pollfd(pfd, pt) {

            _mask = file->f_op->poll(file, pwait);//实际效果:执行我们写的drivers_poll(file, pwait)

        })

|

    _poll_wait(file, &button_waitq, wait);//实际效果:执行__pollwait(file, &button_waitq, wait),也就是将进程挂接到button_waitq等待队列下

|

    pollfd->revents = mask; //--mask赋值

    return mask; //将实际事件类型返回

|

count++;

pt = NULL;

}

}

|

if (count || timed_out) //如果有事件发生,或者超时,则跳出poll

break;

if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack)) //如果没有事件发生,那么陷入睡眠状态

timed_out = 1;

}

??由此可见,我们的driver_poll()函数,是系统在执行sys_poll()过程中的一个调用,调用的目的是“将进程挂接到等待队列下”和“返回事件类型mask”。当已经发生了请求事件,那么通过标记mask非0,if(do_pollfd(pfd, pt))判断为真,令count++,从而可以直接令poll()函数成功返回。如果还没有发生请求的事件,那么mask将被标记为0,进程将通过函数poll_schedule_timeout()陷入休眠状态,一旦发生了请求的事件,因为之前已经将进程挂接到等待队列下,所以进程将被唤醒,重新执行drivers_poll(),而显然此时能够成功返回。


版权声明:本文为m0_49328056原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。