Linux 为什么我们需要在poll中调用poll\u wait?
在LDD3中,我看到了这样的代码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
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表中
。