epoll primer
A practical introduction to Linux epoll for building scalable event-driven servers. This primer walks through the core API, edge-triggered vs level-triggered modes, and a minimal echo-server pattern you can lift into Meridian workers handling thousands of concurrent sockets.
1.Why epoll
Classic select and poll scale O(n) with watched descriptors because the kernel walks the whole set each call. epoll keeps an interest list inside the kernel, returns only the ready descriptors, and stays O(1) per event. For a Meridian gateway juggling 10k+ keep-alive connections, that difference is the gap between 40% and 4% CPU at idle.
2.The three syscalls
The whole API is three calls. epoll_create1 returns an epoll file descriptor, epoll_ctl adds/modifies/removes interest in a target fd, and epoll_wait blocks until one or more events fire. Use EPOLLET for edge-triggered mode and drain the socket fully on each wakeup, otherwise you will deadlock waiting for the next edge.
3.Minimal echo loop
The pattern below registers a listening socket, accepts connections nonblocking, and echoes any inbound data. In production you would also handle EPOLLHUP and EPOLLRDHUPto clean up half-closed peers.
int ep = epoll_create1(EPOLL_CLOEXEC);
struct epoll_event ev = { .events = EPOLLIN | EPOLLET, .data.fd = lfd };
epoll_ctl(ep, EPOLL_CTL_ADD, lfd, &ev);
struct epoll_event events[64];
for (;;) {
int n = epoll_wait(ep, events, 64, -1);
for (int i = 0; i < n; i++) {
int fd = events[i].data.fd;
if (fd == lfd) accept_all(ep, lfd);
else drain_and_echo(fd);
}
}