Merge pull request #3127 from sigiesec/integrate-wepoll

Support epoll polling under Windows with wepoll
This commit is contained in:
Luca Boccassi 2018-05-23 21:15:56 +01:00 committed by GitHub
commit f3e7911dd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 2808 additions and 120 deletions

View File

@ -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 ()

View File

@ -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
View 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
View 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
View File

@ -0,0 +1 @@
https://github.com/piscisaureus/wepoll/tree/v1.5.0

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
View 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_ */

View File

@ -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);

View File

@ -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
{

View File

@ -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

View File

@ -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) {

View File

@ -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 ();
}