mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-14 02:57:47 +01:00
Merge pull request #3127 from sigiesec/integrate-wepoll
Support epoll polling under Windows with wepoll
This commit is contained in:
commit
f3e7911dd6
189
CMakeLists.txt
189
CMakeLists.txt
@ -103,54 +103,56 @@ set (POLLER "" CACHE STRING "Choose polling system for I/O threads. valid values
|
||||
include (CheckFunctionExists)
|
||||
include (CheckTypeSize)
|
||||
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/event.h)
|
||||
check_function_exists (kqueue HAVE_KQUEUE)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_KQUEUE)
|
||||
set (POLLER "kqueue")
|
||||
endif()
|
||||
endif ()
|
||||
if (NOT MSVC)
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/event.h)
|
||||
check_function_exists (kqueue HAVE_KQUEUE)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_KQUEUE)
|
||||
set (POLLER "kqueue")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/epoll.h)
|
||||
check_function_exists (epoll_create HAVE_EPOLL)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_EPOLL)
|
||||
set (POLLER "epoll")
|
||||
check_function_exists (epoll_create1 HAVE_EPOLL_CLOEXEC)
|
||||
if (HAVE_EPOLL_CLOEXEC)
|
||||
set (ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC 1)
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/epoll.h)
|
||||
check_function_exists (epoll_create HAVE_EPOLL)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_EPOLL)
|
||||
set (POLLER "epoll")
|
||||
check_function_exists (epoll_create1 HAVE_EPOLL_CLOEXEC)
|
||||
if (HAVE_EPOLL_CLOEXEC)
|
||||
set (ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC 1)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/devpoll.h)
|
||||
check_type_size ("struct pollfd" DEVPOLL)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_DEVPOLL)
|
||||
set (POLLER "devpoll")
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/devpoll.h)
|
||||
check_type_size ("struct pollfd" DEVPOLL)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_DEVPOLL)
|
||||
set (POLLER "devpoll")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/pollset.h)
|
||||
check_function_exists (pollset_create HAVE_POLLSET)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_POLLSET)
|
||||
set (POLLER "pollset")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES poll.h)
|
||||
check_function_exists (poll HAVE_POLL)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_POLL)
|
||||
set (POLLER "poll")
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/pollset.h)
|
||||
check_function_exists (pollset_create HAVE_POLLSET)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_POLLSET)
|
||||
set (POLLER "pollset")
|
||||
endif()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (POLLER STREQUAL "")
|
||||
set (CMAKE_REQUIRED_INCLUDES poll.h)
|
||||
check_function_exists (poll HAVE_POLL)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
if (HAVE_POLL)
|
||||
set (POLLER "poll")
|
||||
endif ()
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (POLLER STREQUAL "")
|
||||
if (WIN32)
|
||||
@ -182,6 +184,11 @@ else ()
|
||||
message (FATAL_ERROR "Invalid polling method")
|
||||
endif ()
|
||||
|
||||
if (POLLER STREQUAL "epoll" AND WIN32)
|
||||
message (STATUS "Including wepoll")
|
||||
list (APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/external/wepoll/wepoll.c ${CMAKE_CURRENT_SOURCE_DIR}/external/wepoll/wepoll.h)
|
||||
endif()
|
||||
|
||||
if (API_POLLER STREQUAL "")
|
||||
if (POLLER STREQUAL "select")
|
||||
set (API_POLLER "select")
|
||||
@ -208,18 +215,19 @@ include (CMakeDependentOption)
|
||||
include (CheckCXXSymbolExists)
|
||||
include (CheckSymbolExists)
|
||||
|
||||
check_include_files (ifaddrs.h ZMQ_HAVE_IFADDRS)
|
||||
check_include_files (windows.h ZMQ_HAVE_WINDOWS)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore" AND CMAKE_SYSTEM_VERSION STREQUAL "10.0")
|
||||
SET(ZMQ_HAVE_WINDOWS_UWP ON)
|
||||
ADD_DEFINITIONS(-D_WIN32_WINNT=_WIN32_WINNT_WIN10)
|
||||
endif()
|
||||
check_include_files (sys/uio.h ZMQ_HAVE_UIO)
|
||||
check_include_files (sys/eventfd.h ZMQ_HAVE_EVENTFD)
|
||||
if (ZMQ_HAVE_EVENTFD AND NOT CMAKE_CROSSCOMPILING)
|
||||
zmq_check_efd_cloexec ()
|
||||
endif ()
|
||||
|
||||
if (NOT MSVC)
|
||||
check_include_files (ifaddrs.h ZMQ_HAVE_IFADDRS)
|
||||
check_include_files (sys/uio.h ZMQ_HAVE_UIO)
|
||||
check_include_files (sys/eventfd.h ZMQ_HAVE_EVENTFD)
|
||||
if (ZMQ_HAVE_EVENTFD AND NOT CMAKE_CROSSCOMPILING)
|
||||
zmq_check_efd_cloexec ()
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (ZMQ_HAVE_WINDOWS)
|
||||
# Cannot use check_library_exists because the symbol is always declared as char(*)(void)
|
||||
@ -259,25 +267,27 @@ if (WIN32 AND NOT CYGWIN)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set (CMAKE_REQUIRED_LIBRARIES rt)
|
||||
check_function_exists (clock_gettime HAVE_CLOCK_GETTIME)
|
||||
set (CMAKE_REQUIRED_LIBRARIES)
|
||||
if (NOT MSVC)
|
||||
set (CMAKE_REQUIRED_LIBRARIES rt)
|
||||
check_function_exists (clock_gettime HAVE_CLOCK_GETTIME)
|
||||
set (CMAKE_REQUIRED_LIBRARIES)
|
||||
|
||||
set (CMAKE_REQUIRED_INCLUDES unistd.h)
|
||||
check_function_exists (fork HAVE_FORK)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
set (CMAKE_REQUIRED_INCLUDES unistd.h)
|
||||
check_function_exists (fork HAVE_FORK)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/time.h)
|
||||
check_function_exists (gethrtime HAVE_GETHRTIME)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/time.h)
|
||||
check_function_exists (gethrtime HAVE_GETHRTIME)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
|
||||
set (CMAKE_REQUIRED_INCLUDES stdlib.h)
|
||||
check_function_exists (mkdtemp HAVE_MKDTEMP)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
set (CMAKE_REQUIRED_INCLUDES stdlib.h)
|
||||
check_function_exists (mkdtemp HAVE_MKDTEMP)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/socket.h)
|
||||
check_function_exists (accept4 HAVE_ACCEPT4)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
set (CMAKE_REQUIRED_INCLUDES sys/socket.h)
|
||||
check_function_exists (accept4 HAVE_ACCEPT4)
|
||||
set (CMAKE_REQUIRED_INCLUDES)
|
||||
endif()
|
||||
|
||||
add_definitions (-D_REENTRANT -D_THREAD_SAFE)
|
||||
add_definitions (-DZMQ_CUSTOM_PLATFORM_HPP)
|
||||
@ -309,31 +319,36 @@ if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
zmq_check_cxx_flag_prepend ("-Wextra")
|
||||
endif ()
|
||||
|
||||
# TODO: why is -Wno-long-long defined differently than in configure.ac?
|
||||
zmq_check_cxx_flag_prepend ("-Wno-long-long")
|
||||
zmq_check_cxx_flag_prepend ("-Wno-uninitialized")
|
||||
|
||||
option (LIBZMQ_PEDANTIC "" ON)
|
||||
option (LIBZMQ_WERROR "" OFF)
|
||||
|
||||
if (LIBZMQ_PEDANTIC)
|
||||
zmq_check_cxx_flag_prepend ("-pedantic")
|
||||
# TODO: why is -Wno-long-long defined differently than in configure.ac?
|
||||
if (NOT MSVC)
|
||||
zmq_check_cxx_flag_prepend ("-Wno-long-long")
|
||||
zmq_check_cxx_flag_prepend ("-Wno-uninitialized")
|
||||
|
||||
if (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel")
|
||||
zmq_check_cxx_flag_prepend ("-strict-ansi")
|
||||
endif ()
|
||||
if (LIBZMQ_PEDANTIC)
|
||||
zmq_check_cxx_flag_prepend ("-pedantic")
|
||||
|
||||
if (${CMAKE_CXX_COMPILER_ID} MATCHES "SunPro")
|
||||
zmq_check_cxx_flag_prepend ("-compat=5")
|
||||
endif ()
|
||||
endif ()
|
||||
if (${CMAKE_CXX_COMPILER_ID} MATCHES "Intel")
|
||||
zmq_check_cxx_flag_prepend ("-strict-ansi")
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_CXX_COMPILER_ID} MATCHES "SunPro")
|
||||
zmq_check_cxx_flag_prepend ("-compat=5")
|
||||
endif ()
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (LIBZMQ_WERROR)
|
||||
zmq_check_cxx_flag_prepend ("-Werror")
|
||||
zmq_check_cxx_flag_prepend ("/WX")
|
||||
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
zmq_check_cxx_flag_prepend ("-errwarn=%all")
|
||||
endif()
|
||||
if(MSVC)
|
||||
zmq_check_cxx_flag_prepend ("/WX")
|
||||
else()
|
||||
zmq_check_cxx_flag_prepend ("-Werror")
|
||||
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
zmq_check_cxx_flag_prepend ("-errwarn=%all")
|
||||
endif()
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^sparc")
|
||||
@ -367,7 +382,7 @@ endif ()
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
if (NOT CMAKE_CROSSCOMPILING AND NOT MSVC)
|
||||
zmq_check_sock_cloexec ()
|
||||
zmq_check_o_cloexec ()
|
||||
zmq_check_so_bindtodevice ()
|
||||
@ -886,8 +901,9 @@ endif ()
|
||||
|
||||
if (MSVC)
|
||||
# default for all sources is to use precompiled headers
|
||||
foreach(source ${sources})
|
||||
if (NOT ${source} STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/src/precompiled.cpp")
|
||||
foreach(source ${sources})
|
||||
# C and C++ can not use the same precompiled header
|
||||
if (${soruce} MATCHES ".cpp$" AND NOT ${source} STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}/src/precompiled.cpp")
|
||||
set_source_files_properties(${source}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "/Yuprecompiled.hpp"
|
||||
@ -901,11 +917,6 @@ if (MSVC)
|
||||
COMPILE_FLAGS "/Ycprecompiled.hpp"
|
||||
OBJECT_OUTPUTS precompiled.hpp
|
||||
)
|
||||
# C and C++ can not use the same precompiled header
|
||||
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/src/tweetnacl.c
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "/Y-"
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
||||
|
@ -20,6 +20,11 @@ environment:
|
||||
API_POLLER: poll
|
||||
WITH_LIBSODIUM: ON
|
||||
ENABLE_CURVE: ON
|
||||
- platform: Win32
|
||||
configuration: Release
|
||||
POLLER: epoll
|
||||
WITH_LIBSODIUM: ON
|
||||
ENABLE_CURVE: ON
|
||||
- platform: Win32
|
||||
configuration: Debug
|
||||
WITH_LIBSODIUM: ON
|
||||
@ -93,7 +98,7 @@ before_build:
|
||||
- cmd: set LIBZMQ_BUILDDIR=C:\projects\build_libzmq
|
||||
- cmd: md "%LIBZMQ_BUILDDIR%"
|
||||
- cd "%LIBZMQ_BUILDDIR%"
|
||||
- cmd: cmake -D CMAKE_INCLUDE_PATH="%SODIUM_INCLUDE_DIR%" -D CMAKE_LIBRARY_PATH="%SODIUM_LIBRARY_DIR%" -D WITH_LIBSODIUM="%WITH_LIBSODIUM%" -D ENABLE_DRAFTS="ON" -D ENABLE_CURVE="%ENABLE_CURVE%" -D API_POLLER="%API_POLLER%" -D CMAKE_C_FLAGS_RELEASE="/MT" -D CMAKE_C_FLAGS_DEBUG="/MTd" -D WITH_LIBSODIUM="%WITH_LIBSODIUM%" -D LIBZMQ_WERROR="ON" -G "%CMAKE_GENERATOR%" "%APPVEYOR_BUILD_FOLDER%"
|
||||
- cmd: cmake -D CMAKE_INCLUDE_PATH="%SODIUM_INCLUDE_DIR%" -D CMAKE_LIBRARY_PATH="%SODIUM_LIBRARY_DIR%" -D WITH_LIBSODIUM="%WITH_LIBSODIUM%" -D ENABLE_DRAFTS="ON" -D ENABLE_CURVE="%ENABLE_CURVE%" -D API_POLLER="%API_POLLER%" -D POLLER="%POLLER%" -D CMAKE_C_FLAGS_RELEASE="/MT" -D CMAKE_C_FLAGS_DEBUG="/MTd" -D WITH_LIBSODIUM="%WITH_LIBSODIUM%" -D LIBZMQ_WERROR="ON" -G "%CMAKE_GENERATOR%" "%APPVEYOR_BUILD_FOLDER%"
|
||||
|
||||
build:
|
||||
parallel: true
|
||||
|
202
external/wepoll/README.md
vendored
Normal file
202
external/wepoll/README.md
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
# wepoll - epoll for windows
|
||||
|
||||
[![][ci status badge]][ci status link]
|
||||
|
||||
This library implements the [epoll][man 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][select scale] and suffer from
|
||||
[other issues][wsapoll broken].
|
||||
|
||||
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][dist].
|
||||
|
||||
## Limitations
|
||||
|
||||
* Only works with sockets.
|
||||
* Edge-triggered (`EPOLLET`) mode isn't supported.
|
||||
|
||||
## How to use
|
||||
|
||||
The library is [distributed][dist] as a single source file
|
||||
([wepoll.c][wepoll.c]) and a single header file ([wepoll.h][wepoll.h]).<br>
|
||||
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][man epoll],
|
||||
and the per-function man pages that are linked below.
|
||||
|
||||
### epoll_create/epoll_create1
|
||||
|
||||
```c
|
||||
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][man epoll_create]
|
||||
|
||||
### epoll_close
|
||||
|
||||
```c
|
||||
int epoll_close(HANDLE ephnd);
|
||||
```
|
||||
|
||||
* Close an epoll port.
|
||||
* Do not attempt to close the epoll port with `close()`,
|
||||
`CloseHandle()` or `closesocket()`.
|
||||
|
||||
### epoll_ctl
|
||||
|
||||
```c
|
||||
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()`](#epoll_createepoll_create1) or
|
||||
[`epoll_create1()`](#epoll_createepoll_create1).
|
||||
* `op` must be one of `EPOLL_CTL_ADD`, `EPOLL_CTL_MOD`, `EPOLL_CTL_DEL`.
|
||||
* `sock` must be a valid socket created by [`socket()`][msdn socket],
|
||||
[`WSASocket()`][msdn wsasocket], or [`accept()`][msdn accept].
|
||||
* `event` should be a pointer to a [`struct epoll_event`](#struct-epoll_event).<br>
|
||||
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.<br>
|
||||
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()`](#epoll_wait).
|
||||
* [Linux man page][man epoll_ctl]
|
||||
|
||||
### epoll_wait
|
||||
|
||||
```c
|
||||
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`](#struct-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][man epoll_wait]
|
||||
|
||||
### struct epoll_event
|
||||
|
||||
```c
|
||||
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;
|
||||
```
|
||||
|
||||
```c
|
||||
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.<br>
|
||||
Flags are accepted by [`epoll_ctl()`](#epoll_ctl), but they are not reported
|
||||
back by [`epoll_wait()`](#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()`](#epoll_wait).
|
||||
* [Linux man page][man epoll_ctl]
|
||||
|
||||
| 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 error<sup>1</sup> |
|
||||
| `EPOLLHUP` | socket hang-up<sup>1</sup> |
|
||||
| `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 |
|
||||
|
||||
<sup>1</sup>: the `EPOLLERR` and `EPOLLHUP` events may always be reported by
|
||||
[`epoll_wait()`](#epoll_wait), regardless of the event mask that was passed to
|
||||
[`epoll_ctl()`](#epoll_ctl).
|
||||
|
||||
|
||||
[ci status badge]: https://ci.appveyor.com/api/projects/status/github/piscisaureus/wepoll?branch=master&svg=true
|
||||
[ci status link]: https://ci.appveyor.com/project/piscisaureus/wepoll/branch/master
|
||||
[dist]: https://github.com/piscisaureus/wepoll/tree/dist
|
||||
[man epoll]: http://man7.org/linux/man-pages/man7/epoll.7.html
|
||||
[man epoll_create]: http://man7.org/linux/man-pages/man2/epoll_create.2.html
|
||||
[man epoll_ctl]: http://man7.org/linux/man-pages/man2/epoll_ctl.2.html
|
||||
[man epoll_wait]: http://man7.org/linux/man-pages/man2/epoll_wait.2.html
|
||||
[msdn accept]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(v=vs.85).aspx
|
||||
[msdn socket]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx
|
||||
[msdn wsasocket]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx
|
||||
[select scale]: https://daniel.haxx.se/docs/poll-vs-select.html
|
||||
[wsapoll broken]: https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/
|
||||
[wepoll.c]: https://github.com/piscisaureus/wepoll/blob/dist/wepoll.c
|
||||
[wepoll.h]: https://github.com/piscisaureus/wepoll/blob/dist/wepoll.h
|
28
external/wepoll/license.txt
vendored
Normal file
28
external/wepoll/license.txt
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
wepoll - epoll for Windows
|
||||
https://github.com/piscisaureus/wepoll
|
||||
|
||||
Copyright 2012-2018, Bert Belder <bertbelder@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
1
external/wepoll/version.txt
vendored
Normal file
1
external/wepoll/version.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
https://github.com/piscisaureus/wepoll/tree/v1.5.0
|
2290
external/wepoll/wepoll.c
vendored
Normal file
2290
external/wepoll/wepoll.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
117
external/wepoll/wepoll.h
vendored
Normal file
117
external/wepoll/wepoll.h
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* wepoll - epoll for Windows
|
||||
* https://github.com/piscisaureus/wepoll
|
||||
*
|
||||
* Copyright 2012-2018, Bert Belder <bertbelder@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef WEPOLL_H_
|
||||
#define WEPOLL_H_
|
||||
|
||||
#ifndef WEPOLL_EXPORT
|
||||
#define WEPOLL_EXPORT
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
enum EPOLL_EVENTS {
|
||||
EPOLLIN = (int) (1U << 0),
|
||||
EPOLLPRI = (int) (1U << 1),
|
||||
EPOLLOUT = (int) (1U << 2),
|
||||
EPOLLERR = (int) (1U << 3),
|
||||
EPOLLHUP = (int) (1U << 4),
|
||||
EPOLLRDNORM = (int) (1U << 6),
|
||||
EPOLLRDBAND = (int) (1U << 7),
|
||||
EPOLLWRNORM = (int) (1U << 8),
|
||||
EPOLLWRBAND = (int) (1U << 9),
|
||||
EPOLLMSG = (int) (1U << 10), /* Never reported. */
|
||||
EPOLLRDHUP = (int) (1U << 13),
|
||||
EPOLLONESHOT = (int) (1U << 31)
|
||||
};
|
||||
|
||||
#define EPOLLIN (1U << 0)
|
||||
#define EPOLLPRI (1U << 1)
|
||||
#define EPOLLOUT (1U << 2)
|
||||
#define EPOLLERR (1U << 3)
|
||||
#define EPOLLHUP (1U << 4)
|
||||
#define EPOLLRDNORM (1U << 6)
|
||||
#define EPOLLRDBAND (1U << 7)
|
||||
#define EPOLLWRNORM (1U << 8)
|
||||
#define EPOLLWRBAND (1U << 9)
|
||||
#define EPOLLMSG (1U << 10)
|
||||
#define EPOLLRDHUP (1U << 13)
|
||||
#define EPOLLONESHOT (1U << 31)
|
||||
|
||||
#define EPOLL_CTL_ADD 1
|
||||
#define EPOLL_CTL_MOD 2
|
||||
#define EPOLL_CTL_DEL 3
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
typedef void* HANDLE;
|
||||
typedef uintptr_t SOCKET;
|
||||
|
||||
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 */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
WEPOLL_EXPORT HANDLE epoll_create(int size);
|
||||
WEPOLL_EXPORT HANDLE epoll_create1(int flags);
|
||||
|
||||
WEPOLL_EXPORT int epoll_close(HANDLE ephnd);
|
||||
|
||||
WEPOLL_EXPORT int epoll_ctl(HANDLE ephnd,
|
||||
int op,
|
||||
SOCKET sock,
|
||||
struct epoll_event* event);
|
||||
|
||||
WEPOLL_EXPORT int epoll_wait(HANDLE ephnd,
|
||||
struct epoll_event* events,
|
||||
int maxevents,
|
||||
int timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* WEPOLL_H_ */
|
@ -28,23 +28,29 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "epoll.hpp"
|
||||
#if defined ZMQ_IOTHREAD_POLLER_USE_EPOLL
|
||||
#include "epoll.hpp"
|
||||
|
||||
#if !defined ZMQ_HAVE_WINDOWS
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
|
||||
#include "macros.hpp"
|
||||
#include "epoll.hpp"
|
||||
#include "err.hpp"
|
||||
#include "config.hpp"
|
||||
#include "i_poll_events.hpp"
|
||||
|
||||
#ifdef ZMQ_HAVE_WINDOWS
|
||||
const zmq::epoll_t::epoll_fd_t zmq::epoll_t::epoll_retired_fd =
|
||||
INVALID_HANDLE_VALUE;
|
||||
#endif
|
||||
|
||||
zmq::epoll_t::epoll_t (const zmq::thread_ctx_t &ctx_) :
|
||||
worker_poller_base_t (ctx_)
|
||||
{
|
||||
@ -56,7 +62,7 @@ zmq::epoll_t::epoll_t (const zmq::thread_ctx_t &ctx_) :
|
||||
#else
|
||||
epoll_fd = epoll_create (1);
|
||||
#endif
|
||||
errno_assert (epoll_fd != -1);
|
||||
errno_assert (epoll_fd != epoll_retired_fd);
|
||||
}
|
||||
|
||||
zmq::epoll_t::~epoll_t ()
|
||||
@ -64,7 +70,11 @@ zmq::epoll_t::~epoll_t ()
|
||||
// Wait till the worker thread exits.
|
||||
stop_worker ();
|
||||
|
||||
#ifdef ZMQ_HAVE_WINDOWS
|
||||
epoll_close (epoll_fd);
|
||||
#else
|
||||
close (epoll_fd);
|
||||
#endif
|
||||
for (retired_t::iterator it = retired.begin (); it != retired.end ();
|
||||
++it) {
|
||||
LIBZMQ_DELETE (*it);
|
||||
|
@ -35,7 +35,12 @@
|
||||
#if defined ZMQ_IOTHREAD_POLLER_USE_EPOLL
|
||||
|
||||
#include <vector>
|
||||
|
||||
#if defined ZMQ_HAVE_WINDOWS
|
||||
#include "../external/wepoll/wepoll.h"
|
||||
#else
|
||||
#include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
#include "ctx.hpp"
|
||||
#include "fd.hpp"
|
||||
@ -70,11 +75,22 @@ class epoll_t : public worker_poller_base_t
|
||||
static int max_fds ();
|
||||
|
||||
private:
|
||||
#if defined ZMQ_HAVE_WINDOWS
|
||||
typedef HANDLE epoll_fd_t;
|
||||
static const epoll_fd_t epoll_retired_fd;
|
||||
#else
|
||||
typedef fd_t epoll_fd_t;
|
||||
enum
|
||||
{
|
||||
epoll_retired_fd = retired_fd
|
||||
};
|
||||
#endif
|
||||
|
||||
// Main event loop.
|
||||
void loop ();
|
||||
|
||||
// Main epoll file descriptor
|
||||
fd_t epoll_fd;
|
||||
epoll_fd_t epoll_fd;
|
||||
|
||||
struct poll_entry_t
|
||||
{
|
||||
|
@ -217,9 +217,12 @@ if(ZMQ_HAVE_CURVE)
|
||||
endif()
|
||||
set_tests_properties(test_heartbeats PROPERTIES TIMEOUT 60)
|
||||
|
||||
if(WIN32 AND ${POLLER} MATCHES "poll")
|
||||
set_tests_properties(test_many_sockets PROPERTIES TIMEOUT 30)
|
||||
set_tests_properties(test_immediate PROPERTIES TIMEOUT 30)
|
||||
if(WIN32 AND ${POLLER} MATCHES "epoll")
|
||||
set_tests_properties(test_many_sockets PROPERTIES TIMEOUT 120)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set_tests_properties(test_radio_dish PROPERTIES TIMEOUT 30)
|
||||
endif()
|
||||
|
||||
#add additional required flags
|
||||
|
@ -47,7 +47,9 @@ void test_system_max ()
|
||||
break;
|
||||
sockets.push_back (socket);
|
||||
}
|
||||
assert ((int) sockets.size () <= no_of_sockets);
|
||||
assert (static_cast<int> (sockets.size ()) <= no_of_sockets);
|
||||
printf ("Socket creation failed after %i sockets\n",
|
||||
static_cast<int> (sockets.size ()));
|
||||
|
||||
// System is out of resources, further calls to zmq_socket should return NULL
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
|
@ -259,7 +259,7 @@ static const char *mcast_url (int ipv6_)
|
||||
if (ipv6_) {
|
||||
return "udp://[" MCAST_IPV6 "]:5555";
|
||||
} else {
|
||||
return "udp://[" MCAST_IPV4 "]:5555";
|
||||
return "udp://" MCAST_IPV4 ":5555";
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,8 +421,18 @@ out:
|
||||
return success;
|
||||
}
|
||||
|
||||
static void ignore_if_unavailable (int ipv6_)
|
||||
{
|
||||
if (ipv6_ && !is_ipv6_available ())
|
||||
TEST_IGNORE_MESSAGE ("No IPV6 available");
|
||||
if (!is_multicast_available (ipv6_))
|
||||
TEST_IGNORE_MESSAGE ("No multicast available");
|
||||
}
|
||||
|
||||
static void test_radio_dish_mcast (int ipv6_)
|
||||
{
|
||||
ignore_if_unavailable (ipv6_);
|
||||
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
@ -450,6 +460,12 @@ MAKE_TEST_V4V6 (test_radio_dish_mcast)
|
||||
|
||||
static void test_radio_dish_no_loop (int ipv6_)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
TEST_IGNORE_MESSAGE (
|
||||
"ZMQ_MULTICAST_LOOP=false does not appear to work on Windows (TODO)");
|
||||
#endif
|
||||
ignore_if_unavailable (ipv6_);
|
||||
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
@ -458,7 +474,7 @@ static void test_radio_dish_no_loop (int ipv6_)
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
// Disable multicast loop
|
||||
// Disable multicast loop for radio
|
||||
int loop = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (radio, ZMQ_MULTICAST_LOOP, &loop, sizeof (int)));
|
||||
@ -476,14 +492,8 @@ static void test_radio_dish_no_loop (int ipv6_)
|
||||
|
||||
// Looping is disabled, we shouldn't receive anything
|
||||
msleep (SETTLE_TIME);
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
|
||||
int rc = zmq_msg_recv (&msg, dish, ZMQ_DONTWAIT);
|
||||
zmq_msg_close (&msg);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (rc, -1);
|
||||
TEST_ASSERT_EQUAL_INT (errno, EAGAIN);
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (dish, NULL, 0, ZMQ_DONTWAIT));
|
||||
|
||||
test_context_socket_close (dish);
|
||||
test_context_socket_close (radio);
|
||||
@ -507,18 +517,11 @@ int main (void)
|
||||
RUN_TEST (test_radio_dish_udp_ipv4);
|
||||
RUN_TEST (test_radio_dish_udp_ipv6);
|
||||
|
||||
bool ipv4_mcast = is_multicast_available (false);
|
||||
bool ipv6_mcast = is_ipv6_available () && is_multicast_available (true);
|
||||
RUN_TEST (test_radio_dish_mcast_ipv4);
|
||||
RUN_TEST (test_radio_dish_no_loop_ipv4);
|
||||
|
||||
if (ipv4_mcast) {
|
||||
RUN_TEST (test_radio_dish_mcast_ipv4);
|
||||
RUN_TEST (test_radio_dish_no_loop_ipv4);
|
||||
}
|
||||
|
||||
if (ipv6_mcast) {
|
||||
RUN_TEST (test_radio_dish_mcast_ipv6);
|
||||
RUN_TEST (test_radio_dish_no_loop_ipv6);
|
||||
}
|
||||
RUN_TEST (test_radio_dish_mcast_ipv6);
|
||||
RUN_TEST (test_radio_dish_no_loop_ipv6);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user