如果在边缘触发模式下调用epoll_ctl之前文件是可读的,那么随后的epoll_wait会立即返回吗?

10

epoll能否保证在使用epoll_ctl注册文件时,对于EPOLLIN和EPOLLET的第一次(或持续性)调用epoll_wait会立即返回,如果在epoll_ctl调用之前文件已经可读?通过我的测试程序的实验,答案似乎是肯定的。以下是几个示例以澄清我的问题:

假设我们已初始化了一个epoll文件efd和文件fd,并且定义了以下事件:

event.data.fd = fd;
event.events  = EPOLLIN | EPOLLET;

现在考虑以下情况:
  1. 线程1:向fd写入数据
  2. 线程2:epoll_ctl (efd, EPOLL_CTL_ADD, fd, &event);
  3. 线程2:epoll_wait (efd, events, MAXEVENTS, -1);
现在第3步的调用是否会立即返回?根据我的经验,它确实会。这是有保证的吗?
现在考虑第二种情况,扩展第一种情况:
  1. 线程1:向fd写入数据
  2. 线程2:epoll_ctl (efd, EPOLL_CTL_ADD, fd, &event);
  3. 线程2:epoll_wait (efd, events, MAXEVENTS, -1);
  4. 线程2:epoll_ctl (efd, EPOLL_CTL_MOD, fd, &event);
  5. 线程2:epoll_wait (efd, events, MAXEVENTS, -1);
第5步的调用是否会立即返回?根据我的经验,它确实会。这是有保证的吗?
epoll手册对此问题并不完全清楚。特别是手册建议,在使用边缘触发模式时,应始终从文件中读取,直到返回EAGAIN。但似乎这些注释假定您在每次想要等待文件时不会重新注册文件。
相关讨论可以参考epoll的边缘触发选项的目的是什么?。第一个答案的前两个评论似乎证实了我看到的行为是预期的。 https://gist.github.com/3900742 是一个C测试程序,说明使用管道的epoll似乎就是我所描述的。
1个回答

6
由于epoll是特定于Linux的,因此没有真正的规范,因此它基本上取决于实际实现(手册试图以一种更为用户友好的方式描述这一点,但不提供边缘情况的所有细节)。
查看ep_insertep_modify,两者都检查当前事件位(与EPOLLET无关):
/*
 * Get current event bits. We can safely use the file* here because
 * its usage count has been increased by the caller of this function.
 */
revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt);

因此,这解释了您所看到的行为,并且似乎是故意为之。但是由于没有规范,无法百分之百保证今后不会更改这种行为。


1
是的。看起来你提到的对 poll 的调用会填充 revents,它似乎是准备好事件的位图,然后在几行代码之后,有一些代码检查这些位与正在注册的事件是否匹配,并且如果准备好的事件匹配,则将文件添加到“准备就绪列表”中;例如,在 ep_insert 中以下是接下来的几行:/* 如果文件已经“准备就绪”,我们将其放入准备就绪列表中 */ if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) { list_add_tail(&epi->rdllink, &ep->rdllist); - Andreas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接