为什么我们需要在 poll 中调用 poll_wait?

Why do we need to call poll_wait in poll?

在LDD3中,我看到了这样的代码

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(filp, &dev->inq,  wait);
    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;
}

但它说 poll_wait 不会等待,会 return 立即。那为什么我们需要调用它呢?为什么我们不能 return 面具?

poll_wait 将您的设备(由 "struct file" 表示)添加到可以唤醒进程的设备列表中。

这个想法是进程可以使用 poll(或 select 或 epoll 等)将一堆文件描述符添加到它希望等待的列表中。调用每个驱动程序的轮询条目。每个人都将自己(通过 poll_wait)添加到服务员名单中。

然后核心内核在一个地方阻塞进程。这样,任何一个设备都可以唤醒进程。如果您 return 非零掩码位,则意味着那些 "ready" 属性 (readable/writable/etc) 适用 now.

所以,在伪代码中,大致是这样的:

foreach fd:
    find device corresponding to fd
    call device poll function to setup wait queues (with poll_wait) and to collect its "ready-now" mask

while time remaining in timeout and no devices are ready:
    sleep

return from system call (either due to timeout or to ready devices)

poll_wait 在它正在等待的任何 fd 上发生预期事件或超时时触发。

检查掩码以了解触发了哪个事件poll_wait。如果你不想poll_wait触发这样的事件,你可以在注册文件描述符时配置它来轮询fd。

如果你return0

pollfile_operation就会睡觉

这就是让我困惑的地方。

当你 return 非零时,这意味着某个事件被触发,它被唤醒。

一旦你看到这个,很明显一定是有什么东西把进程绑在了等待队列上,那就是 poll_wait

还要记住 struct file 代表 "a connection between a process and an open file",而不仅仅是文件系统文件,因此它包含用于识别进程的 pid。

玩一个最小的可运行示例也可能有助于解决问题: