1

我正在监视套接字 fds 的列表并等待 POLLIN 事件。

首先,我将 fds 添加到数组并在该数组上运行 poll()。此外,在某些情况下,我想从这个数组中删除 fd(不关闭)。有时它可能与 poll() 正在运行同时发生。

据我了解,当 poll() 启动时,内核缓存了带有等待 pollfds 的数组,所以它不能知道我立即删除 fd,对吗?

我发现我们可以使用 eventfd() 实现唤醒机制,并使用它来唤醒我们的线程并从数组中删除 fd,然后继续使用新数组运行 poll()。

首先我想问一下,如果我们在 poll() 运行的同时从 pollfds 数组中删除 fd,poll() 是否正确?更要澄清的是,也许有一些不同的机制可以从等待的 pollfds 数组中删除 fd(不包括唤醒机制), poll() 会立即中断吗?

4

1 回答 1

1

系统poll调用首先将用户提供的 fd 列表复制到内核缓冲区,然后再开始检查这些文件的更新。简而言之,这意味着您将无法从并发线程更改 fds 列表,并且如果您写入参数pollfds数组,则在此列表上等待的系统调用不会立即唤醒。

此系统调用的相关代码在do_sys_poll函数中(https://elixir.bootlin.com/linux/v5.11/source/fs/select.c#L970)。这walk是一个缓冲区的内核列表,其中包含用户提供的 fds 列表的副本ufds。在第 987-1008 行的 for 循环期间,内核从ufds. 在此状态之前或期间来自线程的任何并发写入都可以更改walk. 复制之后,内核调用do_poll实际执行系统调用的工作,检查这些 fd 的更新。任何并发到ufds在此期间更新用户空间缓冲区,但不更新内核版本。内核永远不会看到这些更新,因此永远不会忽略您从此列表中“删除”的任何 fd(假设您的意思是将 fd 设置为负数)。

于 2021-06-22T11:05:03.553 回答