Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I get a notification from epoll when a fd is closed?

Tags:

linux

epoll

I am currently building something that uses epoll. It works pretty nice, but it would be good to have a notification when a file descriptor gets removed from epoll when the underlying fd is closed.

Is there a way to get a notification from epoll as soon as an fd is closed?

like image 517
Nidhoegger Avatar asked Mar 26 '17 21:03

Nidhoegger


1 Answers

No. Here's a Zig program to demonstrate:

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);
}

It outputs:

epoll wait
close fd
^C

(I had to kill it with Ctrl+C because it never woke up.)

Here's the strace output:

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
like image 140
andrewrk Avatar answered Sep 21 '22 23:09

andrewrk