gpt4 book ai didi

linux - EPOLLET 行为不正确?

转载 作者:太空宇宙 更新时间:2023-11-04 10:09:01 26 4
gpt4 key购买 nike

请考虑以下程序:

#define _GNU_SOURCE
#include <sys/epoll.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

int verify(int result, const char *msg) {
if( result>=0 )
return result;

perror(msg);
abort();

return -1;
}

void writepipe( int fd, int num_bytes, const char *msg ) {
unsigned char buffer[num_bytes];
ssize_t num_written = verify( write(fd, buffer, num_bytes), msg );
assert( num_written==num_bytes );
}

void readpipe( int fd, int num_bytes, const char *msg ) {
unsigned char buffer[num_bytes];
ssize_t num_read = verify( read(fd, buffer, num_bytes), msg );
assert( num_read==num_bytes );
}

int main() {
int pipefds[2];
verify( pipe2(pipefds, O_NONBLOCK), "pipe creation failed" );

int epollfd = verify(epoll_create1(0), "epoll creation failed");

struct epoll_event evt;
evt.events = EPOLLIN|EPOLLET;
evt.data.u64 = 17;
verify( epoll_ctl( epollfd, EPOLL_CTL_ADD, pipefds[0], &evt ), "epoll_add failed" );

int num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait failed" );
assert(num_events == 0);

writepipe( pipefds[1], 12, "initial filling of pipe" );

num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait failed" );
assert(num_events == 1);
assert(evt.data.u64 == 17);

num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait failed" );
assert(num_events == 0);

readpipe( pipefds[0], 12, "clean the data" );

num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait failed" );
assert(num_events == 0);

writepipe( pipefds[1], 3, "write no trigger" );

num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait on unarmed fd" );
assert(num_events == 0);

return 0;
}

最后一个断言失败。

因为我们从来没有从 epoll 中读取 EPOLLET,所以我期望最后一个 epoll_wait 返回 0。相反,我得到了 1。

这是为什么?

来自 Ubuntu 16.10 的内核 4.13.0-39-generic。

最佳答案

迟到的答案,但可能对其他人仍有帮助。

你假设在你最后的 epoll_wait 调用中 fd 是未武装的。不是这种情况。如果你真的想让它处于非武装状态,你可以使用 EPOLLONESHOT。在它触发一次之后,你必须为 epoll 重新准备它。您可能还假设第二次写入不会导致触发 epoll。这个假设也是错误的。 EPOLLET 只保证只要 FD 上没有变化,EPOLLET 就不会再次被触发。管道上的写入会触发更改,因此会触发 epoll(不一定是人们期望发生的事情)。

The reason for this is that edge-triggered mode delivers events only when changes occur on the monitored file descriptor.

来源:http://man7.org/linux/man-pages/man7/epoll.7.html

我真的不知道你说的“我们从来没有读过一个 EPOLLET”是什么意思,你是说 EAGAIN 表示所有数据都已被读取吗?这实际上与您的问题无关。您完全清空管道。所以下一次读取会导致 EAGAIN,但这不会改变上面提到的行为。即使不读取数据,第二次写入也会触发 epoll。检查 EAGAIN 只是为了确保在文件描述符没有变化的情况下我们完全读取所有数据。

关于linux - EPOLLET 行为不正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50278921/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com