diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f83f8ae..82409b2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,7 +94,10 @@ if (WITH_MILITANT) add_definitions(-DZMQ_ACT_MILITANT) endif() -set (POLLER "" CACHE STRING "Choose polling system. valid values are +set (API_POLLER "" CACHE STRING "Choose polling system for zmq_poll(er)_*. valid values are + poll or select [default=poll unless POLLER=select]") + +set (POLLER "" CACHE STRING "Choose polling system for I/O threads. valid values are kqueue, epoll, devpoll, pollset, poll or select [default=autodetect]") include (CheckFunctionExists) @@ -117,7 +120,7 @@ if (POLLER STREQUAL "") set (POLLER "epoll") check_function_exists (epoll_create1 HAVE_EPOLL_CLOEXEC) if (HAVE_EPOLL_CLOEXEC) - set (ZMQ_USE_EPOLL_CLOEXEC 1) + set (ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC 1) endif () endif () endif () @@ -172,13 +175,25 @@ if (POLLER STREQUAL "kqueue" OR POLLER STREQUAL "pollset" OR POLLER STREQUAL "poll" OR POLLER STREQUAL "select") - message (STATUS "Detected ${POLLER} polling method") + message (STATUS "Using polling method in I/O threads: ${POLLER}") string (TOUPPER ${POLLER} UPPER_POLLER) - set (ZMQ_USE_${UPPER_POLLER} 1) + set (ZMQ_IOTHREAD_POLLER_USE_${UPPER_POLLER} 1) else () message (FATAL_ERROR "Invalid polling method") endif () +if (API_POLLER STREQUAL "") + if (POLLER STREQUAL "select") + set (API_POLLER "select") + else() + set (API_POLLER "poll") + endif() +endif() + +message (STATUS "Using polling method in zmq_poll(er)_* API: ${API_POLLER}") + string (TOUPPER ${API_POLLER} UPPER_API_POLLER) +set (ZMQ_POLL_BASED_ON_${UPPER_API_POLLER} 1) + include (TestZMQVersion) if (NOT CMAKE_CROSSCOMPILING) include (ZMQSourceRunChecks) diff --git a/acinclude.m4 b/acinclude.m4 index d96a6215..891d9cfe 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1052,7 +1052,12 @@ AC_DEFUN([LIBZMQ_CHECK_POLLER], [{ # Allow user to override poller autodetection AC_ARG_WITH([poller], [AS_HELP_STRING([--with-poller], - [choose polling system manually. Valid values are 'kqueue', 'epoll', 'devpoll', 'pollset', 'poll', 'select', or 'auto'. [default=auto]])]) + [choose I/O thread polling system manually. Valid values are 'kqueue', 'epoll', 'devpoll', 'pollset', 'poll', 'select', or 'auto'. [default=auto]])]) + + # Allow user to override poller autodetection + AC_ARG_WITH([api_poller], + [AS_HELP_STRING([--with-api-poller], + [choose zmq_poll(er)_* API polling system manually. Valid values are 'poll', 'select', or 'auto'. [default=auto]])]) if test "x$with_poller" == "x"; then pollers=auto @@ -1065,14 +1070,14 @@ AC_DEFUN([LIBZMQ_CHECK_POLLER], [{ fi # try to find suitable polling system. the order of testing is: - AC_MSG_NOTICE([Choosing polling system from '$pollers'...]) + AC_MSG_NOTICE([Choosing I/O thread polling system from '$pollers'...]) poller_found=0 for poller in $pollers; do case "$poller" in kqueue) LIBZMQ_CHECK_POLLER_KQUEUE([ - AC_MSG_NOTICE([Using 'kqueue' polling system]) - AC_DEFINE(ZMQ_USE_KQUEUE, 1, [Use 'kqueue' polling system]) + AC_MSG_NOTICE([Using 'kqueue' I/O thread polling system]) + AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_KQUEUE, 1, [Use 'kqueue' I/O thread polling system]) poller_found=1 ]) ;; @@ -1084,17 +1089,17 @@ AC_DEFUN([LIBZMQ_CHECK_POLLER], [{ # that ZMQ has from Linux systems. Unless you undertake # to fix the integration, do not disable this exception # and use select() or poll() on Solarish OSes for now. - AC_MSG_NOTICE([NOT using 'epoll' polling system on '$host_os']) ;; + AC_MSG_NOTICE([NOT using 'epoll' I/O thread polling system on '$host_os']) ;; *) LIBZMQ_CHECK_POLLER_EPOLL_CLOEXEC([ - AC_MSG_NOTICE([Using 'epoll' polling system with CLOEXEC]) - AC_DEFINE(ZMQ_USE_EPOLL, 1, [Use 'epoll' polling system]) - AC_DEFINE(ZMQ_USE_EPOLL_CLOEXEC, 1, [Use 'epoll' polling system with CLOEXEC]) + AC_MSG_NOTICE([Using 'epoll' I/O thread polling system with CLOEXEC]) + AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_EPOLL, 1, [Use 'epoll' I/O thread polling system]) + AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC, 1, [Use 'epoll' I/O thread polling system with CLOEXEC]) poller_found=1 ],[ LIBZMQ_CHECK_POLLER_EPOLL([ - AC_MSG_NOTICE([Using 'epoll' polling system with CLOEXEC]) - AC_DEFINE(ZMQ_USE_EPOLL, 1, [Use 'epoll' polling system]) + AC_MSG_NOTICE([Using 'epoll' I/O thread polling system with CLOEXEC]) + AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_EPOLL, 1, [Use 'epoll' I/O thread polling system]) poller_found=1 ]) ]) @@ -1103,29 +1108,29 @@ AC_DEFUN([LIBZMQ_CHECK_POLLER], [{ ;; devpoll) LIBZMQ_CHECK_POLLER_DEVPOLL([ - AC_MSG_NOTICE([Using 'devpoll' polling system]) - AC_DEFINE(ZMQ_USE_DEVPOLL, 1, [Use 'devpoll' polling system]) + AC_MSG_NOTICE([Using 'devpoll' I/O thread polling system]) + AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_DEVPOLL, 1, [Use 'devpoll' I/O thread polling system]) poller_found=1 ]) ;; pollset) LIBZMQ_CHECK_POLLER_POLLSET([ - AC_MSG_NOTICE([Using 'pollset' polling system]) - AC_DEFINE(ZMQ_USE_POLLSET, 1, [Use 'pollset' polling system]) + AC_MSG_NOTICE([Using 'pollset' I/O thread polling system]) + AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_POLLSET, 1, [Use 'pollset' I/O thread polling system]) poller_found=1 ]) ;; poll) LIBZMQ_CHECK_POLLER_POLL([ - AC_MSG_NOTICE([Using 'poll' polling system]) - AC_DEFINE(ZMQ_USE_POLL, 1, [Use 'poll' polling system]) + AC_MSG_NOTICE([Using 'poll' I/O thread polling system]) + AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_POLL, 1, [Use 'poll' I/O thread polling system]) poller_found=1 ]) ;; select) LIBZMQ_CHECK_POLLER_SELECT([ - AC_MSG_NOTICE([Using 'select' polling system]) - AC_DEFINE(ZMQ_USE_SELECT, 1, [Use 'select' polling system]) + AC_MSG_NOTICE([Using 'select' I/O thread polling system]) + AC_DEFINE(ZMQ_IOTHREAD_POLLER_USE_SELECT, 1, [Use 'select' I/O thread polling system]) poller_found=1 ]) ;; @@ -1135,4 +1140,25 @@ AC_DEFUN([LIBZMQ_CHECK_POLLER], [{ if test $poller_found -eq 0; then AC_MSG_ERROR([None of '$pollers' are valid pollers on this platform]) fi + if test "x$with_api_poller" == "x"; then + with_api_poller=auto + fi + if test "x$with_api_poller" == "xauto"; then + if test $poller == "select"; then + api_poller=select + else + api_poller=poll + fi + else + api_poller=$with_api_poller + fi + if test "$api_poller" == "select"; then + AC_MSG_NOTICE([Using 'select' zmq_poll(er)_* API polling system]) + AC_DEFINE(ZMQ_POLL_BASED_ON_SELECT, 1, [Use 'select' zmq_poll(er)_* API polling system]) + elif test "$api_poller" == "poll"; then + AC_MSG_NOTICE([Using 'poll' zmq_poll(er)_* API polling system]) + AC_DEFINE(ZMQ_POLL_BASED_ON_POLL, 1, [Use 'poll' zmq_poll(er)_* API polling system]) + else + AC_MSG_ERROR([Invalid API poller '$api_poller' specified]) + fi }]) diff --git a/appveyor.yml b/appveyor.yml index 9916f767..f454fac1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ environment: ENABLE_CURVE: ON - platform: Win32 configuration: Release - POLLER: poll + API_POLLER: poll WITH_LIBSODIUM: ON ENABLE_CURVE: ON - platform: Win32 @@ -93,7 +93,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 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%" + - 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%" build: parallel: true diff --git a/builds/cmake/platform.hpp.in b/builds/cmake/platform.hpp.in index 18d02d2b..8c8e6cf2 100644 --- a/builds/cmake/platform.hpp.in +++ b/builds/cmake/platform.hpp.in @@ -1,12 +1,15 @@ #ifndef __ZMQ_PLATFORM_HPP_INCLUDED__ #define __ZMQ_PLATFORM_HPP_INCLUDED__ -#cmakedefine ZMQ_USE_KQUEUE -#cmakedefine ZMQ_USE_EPOLL -#cmakedefine ZMQ_USE_EPOLL_CLOEXEC -#cmakedefine ZMQ_USE_DEVPOLL -#cmakedefine ZMQ_USE_POLL -#cmakedefine ZMQ_USE_SELECT +#cmakedefine ZMQ_IOTHREAD_POLLER_USE_KQUEUE +#cmakedefine ZMQ_IOTHREAD_POLLER_USE_EPOLL +#cmakedefine ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC +#cmakedefine ZMQ_IOTHREAD_POLLER_USE_DEVPOLL +#cmakedefine ZMQ_IOTHREAD_POLLER_USE_POLL +#cmakedefine ZMQ_IOTHREAD_POLLER_USE_SELECT + +#cmakedefine ZMQ_POLL_BASED_ON_SELECT +#cmakedefine ZMQ_POLL_BASED_ON_POLL #cmakedefine ZMQ_FORCE_MUTEXES diff --git a/src/devpoll.cpp b/src/devpoll.cpp index 897d2e91..d11ab16d 100644 --- a/src/devpoll.cpp +++ b/src/devpoll.cpp @@ -29,7 +29,7 @@ #include "precompiled.hpp" #include "devpoll.hpp" -#if defined ZMQ_USE_DEVPOLL +#if defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL #include #include diff --git a/src/devpoll.hpp b/src/devpoll.hpp index cc7dff36..ef84d808 100644 --- a/src/devpoll.hpp +++ b/src/devpoll.hpp @@ -32,7 +32,7 @@ // poller.hpp decides which polling mechanism to use. #include "poller.hpp" -#if defined ZMQ_USE_DEVPOLL +#if defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL #include diff --git a/src/epoll.cpp b/src/epoll.cpp index 7f3f9c1a..ef87dee5 100644 --- a/src/epoll.cpp +++ b/src/epoll.cpp @@ -29,7 +29,7 @@ #include "precompiled.hpp" #include "epoll.hpp" -#if defined ZMQ_USE_EPOLL +#if defined ZMQ_IOTHREAD_POLLER_USE_EPOLL #include #include diff --git a/src/epoll.hpp b/src/epoll.hpp index d320764f..b31504a0 100644 --- a/src/epoll.hpp +++ b/src/epoll.hpp @@ -32,7 +32,7 @@ // poller.hpp decides which polling mechanism to use. #include "poller.hpp" -#if defined ZMQ_USE_EPOLL +#if defined ZMQ_IOTHREAD_POLLER_USE_EPOLL #include #include diff --git a/src/kqueue.cpp b/src/kqueue.cpp index 93a53969..53d82ac4 100644 --- a/src/kqueue.cpp +++ b/src/kqueue.cpp @@ -29,7 +29,7 @@ #include "precompiled.hpp" #include "kqueue.hpp" -#if defined ZMQ_USE_KQUEUE +#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE #include #include diff --git a/src/kqueue.hpp b/src/kqueue.hpp index e2d2f521..0b5a60a6 100644 --- a/src/kqueue.hpp +++ b/src/kqueue.hpp @@ -32,7 +32,7 @@ // poller.hpp decides which polling mechanism to use. #include "poller.hpp" -#if defined ZMQ_USE_KQUEUE +#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE #include #include diff --git a/src/poll.cpp b/src/poll.cpp index 809685c6..67de088d 100644 --- a/src/poll.cpp +++ b/src/poll.cpp @@ -29,13 +29,11 @@ #include "precompiled.hpp" #include "poll.hpp" -#if defined ZMQ_USE_POLL +#if defined ZMQ_IOTHREAD_POLLER_USE_POLL #include -#if !defined ZMQ_HAVE_WINDOWS #include #include -#endif #include #include "poll.hpp" @@ -43,10 +41,6 @@ #include "config.hpp" #include "i_poll_events.hpp" -#ifdef ZMQ_HAVE_WINDOWS -typedef unsigned long nfds_t; -#endif - zmq::poll_t::poll_t (const zmq::thread_ctx_t &ctx_) : worker_poller_base_t (ctx_), retired (false) @@ -161,14 +155,10 @@ void zmq::poll_t::loop () // Wait for events. int rc = poll (&pollset[0], static_cast (pollset.size ()), timeout ? timeout : -1); -#ifdef ZMQ_HAVE_WINDOWS - wsa_assert (rc != SOCKET_ERROR); -#else if (rc == -1) { errno_assert (errno == EINTR); continue; } -#endif // If there are no events (i.e. it's a timeout) there's no point // in checking the pollset. diff --git a/src/poll.hpp b/src/poll.hpp index b766b344..da8bc931 100644 --- a/src/poll.hpp +++ b/src/poll.hpp @@ -32,11 +32,15 @@ // poller.hpp decides which polling mechanism to use. #include "poller.hpp" -#if defined ZMQ_USE_POLL +#if defined ZMQ_IOTHREAD_POLLER_USE_POLL -#if !defined ZMQ_HAVE_WINDOWS -#include +#if defined ZMQ_HAVE_WINDOWS +#error \ + "poll is broken on Windows for the purpose of the I/O thread poller, use select instead; "\ + "see https://github.com/zeromq/libzmq/issues/3107" #endif + +#include #include #include diff --git a/src/poller.hpp b/src/poller.hpp index 5b0d19df..ba9fbb17 100644 --- a/src/poller.hpp +++ b/src/poller.hpp @@ -30,35 +30,39 @@ #ifndef __ZMQ_POLLER_HPP_INCLUDED__ #define __ZMQ_POLLER_HPP_INCLUDED__ -#if defined ZMQ_USE_KQUEUE + defined ZMQ_USE_EPOLL + defined ZMQ_USE_DEVPOLL \ - + defined ZMQ_USE_POLLSET + defined ZMQ_USE_POLL + defined ZMQ_USE_SELECT \ +#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE \ + + defined ZMQ_IOTHREAD_POLLER_USE_EPOLL \ + + defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL \ + + defined ZMQ_IOTHREAD_POLLER_USE_POLLSET \ + + defined ZMQ_IOTHREAD_POLLER_POLL \ + + defined ZMQ_IOTHREAD_POLLER_USE_SELECT \ > 1 -#error More than one of the ZMQ_USE_* macros defined +#error More than one of the ZMQ_IOTHREAD_POLLER_USE_* macros defined #endif -#if defined ZMQ_USE_KQUEUE +#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE #include "kqueue.hpp" -#elif defined ZMQ_USE_EPOLL +#elif defined ZMQ_IOTHREAD_POLLER_USE_EPOLL #include "epoll.hpp" -#elif defined ZMQ_USE_DEVPOLL +#elif defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL #include "devpoll.hpp" -#elif defined ZMQ_USE_POLLSET +#elif defined ZMQ_IOTHREAD_POLLER_USE_POLLSET #include "pollset.hpp" -#elif defined ZMQ_USE_POLL +#elif defined ZMQ_IOTHREAD_POLLER_USE_POLL #include "poll.hpp" -#elif defined ZMQ_USE_SELECT +#elif defined ZMQ_IOTHREAD_POLLER_USE_SELECT #include "select.hpp" #elif defined ZMQ_HAVE_GNU -#define ZMQ_USE_POLL +#define ZMQ_IOTHREAD_POLLER_USE_POLL #include "poll.hpp" #else -#error None of the ZMQ_USE_* macros defined +#error None of the ZMQ_IOTHREAD_POLLER_USE_* macros defined #endif -#if defined ZMQ_USE_SELECT -#define ZMQ_POLL_BASED_ON_SELECT -#else -#define ZMQ_POLL_BASED_ON_POLL +#if (defined ZMQ_POLL_BASED_ON_SELECT + defined ZMQ_POLL_BASED_ON_POLL) > 1 +#error More than one of the ZMQ_POLL_BASED_ON_* macros defined +#elif (defined ZMQ_POLL_BASED_ON_SELECT + defined ZMQ_POLL_BASED_ON_POLL) == 0 +#error None of the ZMQ_POLL_BASED_ON_* macros defined #endif #endif diff --git a/src/pollset.cpp b/src/pollset.cpp index 9936dd91..1a1dee95 100644 --- a/src/pollset.cpp +++ b/src/pollset.cpp @@ -29,7 +29,7 @@ #include "precompiled.hpp" #include "pollset.hpp" -#if defined ZMQ_USE_POLLSET +#if defined ZMQ_IOTHREAD_POLLER_USE_POLLSET #include #include diff --git a/src/pollset.hpp b/src/pollset.hpp index d07b714b..bd99ad2d 100644 --- a/src/pollset.hpp +++ b/src/pollset.hpp @@ -32,7 +32,7 @@ // poller.hpp decides which polling mechanism to use. #include "poller.hpp" -#if defined ZMQ_USE_POLLSET +#if defined ZMQ_IOTHREAD_POLLER_USE_POLLSET #include #include diff --git a/src/select.cpp b/src/select.cpp index 7d0c1137..86bd8a80 100644 --- a/src/select.cpp +++ b/src/select.cpp @@ -29,7 +29,7 @@ #include "precompiled.hpp" #include "select.hpp" -#if defined ZMQ_USE_SELECT +#if defined ZMQ_IOTHREAD_POLLER_USE_SELECT #if defined ZMQ_HAVE_WINDOWS #elif defined ZMQ_HAVE_HPUX diff --git a/src/select.hpp b/src/select.hpp index 6553df66..7093c3d4 100644 --- a/src/select.hpp +++ b/src/select.hpp @@ -32,7 +32,7 @@ // poller.hpp decides which polling mechanism to use. #include "poller.hpp" -#if defined ZMQ_USE_SELECT +#if defined ZMQ_IOTHREAD_POLLER_USE_SELECT #include #include diff --git a/src/windows.hpp b/src/windows.hpp index 6c3839fd..824a256d 100644 --- a/src/windows.hpp +++ b/src/windows.hpp @@ -83,7 +83,7 @@ struct tcp_keepalive #include #endif -#if defined ZMQ_USE_POLL +#if defined ZMQ_IOTHREAD_POLLER_USE_POLL || defined ZMQ_POLL_BASED_ON_POLL static inline int poll (struct pollfd *pfd, unsigned long nfds, int timeout) { return WSAPoll (pfd, nfds, timeout); diff --git a/unittests/unittest_poller.cpp b/unittests/unittest_poller.cpp index ec340972..d48f6a79 100644 --- a/unittests/unittest_poller.cpp +++ b/unittests/unittest_poller.cpp @@ -205,6 +205,56 @@ void test_add_fd_and_remove_by_timer () close_fdpair (w, r); } +#ifdef _WIN32 +void test_add_fd_with_pending_failing_connect () +{ + zmq::thread_ctx_t thread_ctx; + zmq::poller_t poller (thread_ctx); + + zmq::fd_t bind_socket = socket (AF_INET, SOCK_STREAM, 0); + sockaddr_in addr = {0}; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + addr.sin_port = 0; + TEST_ASSERT_EQUAL_INT (0, bind (bind_socket, + reinterpret_cast (&addr), + sizeof (addr))); + + int addr_len = static_cast (sizeof (addr)); + TEST_ASSERT_EQUAL_INT (0, getsockname (bind_socket, + reinterpret_cast (&addr), + &addr_len)); + + zmq::fd_t connect_socket = socket (AF_INET, SOCK_STREAM, 0); + zmq::unblock_socket (connect_socket); + + TEST_ASSERT_EQUAL_INT ( + -1, connect (connect_socket, reinterpret_cast (&addr), + sizeof (addr))); + TEST_ASSERT_EQUAL_INT (WSAEWOULDBLOCK, WSAGetLastError ()); + + test_events_t events (connect_socket, poller); + + zmq::poller_t::handle_t handle = poller.add_fd (connect_socket, &events); + events.set_handle (handle); + poller.set_pollin (handle); + poller.start (); + + wait_in_events (events); + + int value; + int value_len = sizeof (value); + TEST_ASSERT_EQUAL_INT (0, getsockopt (connect_socket, SOL_SOCKET, SO_ERROR, + reinterpret_cast (&value), + &value_len)); + TEST_ASSERT_EQUAL_INT (WSAECONNREFUSED, value); + + // required cleanup + close (connect_socket); + close (bind_socket); +} +#endif + int main (void) { UNITY_BEGIN (); @@ -216,6 +266,10 @@ int main (void) RUN_TEST (test_add_fd_and_start_and_receive_data); RUN_TEST (test_add_fd_and_remove_by_timer); +#if defined _WIN32 + RUN_TEST (test_add_fd_with_pending_failing_connect); +#endif + zmq::shutdown_network (); return UNITY_END ();