当fd关闭时,我会从epoll收到通知吗?

时间:2017-03-26 21:05:03

标签: linux epoll

我目前正在构建使用epoll的内容。它的工作非常好,但是当基础epoll关闭时,如果文件描述符从fd中删除,则会收到通知。

epoll关闭后,有没有办法从fd收到通知?

3 个答案:

答案 0 :(得分:-1)

您需要注意epoll_wait()何时返回-1,然后检查errno值,看它是否与EBADF匹配。

有关详细信息,请参阅man epoll_wait()man errno

答案 1 :(得分:-1)

不。文件描述符一旦关闭,它就不再可用于内核在新文件描述符中使用的任何内容。一旦您因新的open(2)create(2)socket(2)等系统调用而无法再次获取,系统调用将其用作参数任何系统调用(包括select(2)epoll(2)

内核已经释放了进程结构中的文件描述符条目,因此使用它无效。

如果你关闭它,你可以从epoll(2)得到一些东西的唯一方法就是你有两个线程,并且当你在另一个线程中等待它时,你close(2)一个线程中的文件描述符。这次你可以立即从epoll(2)系统调用返回,可能有一些错误(我没有测试过这个),但我认为这不是你的场景。

答案 2 :(得分:-1)

不。这是一个Zig程序来演示:

const std = @import("std");

pub fn main() !void {
    const epollfd = blk: {
        const rc = std.os.linux.epoll_create1(std.os.linux.EPOLL_CLOEXEC);
        const err = std.os.linux.getErrno(rc);
        if (err != 0) return error.EpollCreateFailed;
        break :blk @intCast(i32, rc);
    };
    defer std.os.close(epollfd);

    var pipe: [2]i32 = undefined;
    {
        const rc = std.os.linux.pipe2(&pipe, std.os.linux.O_CLOEXEC);
        const err = std.os.linux.getErrno(rc);
        if (err != 0) return error.PipeCreateFailed;
    }

    var ev: std.os.linux.epoll_event = undefined;

    ev.events = std.os.linux.EPOLLIN | std.os.linux.EPOLLET;
    ev.data.fd = pipe[0];
    {
        const rc = std.os.linux.epoll_ctl(epollfd, std.os.linux.EPOLL_CTL_ADD, pipe[0], &ev);
        const err = std.os.linux.getErrno(rc);
        if (err != 0) return error.EpollCtlFailed;
    }

    const thread = try std.os.spawnThread(pipe[0], threadStart);

    var events: [10]std.os.linux.epoll_event = undefined;
    const nfds = blk: {
        std.debug.warn("epoll wait\n");
        const rc = std.os.linux.epoll_wait(epollfd, &events, @intCast(u32, events.len), -1);
        std.debug.warn("epoll wakeup\n");
        const err = std.os.linux.getErrno(rc);
        if (err != 0) return error.EpollWaitFailed;
        break :blk rc;
    };
    if (nfds != 1) return error.NotExactly1FileDescriptor;
    std.debug.assert(events[0].data.fd == pipe[0]);
    thread.wait();
}

fn threadStart(fd: i32) void {
    std.os.time.sleep(1, 0);
    std.debug.warn("close fd\n");
    std.os.close(fd);
}

它输出:

epoll wait
close fd
^C

(我必须用Ctrl + C杀死它,因为它永远不会醒来。)

这是strace的输出:

execve("./test", ["./test"], 0x7fff311ff208 /* 122 vars */) = 0
epoll_create1(EPOLL_CLOEXEC)            = 3
pipe2([4, 5], O_CLOEXEC)                = 0
epoll_ctl(3, EPOLL_CTL_ADD, 4, {EPOLLIN|EPOLLET, {u32=4, u64=4}}) = 0
mmap(NULL, 8388608, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0) = 0x7fd082ed9000
clone(child_stack=0x7fd0836d8fd8, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID|0x400000, parent_tidptr=0x7fd0836d8fe4, child_tidptr=0x7fd0836d8fe4) = 13547
strace: Process 13547 attached
[pid 13546] write(2, "epoll wait\n", 11epoll wait
<unfinished ...>
[pid 13547] nanosleep({tv_sec=1, tv_nsec=0},  <unfinished ...>
[pid 13546] <... write resumed> )       = 11
[pid 13546] epoll_wait(3,  <unfinished ...>
[pid 13547] <... nanosleep resumed> 0x7fd0836d8f20) = 0
[pid 13547] write(2, "close fd\n", 9close fd
)   = 9
[pid 13547] close(4)                    = 0
[pid 13547] exit(0)                     = ?
[pid 13547] +++ exited with 0 +++
^Cstrace: Process 13546 detached