gpt4 book ai didi

c - epoll 事件不会引发 SIGIO

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:37:02 28 4
gpt4 key购买 nike

根据我的研究,您可以添加一个 epoll 文件描述符来轮询、选择或另一个 epoll,如果事件可用,它将返回 POLLIN。根据 epoll(7):

   Q3  Is the epoll file descriptor itself poll/epoll/selectable?

A3 Yes. If an epoll file descriptor has events waiting, then it will
indicate as being readable.

这在我的测试中有效。但是,我现在正尝试将 O_ASYNC 应用于我的 epoll fd,以便它会在事件准备就绪时引发 SIGIO:

//Epoll setup code - trySc runs perror on the string and exits if the function returns -1
int epollFd = epoll_create1(EPOLL_CLOEXEC);
trySc(epollFd, "epoll_create1");
trySc(fcntl(epollFd, F_SETOWN, getpid()), "fcntl F_SETOWN");
trySc(fcntl(epollFd, F_SETSIG, SIGIO), "fcntl F_SETSIG");
int oldFlags = fcntl(epollFd, F_GETFL, 0);
trySc(oldFlags, "fcntl F_GETFL");
trySc(fcntl(epollFd, F_SETFL, oldFlags | O_ASYNC), "fcntl F_SETFL");

//Set up SIGIO and get a socket fd, you don't need to see this
//All my handler does is exit - it's a definite method of knowing SIGIO was raised

struct epoll_event event = {
.events = EPOLLIN | EPOLLET,
.data.fd = socketFd
};
trySc(epoll_ctl(epollFd, EPOLL_CTL_ADD, socketFd, &event), "epoll_ctl");
//Then connect
while(1){
struct pollfd pfd = {
.fd = epollFd,
.events = POLLIN
};
//This blocks until I write something to the socket. Then it enters an infinite loop.
printf("Returning to main(), poll = %d\n", poll(&pfd, 1, -1));
}

当我这样做时,它不会为 epoll 中的新事件引发 SIGIO。 Poll 表明 epollFd 中有事件就绪,但它应该首先引发 SIGIO(它只是检查事件是否在 epollFd 中并退出)。我知道我可以将 O_ASYNC 应用于套接字(我也试过这个)但我希望在我的事件中包含数据。 Epoll 让我这样做。

这是我的完整代码:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <netdb.h>
#include <poll.h>
#include <signal.h>
#include <errno.h>

void handleSIGIO(int, siginfo_t *, void *);

const struct sigaction saSIGIO = {
.sa_sigaction = handleSIGIO,
.sa_flags = SA_SIGINFO
};

const struct addrinfo hints = {
.ai_flags = AI_PASSIVE,
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM
};

void trySc(int err, const char *msg){
if(err != -1) return;
perror(msg);
exit(errno);
}

int main(){
signal(SIGPIPE, SIG_IGN);
trySc(sigaction(SIGIO, &saSIGIO, NULL), "sigaction");
int epollFd = epoll_create1(EPOLL_CLOEXEC);
trySc(epollFd, "epoll_create1");
trySc(fcntl(epollFd, F_SETOWN, getpid()), "fcntl F_SETOWN");
trySc(fcntl(epollFd, F_SETSIG, SIGIO), "fcntl F_SETSIG");
int oldFlags = fcntl(epollFd, F_GETFL, 0);
trySc(oldFlags, "fcntl F_GETFL");
trySc(fcntl(epollFd, F_SETFL, oldFlags | O_ASYNC), "fcntl F_SETFL");
int socketFd = socket(AF_INET, SOCK_STREAM, 0);
trySc(socketFd, "socket");
struct addrinfo *servinfo;
trySc(getaddrinfo("127.0.0.1", "5000", &hints, &servinfo),
"getaddrinfo");
struct epoll_event event = {
.events = EPOLLIN | EPOLLET,
.data.fd = socketFd
};
trySc(epoll_ctl(epollFd, EPOLL_CTL_ADD, socketFd, &event), "epoll_ctl");
trySc(connect(socketFd, servinfo->ai_addr, servinfo->ai_addrlen),
"connect");
printf("Connected\n");
while(1){
struct pollfd pfd = {
.fd = epollFd,
.events = POLLIN
};
printf("Returning to main(), poll = %d\n", poll(&pfd, 1, -1));
}
}

void handleSIGIO(int sn, siginfo_t *info, void *ctx){
printf("SIGIO called\n");
struct epoll_event event;
if(epoll_wait(info->si_fd, &event, 1, 0) != 1){
printf("Warning: no event available\n");
return;
}
printf("Event raised for fd %d\n", event.data.fd);
exit(0);
}

编辑:根据this website ,我正在尝试做的应该有效:

Note that an epoll set descriptor can be used much like a regular file 
descriptor. That is, it can be made to generate SIGIO (or another signal)
when input (i.e. events) is available on it; likewise it can be used with
poll() and can even be stored inside another epoll set.

最佳答案

经过更多研究,我发现这是不可能的。根据open(2)

O_ASYNC

Enable signal-driven I/O: generate a signal (SIGIO by default, but this can be changed via fcntl(2)) when input or output becomes possible on this file descriptor. This feature is available only for terminals, pseudoterminals, sockets, and (since Linux 2.6) pipes and FIFOs. See fcntl(2) for further details. See also BUGS, below.

我真的希望我可以将 epoll 与 SIGIO 一起使用。我会找到我能做的其他事情。

我找到了这个问题的解决方案:将 O_ASYNC 应用于每个套接字,然后在您的 SIGIO 处理程序中,在您的 epoll fd 上调用 epoll_wait。然后像往常一样处理来自 epoll 的事件。它不适用于不支持 SIGIO 的 FD,即使它们支持 epoll,但它适用于套接字和管道,这可能是异步 IO 最常见的用法。

关于c - epoll 事件不会引发 SIGIO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47764803/

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