/wepoll

wepoll: fast epoll for windows⁧ 🎭

Primary LanguageCOtherNOASSERTION

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 and GetLastError() 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() or closesocket().

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 by epoll_create() or epoll_create1().
  • op must be one of EPOLL_CTL_ADD, EPOLL_CTL_MOD, EPOLL_CTL_DEL.
  • sock must be a valid socket created by socket(), WSASocket(), or accept().
  • event should be a pointer to a struct epoll_event.
    If op is EPOLL_CTL_DEL then the event parameter is ignored, and it may be NULL.
  • 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 to epoll_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 of epoll_event structs, which will receive the reported events.
  • maxevents is the maximum number of events that will be written to the events array, and must be greater than zero.
  • timeout specifies whether to block when no events are immediately available.
    • <0 block indefinitely
    • 0 report any events that are already waiting, but don't block
    • ≥1 block for at most N milliseconds
  • Return value:
    • -1 an error occurred
    • 0 timed out without any events to report
    • ≥1 the number of events stored in the events 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 by epoll_ctl(), but they are not reported back by epoll_wait().
  • The data field can be used to associate application-specific information with a socket; its value will be returned unmodified by epoll_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().