Will an epoll be woken up on EPOLLERR/EPOLLHUP if no other flags are provided?

Viewed 413

I want to add a file descriptor to an existing epoll instance but not have it wake up yet. Specifically, I would like to make sure that EPOLLERR and EPOLLHUP are not raised. I am using EPOLLONESHOT to wake up a single thread at a time, then EPOLL_CTL_MOD to re-arm once I'm done processing the events.

(My motivation is to use the same code path for handling a wakeup and creating a new socket: both of them could finish by calling epoll_ctl with EPOLL_CTL_MOD to re-arm the event. However, I don't want a spurious thread wakeup if an error occurs in the socket before the EPOLL_CTL_MOD).

According to the manpage, that is not possible. Both EPOLLERR and EPOLLHUP claim that:

epoll_wait(2) will always wait for this event; it is not necessary to set it in events when calling epoll_ctl().

However, after reviewing eventpoll.c in the Linux source tree, it looks like if no "public" events bits are set, the wakeup is suppressed. (Block comments in the original; line comments are my notes.)

/* Epoll private bits inside the event mask */
#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET | EPOLLEXCLUSIVE)

// ...snip...

// Inside the callback function that fires on epoll wakeup:

    /*
     * If the event mask does not contain any poll(2) event, we consider the
     * descriptor to be disabled. This condition is likely the effect of the
     * EPOLLONESHOT bit that disables the descriptor when an event is received,
     * until the next EPOLL_CTL_MOD will be issued.
     */
    if (!(epi->event.events & ~EP_PRIVATE_BITS))
        goto out_unlock; // Exits the callback without waking userspace

Two concrete questions:

Is my reading of the kernel source correct that EPOLLERR/EPOLLHUP will not be triggered as long as no flags are specified apart from the four private bits?

Can I rely on this behavior that is undocumented in the man page?

1 Answers

Is my reading of the kernel source correct that EPOLLERR/EPOLLHUP will not be triggered as long as no flags are specified apart from the four private bits?

Insufficient information is provided to make that determination.

The C statement presented in the question tests whether epi->event.events has any bits set that are not set in EP_PRIVATE_BITS. If not, then control branches to the statement labelled out_unlock. It is not clear from the code presented whether following that branch means that neither EPOLLERR nor EPOLLHUP will be triggered. And even if so, it also is not clear whether, when they are evaluated in that conditional, the contents of epi->event.events can be relied upon to be only the flags specified explicitly by the user.

Can I rely on this behavior that is undocumented in the man page?

You can do whatever you want, but, generally speaking, relying on undocumented behavior is extremely unwise. Relying on behavior contrary to documentation -- that is, on bugs -- is beyond unwise.

I am inclined to guess that something has escaped you in your source analysis, such that in fact the system produces epoll behavior that is consistent with the documentation. But even if not, I really cannot imagine relying on a system interface to behave contrary to specification, unless in circumstances where you can actively ensure that the wanted behavior is realized. And by "actively ensure" I mean take control of the implementation, not just study it.

Related