Network
epoll
https://idndx.com/2014/09/01/the-implementation-of-epoll-1/
Old implementation with select
or poll
With select
or poll
, the server handles all the requests by looking through the fd
table, which is O(N)
time.
A traditional echo server like TCP server, creates a thread/process for each client, block on read until the request finishes and write a response.
select
and poll
system call
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select
allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possible). A file descriptor is considered ready if it is possible to perform the corresponding I/O operation without blocking.
int poll (struct pollfd *fds, unsigned int nfds, int timeout);
struct pollfd {
int fd;
short events;
short revents;
};
poll
use pollfd
which has a different fields for the events and the returning events. It checks the bits in revents
which represents the events that actually occurred, and events
represents the events that we are actually interested in.
The time complexity is the same, but poll
has less fields to specify. e.g, no number of fd
needs to be specified.
epoll
system call
epoll
is not part of POSIX, but supported by linux. It is much more efficient if there are many file descriptors.
Three steps from guide
epoll_create()
: create a contextepoll_ctl()
: add monitored fds and related data structure to the contextepoll_wait()
: does the actual wait, return a file descriptor that satisfies the events.
The time complexity of monitoring is O(1)
, also less context switching between user space and kernel space - the context created is always within kernel space. Less CPU time was spent on finding available fds.
epoll
source code analysis here