wepoll - epoll for windows
This library implements the epoll API for Windows applications. It is fast and scalable, and it closely resembles the API and behavior of Linux' epoll.
Rationale
Unlike Linux, OS X, and many other operating systems, Windows doesn't
have a good API for receiving socket state notifications. It only
supports the select and WSAPoll APIs, but they
don't scale and suffer from
other issues.
Using I/O completion ports isn't always practical when software is designed to be cross-platform. Wepoll offers an alternative that is much closer to a drop-in replacement for software that was designed to run on Linux.
Features
- Can poll 100000s of sockets efficiently.
- Fully thread-safe.
- Multiple threads can poll the same epoll port.
- Sockets can be added to multiple epoll sets.
- All epoll events (
EPOLLIN,EPOLLOUT,EPOLLPRI,EPOLLRDHUP) are supported. - Level-triggered and one-shot (
EPOLLONESTHOT) modes are supported - Trivial to embed: you need only two files.
Limitations
- Only works with sockets.
- Edge-triggered (
EPOLLET) mode isn't supported.
How to use
The library is distributed as a single source file
(wepoll.c) and a single header file (wepoll.h).
Compile the .c file as part of your project, and include the header wherever
needed.
Compatibility
- Requires Windows Vista or higher.
- Can be compiled with recent versions of MSVC, Clang, and GCC.
API
General remarks
- The epoll port is a
HANDLE, not a file descriptor. - All functions set both
errnoandGetLastError()on failure. - For more extensive documentation, see the epoll(7) man page, and the per-function man pages that are linked below.
epoll_create/epoll_create1
HANDLE epoll_create(int size);
HANDLE epoll_create1(int flags);
- Create a new epoll instance (port).
sizeis ignored but most be greater than zero.flagsmust be zero as there are no supported flags.- Returns
NULLon failure. - Linux man page
epoll_close
int epoll_close(HANDLE ephnd);
- Close an epoll port.
- Do not attempt to close the epoll port with
close(),CloseHandle()orclosesocket().
epoll_ctl
int epoll_ctl(HANDLE ephnd,
int op,
SOCKET sock,
struct epoll_event* event);
- Control which socket events are monitored by an epoll port.
ephndmust be a HANDLE created byepoll_create()orepoll_create1().opmust be one ofEPOLL_CTL_ADD,EPOLL_CTL_MOD,EPOLL_CTL_DEL.sockmust be a valid socket created bysocket(),WSASocket(), oraccept().eventshould be a pointer to astruct epoll_event.
IfopisEPOLL_CTL_DELthen theeventparameter is ignored, and it may beNULL.- Returns 0 on success, -1 on failure.
- It is recommended to always explicitly remove a socket from its epoll
set using
EPOLL_CTL_DELbefore closing it.
As on Linux, closed sockets are automatically removed from the epoll set, but wepoll may not be able to detect that a socket was closed until the next call toepoll_wait(). - Linux man page
epoll_wait
int epoll_wait(HANDLE ephnd,
struct epoll_event* events,
int maxevents,
int timeout);
- Receive socket events from an epoll port.
eventsshould point to a caller-allocated array ofepoll_eventstructs, which will receive the reported events.maxeventsis the maximum number of events that will be written to theeventsarray, and must be greater than zero.timeoutspecifies whether to block when no events are immediately available.<0block indefinitely0report any events that are already waiting, but don't block≥1block for at most N milliseconds
- Return value:
-1an error occurred0timed out without any events to report≥1the number of events stored in theeventsbuffer
- Linux man page
struct epoll_event
typedef union epoll_data {
void* ptr;
int fd;
uint32_t u32;
uint64_t u64;
SOCKET sock; /* Windows specific */
HANDLE hnd; /* Windows specific */
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events and flags */
epoll_data_t data; /* User data variable */
};
- The
eventsfield is a bit mask containing the events being monitored/reported, and optional flags.
Flags are accepted byepoll_ctl(), but they are not reported back byepoll_wait(). - The
datafield can be used to associate application-specific information with a socket; its value will be returned unmodified byepoll_wait(). - Linux man page
| Event | Description |
|---|---|
EPOLLIN |
incoming data available, or incoming connection ready to be accepted |
EPOLLOUT |
ready to send data, or outgoing connection successfully established |
EPOLLRDHUP |
remote peer initiated graceful socket shutdown |
EPOLLPRI |
out-of-band data available for reading |
EPOLLERR |
socket error1 |
EPOLLHUP |
socket hang-up1 |
EPOLLRDNORM |
same as EPOLLIN |
EPOLLRDBAND |
same as EPOLLPRI |
EPOLLWRNORM |
same as EPOLLOUT |
EPOLLWRBAND |
same as EPOLLOUT |
EPOLLMSG |
never reported |
| Flag | Description |
|---|---|
EPOLLONESHOT |
report event(s) only once |
EPOLLET |
not supported by wepoll |
EPOLLEXCLUSIVE |
not supported by wepoll |
EPOLLWAKEUP |
not supported by wepoll |
1: the EPOLLERR and EPOLLHUP events may always be reported by
epoll_wait(), regardless of the event mask that was passed to
epoll_ctl().