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
errno
andGetLastError()
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).
size
is ignored but most be greater than zero.flags
must be zero as there are no supported flags.- Returns
NULL
on 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.
ephnd
must be a HANDLE created byepoll_create()
orepoll_create1()
.op
must be one ofEPOLL_CTL_ADD
,EPOLL_CTL_MOD
,EPOLL_CTL_DEL
.sock
must be a valid socket created bysocket()
,WSASocket()
, oraccept()
.event
should be a pointer to astruct epoll_event
.
Ifop
isEPOLL_CTL_DEL
then theevent
parameter 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_DEL
before 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.
events
should point to a caller-allocated array ofepoll_event
structs, which will receive the reported events.maxevents
is the maximum number of events that will be written to theevents
array, and must be greater than zero.timeout
specifies whether to block when no events are immediately available.<0
block indefinitely0
report any events that are already waiting, but don't block≥1
block for at most N milliseconds
- Return value:
-1
an error occurred0
timed out without any events to report≥1
the number of events stored in theevents
buffer
- 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
events
field 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
data
field 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()
.