module depoll; import core.sys.linux.epoll; import core.sys.posix.unistd : close; import core.stdc.errno : errno, EINTR, EEXIST; import core.stdc.string : strerror; import std.string : fromStringz; import std.exception : enforce; class Epoll { private int epfd_ = -1; this(int flags = 0) { epfd_ = epoll_create1(flags); enforce(epfd_ >= 0, "epoll_create1: " ~ strerror(errno).fromStringz.idup); } ~this() { if (epfd_ >= 0) { close(epfd_); epfd_ = -1; } } /// Добавление дескриптора с произвольным tag (например, tag=0 для fanotify, tag=pid для pidfd) void add(int fd, uint tag, uint events = EPOLLIN | EPOLLERR | EPOLLHUP) { epoll_event ev; ev.events = events; ev.data.u32 = tag; auto rc = epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, &ev); if (rc != 0 && errno == EEXIST) { // Если уже добавлен — делаем MOD rc = epoll_ctl(epfd_, EPOLL_CTL_MOD, fd, &ev); } enforce(rc == 0, "epoll_ctl ADD/MOD: " ~ strerror(errno).fromStringz.idup); } /// Опционально: явное удаление void remove(int fd) { auto rc = epoll_ctl(epfd_, EPOLL_CTL_DEL, fd, null); enforce(rc == 0, "epoll_ctl DEL: " ~ strerror(errno).fromStringz.idup); } struct Event { uint tag; // то самое, что передавали в add() uint events; // EPOLL* биты } /// Возвращает события; пустой массив — если таймаут/прерывание Event[] wait(int maxevents = 16, int timeout = -1) { epoll_event[] evs = new epoll_event[maxevents]; int n; // Терпим EINTR и повторяем while (true) { n = epoll_wait(epfd_, evs.ptr, maxevents, timeout); if (n < 0 && errno == EINTR) continue; break; } if (n <= 0) return []; Event[] res; res.reserve(n); foreach (i; 0 .. n) { res ~= Event(evs[i].data.u32, evs[i].events); } return res; } @property int handle() const { return epfd_; } }