diff --git a/CMakeLists.txt b/CMakeLists.txt index d0a7c7ec..c42c3241 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,6 +183,9 @@ check_include_files (ifaddrs.h ZMQ_HAVE_IFADDRS) check_include_files (windows.h ZMQ_HAVE_WINDOWS) check_include_files (sys/uio.h ZMQ_HAVE_UIO) check_include_files (sys/eventfd.h ZMQ_HAVE_EVENTFD) +if (ZMQ_HAVE_EVENTFD) + zmq_check_efd_cloexec () +endif () check_library_exists (ws2_32 fopen "" HAVE_WS2_32) # TODO: Why doesn't something logical like WSAStartup work? check_library_exists (ws2 fopen "" HAVE_WS2) diff --git a/acinclude.m4 b/acinclude.m4 index 386c6707..0eddc2b9 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -614,6 +614,29 @@ int main (int argc, char *argv []) AS_IF([test "x$libzmq_cv_sock_cloexec" = "xyes"], [$1], [$2]) }]) +dnl ################################################################################ +dnl # LIBZMQ_CHECK_EVENTFD_CLOEXEC([action-if-found], [action-if-not-found]) # +dnl # Check if EFD_CLOEXEC is supported # +dnl ################################################################################ +AC_DEFUN([LIBZMQ_CHECK_EVENTFD_CLOEXEC], [{ + AC_CACHE_CHECK([whether EFD_CLOEXEC is supported], [libzmq_cv_efd_cloexec], + [AC_TRY_RUN([/* EFD_CLOEXEC test */ +#include + +int main (int argc, char *argv []) +{ + int s = eventfd (0, EFD_CLOEXEC); + return (s == -1); +} + ], + [libzmq_cv_efd_cloexec="yes"], + [libzmq_cv_efd_cloexec="no"], + [libzmq_cv_efd_cloexec="not during cross-compile"] + )] + ) + AS_IF([test "x$libzmq_cv_efd_cloexec" = "xyes"], [$1], [$2]) +}]) + dnl ################################################################################ dnl # LIBZMQ_CHECK_ATOMIC_INSTRINSICS([action-if-found], [action-if-not-found]) # dnl # Check if compiler supoorts __atomic_Xxx intrinsics # diff --git a/builds/cmake/Modules/ZMQSourceRunChecks.cmake b/builds/cmake/Modules/ZMQSourceRunChecks.cmake index 10d46d3d..c4644919 100644 --- a/builds/cmake/Modules/ZMQSourceRunChecks.cmake +++ b/builds/cmake/Modules/ZMQSourceRunChecks.cmake @@ -16,6 +16,21 @@ int main(int argc, char *argv []) ZMQ_HAVE_SOCK_CLOEXEC) endmacro() +macro(zmq_check_efd_cloexec) + message(STATUS "Checking whether EFD_CLOEXEC is supported") + check_c_source_runs( + " +#include + +int main(int argc, char *argv []) +{ + int s = eventfd (0, EFD_CLOEXEC); + return(s == -1); +} +" + ZMQ_HAVE_EVENTFD_CLOEXEC) +endmacro() + # TCP keep-alives Checks. macro(zmq_check_so_keepalive) diff --git a/builds/cmake/platform.hpp.in b/builds/cmake/platform.hpp.in index 80195118..14f1898e 100644 --- a/builds/cmake/platform.hpp.in +++ b/builds/cmake/platform.hpp.in @@ -17,6 +17,7 @@ #cmakedefine ZMQ_HAVE_UIO #cmakedefine ZMQ_HAVE_EVENTFD +#cmakedefine ZMQ_HAVE_EVENTFD_CLOEXEC #cmakedefine ZMQ_HAVE_IFADDRS #cmakedefine ZMQ_HAVE_SO_PEERCRED diff --git a/configure.ac b/configure.ac index d548f9fa..a8c9c25d 100644 --- a/configure.ac +++ b/configure.ac @@ -358,8 +358,14 @@ AC_ARG_ENABLE([eventfd], if test "x$zmq_enable_eventfd" = "xyes"; then # Check if we have eventfd.h header file. - AC_CHECK_HEADERS(sys/eventfd.h, - [AC_DEFINE(ZMQ_HAVE_EVENTFD, 1, [Have eventfd extension])]) + AC_CHECK_HEADERS(sys/eventfd.h, [ + AC_DEFINE(ZMQ_HAVE_EVENTFD, 1, [Have eventfd extension]) + LIBZMQ_CHECK_EVENTFD_CLOEXEC([ + AC_DEFINE([ZMQ_HAVE_EVENTFD_CLOEXEC], + [1], + [Whether EFD_CLOEXEC is defined and functioning.]) + ]) + ]) fi # Conditionally build performance measurement tools diff --git a/src/signaler.cpp b/src/signaler.cpp index 77c7ff54..5922cda7 100644 --- a/src/signaler.cpp +++ b/src/signaler.cpp @@ -381,7 +381,14 @@ void zmq::signaler_t::forked () int zmq::signaler_t::make_fdpair (fd_t *r_, fd_t *w_) { #if defined ZMQ_HAVE_EVENTFD - fd_t fd = eventfd (0, 0); + int flags = 0; +#if defined ZMQ_HAVE_EVENTFD_CLOEXEC + // Setting this option result in sane behaviour when exec() functions + // are used. Old sockets are closed and don't block TCP ports, avoid + // leaks, etc. + flags |= EFD_CLOEXEC; +#endif + fd_t fd = eventfd (0, flags); if (fd == -1) { errno_assert (errno == ENFILE || errno == EMFILE); *w_ = *r_ = -1;