86 lines
		
	
	
	
		
			2 KiB
		
	
	
	
		
			D
		
	
	
	
	
	
			
		
		
	
	
			86 lines
		
	
	
	
		
			2 KiB
		
	
	
	
		
			D
		
	
	
	
	
	
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_;
 | 
						||
	}
 | 
						||
}
 |