【问题标题】:Will an epoll be woken up on EPOLLERR/EPOLLHUP if no other flags are provided?如果没有提供其他标志,是否会在 EPOLLERR/EPOLLHUP 上唤醒 epoll?
【发布时间】: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)通过它添加到现有的epoll EPOLL_CTL_ADD,(4) 通过EPOLL_CTL_MOD 重新武装 epoll,(5) 回到等待状态。在这期间,这个线程是唯一与 epoll 交互的线程。这是正确的吗?

标签: c linux linux-kernel epoll manpage


【解决方案1】:

我对内核源代码的阅读是否正确,只要除了四个私有位之外没有指定任何标志,就不会触发 EPOLLERR/EPOLLHUP?

提供的信息不足以做出该决定。

问题中出现的 C 语句测试 epi->event.events 是否设置了 EP_PRIVATE_BITS 中未设置的任何位。如果不是,则控制分支到标记为out_unlock 的语句。从提供的代码中不清楚是否遵循该分支是否意味着EPOLLERR 和EPOLLHUP 都不会被触发。即使是这样,也不清楚,当他们在那个条件下被评估时,epi->event.events 的内容是否可以被认为只是用户明确指定的标志。

我可以依赖手册页中未记录的这种行为吗?

您可以为所欲为,但一般来说,依赖无证行为是极其不明智的。依赖与文档相反的行为——即错误——是非常不明智的。

我倾向于猜测你在源代码分析中漏掉了一些东西,以至于实际上系统产生了与文档一致的 epoll 行为。但即使不是,我也真的无法想象依赖系统接口的行为违反规范,除非在您可以积极确保实现所需行为的情况下。我所说的“积极确保”是指控制实施,而不仅仅是研究它。

【讨论】:

  • 我不相信这种行为是“违反规范”的。 epoll_ctl(2) 报告EPOLLONESHOT:请求关联文件描述符的一次性通知。这意味着在epoll_wait(2) 通知文件描述符的事件后,文件描述符在兴趣列表中被禁用,并且 epoll 接口不会报告其他事件。我会认为使这项工作唯一明智的方法是禁用所有事件,直到重新武装。内核源代码证实了这一点(自 v2.6.2 中引入 EPOLLONESHOT 以来,这种情况一直存在)。
  • @MarcoBonelli,行为是否真的违反规范是一个有效的问题,但 OP 断言所提供的联机帮助页摘录说它是。
  • 我会说 OP 对手册页的解释是完全错误的,虽然手册页的措辞不佳/误导性,但这并不是他们的错。 epoll(7) 还声明:"[...] 指定 EPOLLONESHOT 标志,以告诉 epoll 在收到带有 epoll_wait(2) 的事件后禁用关联的文件描述符 . 当指定EPOLLONESHOT 标志时,调用者负责重新配置文件描述符[...]".
  • 我不依赖 OP 的断言,@MarcoBonelli。关键是,如果他们认为某种行为没有记录在案,或者尤其是与记录相反,那么他们就没有依赖该行为的业务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-09
相关资源
最近更新 更多