预备知识:内核poll钩子原理
内核函数poll_wait
把当前进程加入到驱动里自定义的等待队列上
当驱动事件就绪后,就可以在驱动里自定义的等待队列上唤醒调用poll的进程
故poll_wait作用:可以让驱动知道 事件就绪的时候唤醒哪些等待进程
钩子poll
内核f_op->poll必须配合驱动自己的等待队列才能用,不然驱动有事件产生后不知道哪些进程调用了poll来等待这个事件
内核f_op->poll要做的事情
- 调用
poll_wait
,将当前进程放入驱动设备的等待队列上,这样驱动就知道哪些进程在调用poll
等待事件 - 检查此时立刻已有的事件(
POLLIN\POLLOUT\POLLERR......
)并返回掩码表示
f_op->poll是一个非阻塞的操作,立即返回,返回值以掩码形式表示当前已产生的事件集合
举例
snull驱动的例子:
snull驱动有两个自定义的等待队列:
wait_queue_head_t inq;//读取进程无数据可读时,在此队列等待
wait_queue_head_t outq;//写入进程无空间可写时,在此队列等待
由于snull驱动的读操作read会在读取数据后,唤醒outq队列上的写进程们
且snull驱动的写操作write会在写入数据后,唤醒inq队列上的读进程们
而snull驱动的poll操作:
调用poll_wait将当前进程加入到inq;
调用poll_wait将当前进程加入到outq;
查看当前有什么事件,返回掩码
假设某进程X调用poll,则进程X会出现在inq与outq等待队列上
之后snull写入时,由于将唤醒inq,故调用poll而进入inq的进程X被唤醒
同理,snull读取时,由于将唤醒outq,故调用poll而进入outq的进程X被唤醒
于是,读、写事件唤醒了调用poll
等待事件产生的进程们
白话
进程调用poll
就是希望:事件产生的时候告诉我
而事件E产生的时候,认为其对应的等待队列上的进程是等待E事件的进程,于是会唤醒此等待队列上的进程们
所以进程调用