Linux 为什么我们需要在poll中调用poll\u wait?

Linux 为什么我们需要在poll中调用poll\u wait?,linux,linux-kernel,linux-device-driver,system-calls,epoll,Linux,Linux Kernel,Linux Device Driver,System Calls,Epoll,在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 rig

在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不会等,会马上回来。那我们为什么要叫它?为什么我们不能返回掩码?

poll\u wait将您的设备(由“结构文件”表示)添加到可以唤醒进程的设备列表中

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

然后核心内核在一个地方阻塞进程。这样,任何一个设备都可以唤醒进程。如果返回非零掩码位,则意味着这些“就绪”属性(可读/可写/etc)现在适用

因此,在伪代码中,大致如下所示:

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\u wait触发此类事件,可以在注册文件描述符以轮询fd时对其进行配置。

如果返回
0
将休眠

这就是让我困惑的地方

当您返回非零时,表示触发了某个事件,并且该事件被唤醒

一旦您看到这一点,很明显,一定有什么东西将进程绑定到等待队列,这就是
poll\u wait

还要记住,
struct file
表示“进程和打开文件之间的连接”,而不仅仅是文件系统文件,因此它包含用于标识进程的pid


使用最小的可运行示例也可能有助于澄清问题:

那么进程何时休眠?您的意思是,来自用户空间的轮询调用将阻止进程,对吗?是的。当您在用户空间中调用poll(2)时,会转到内核中名为“sys_poll”的函数(请参阅内核源代码中的fs/select.c)。同样,select(2)=>sys\u select等。所有这些函数或多或少都遵循我上面给出的伪代码。我有一个问题:wait\u queue\u head\t做什么?无效轮询等待(结构文件*,等待队列头*,轮询表*);它是一种数据结构,锚定“等待进程”队列的头部(在此设备内)。因此,如果出现一个中断,该中断传递数据(用于读取)或释放空间(用于写入),设备可以通知核心内核,队列上的任何等待进程都可以被唤醒(这将导致每个进程被解锁[计划运行]从而导致从select/poll系统调用返回用户空间(队列中的进程被阻塞)。这是完全错误的<代码>轮询等待
根本不会“触发”。它只是将等待队列添加到
poll\u表中