【发布时间】:2021-07-19 21:43:44
【问题描述】:
我想向现有的 epoll 实例添加一个文件描述符,但还没有唤醒它。具体来说,我想确保不会引发 EPOLLERR 和 EPOLLHUP。我使用EPOLLONESHOT 一次唤醒一个线程,然后在处理完事件后使用EPOLL_CTL_MOD 重新武装。
(我的动机是使用相同的代码路径来处理唤醒和创建新套接字:它们都可以通过调用 epoll_ctl 和 EPOLL_CTL_MOD 来重新武装事件来完成。但是,我不如果在EPOLL_CTL_MOD 之前的套接字中发生错误,则需要一个虚假的线程唤醒)。
根据manpage,这是不可能的。 EPOLLERR 和 EPOLLHUP 都声称:
epoll_wait(2) 会一直等待这个事件;调用 epoll_ctl() 时不必在事件中设置。
但是,在查看 Linux 源代码树中的 eventpoll.c 之后,看起来如果没有设置“公共”events 位,则唤醒被抑制。 (原文中的块 cmets;行 cmets 是我的笔记。)
/* Epoll private bits inside the event mask */
#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET | EPOLLEXCLUSIVE)
// ...snip...
// Inside the callback function that fires on epoll wakeup:
/*
* If the event mask does not contain any poll(2) event, we consider the
* descriptor to be disabled. This condition is likely the effect of the
* EPOLLONESHOT bit that disables the descriptor when an event is received,
* until the next EPOLL_CTL_MOD will be issued.
*/
if (!(epi->event.events & ~EP_PRIVATE_BITS))
goto out_unlock; // Exits the callback without waking userspace
两个具体问题:
我对内核源代码的阅读是否正确,只要除了四个私有位之外没有指定任何标志,EPOLLERR/EPOLLHUP 就不会被触发?
我可以依赖手册页中未记录的这种行为吗?
【问题讨论】:
-
“在 Linux 源代码树中查看 eventpoll.c”......不确定。 “如果事件掩码不包含任何 poll(2) 事件”
POLLHUP怎么样?蜻蜓bsd文档可能有一些内容 -
@АлексейНеудачин 感谢您的建议,但我认为没有任何 BSD 支持 epoll。我正在专门寻找 Linux 解决方案。
-
github.com/jiixyj/epoll-shim 有一些文档。
-
所以如果我理解正确,你的用例是:(1)一个线程在
epoll_wait()之后唤醒,(2)创建一个套接字,(3)通过它添加到现有的epollEPOLL_CTL_ADD,(4) 通过EPOLL_CTL_MOD重新武装 epoll,(5) 回到等待状态。在这期间,这个线程是唯一与 epoll 交互的线程。这是正确的吗?
标签: c linux linux-kernel epoll manpage