diff --git a/src/event/SocketEvent.cxx b/src/event/SocketEvent.cxx index 22f457a30..e1d39747a 100644 --- a/src/event/SocketEvent.cxx +++ b/src/event/SocketEvent.cxx @@ -85,6 +85,15 @@ SocketEvent::Schedule(unsigned flags) noexcept return success; } +void +SocketEvent::Abandon() noexcept +{ + if (std::exchange(scheduled_flags, 0) != 0) + loop.AbandonFD(fd.Get()); + + fd = SocketDescriptor::Undefined(); +} + void SocketEvent::Dispatch() noexcept { diff --git a/src/event/SocketEvent.hxx b/src/event/SocketEvent.hxx index cd26d6c9d..4e1ebabca 100644 --- a/src/event/SocketEvent.hxx +++ b/src/event/SocketEvent.hxx @@ -121,6 +121,18 @@ public: */ void Close() noexcept; + /** + * Call this instead of Cancel() to unregister this object + * after the underlying socket has already been closed. This + * skips the `EPOLL_CTL_DEL` call because the kernel + * automatically removes closed file descriptors from epoll. + * + * Doing `EPOLL_CTL_DEL` on a closed file descriptor usually + * fails with `-EBADF` or could unregister a different socket + * which happens to be on the same file descriptor number. + */ + void Abandon() noexcept; + unsigned GetScheduledFlags() const noexcept { return scheduled_flags; }