From 6e9565c91fca092f69111a40fa56eabe41c60ff4 Mon Sep 17 00:00:00 2001 From: Alan Antonuk Date: Mon, 1 Jun 2015 23:38:08 -0700 Subject: Lib: add select()-based implementation of poll() Add select() based poll() implementation for platforms that either support this better (Win32) or don't support poll(). --- CMakeLists.txt | 18 ++++++++++++ cmake/config.h.in | 4 +++ configure.ac | 5 ++++ librabbitmq/amqp_socket.c | 53 ++++++++++++++++++++++++++++++---- m4/ax_have_poll.m4 | 72 +++++++++++++++++++++++++++++++++++++++++++++++ m4/ax_have_select.m4 | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 218 insertions(+), 5 deletions(-) create mode 100644 m4/ax_have_poll.m4 create mode 100644 m4/ax_have_select.m4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3be7535..095805f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,24 @@ else (WIN32) endif (WIN32) cmake_pop_check_state() +cmake_push_check_state() +set(CMAKE_REQUIRED_INCLUDES "poll.h") +check_function_exists(poll HAVE_POLL) +set(CMAKE_REQUIRED_INCLUDES ) +if (NOT HAVE_POLL) + if (WIN32) + set(HAVE_SELECT 1) + else() + set(CMAKE_REQUIRED_INCLUDES sys/select.h) + check_function_exists(select HAVE_SELECT) + set(CMAKE_REQUIRED_INCLUDES ) + endif() + if (NOT HAVE_SELECT) + message(FATAL_ERROR "rabbitmq-c requires poll() or select() to be available") + endif() +endif() +cmake_pop_check_state() + check_library_exists(rt clock_gettime "time.h" CLOCK_GETTIME_NEEDS_LIBRT) if (CLOCK_GETTIME_NEEDS_LIBRT) set(LIBRT rt) diff --git a/cmake/config.h.in b/cmake/config.h.in index 7f3fa71..a7e5a2c 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -8,6 +8,10 @@ #cmakedefine HAVE_HTONLL +#cmakedefine HAVE_SELECT + +#cmakedefine HAVE_POLL + #define AMQ_PLATFORM "@CMAKE_SYSTEM@" #endif /* CONFIG_H */ diff --git a/configure.ac b/configure.ac index 3b34d9b..d1781bd 100644 --- a/configure.ac +++ b/configure.ac @@ -124,6 +124,11 @@ AC_LINK_IFELSE( ] ) +# Need poll() or select() +AX_HAVE_POLL([AC_DEFINE([HAVE_POLL], [], ["Have poll()"])], + AX_HAVE_SELECT([AC_DEFINE([HAVE_SELECT], [], ["Have select()"])], + [AC_MSG_ERROR([rabbitmq-c needs poll() or select()])])) + # Configure SSL/TLS AC_ARG_WITH([ssl], [AS_HELP_STRING([--with-ssl=@<:@cyassl/gnutls/no/openssl/polarssl/yes@:>@], diff --git a/librabbitmq/amqp_socket.c b/librabbitmq/amqp_socket.c index 6267d23..c110765 100644 --- a/librabbitmq/amqp_socket.c +++ b/librabbitmq/amqp_socket.c @@ -67,18 +67,19 @@ # include /* On older BSD this must come before net includes */ # include # include +# ifdef HAVE_SELECT +# include +# endif # include # include # include # include -# include +# ifdef HAVE_POLL +# include +# endif # include #endif -#ifdef _WIN32 -# define poll(fdarray, nfds, timeout) WSAPoll(fdarray, nfds, timeout) -#endif - static int amqp_id_in_reply_list( amqp_method_number_t expected, amqp_method_number_t *list ); static int @@ -258,6 +259,7 @@ amqp_socket_get_sockfd(amqp_socket_t *self) } int amqp_poll(int fd, int event, amqp_time_t deadline) { +#ifdef HAVE_POLL struct pollfd pfd; int res; int timeout_ms; @@ -299,6 +301,47 @@ start_poll: } } return AMQP_STATUS_OK; +#elif defined(HAVE_SELECT) + fd_set fds; + int res; + struct timeval tv; + struct timeval *tvp; + + assert(event == AMQP_SF_POLLIN || event == AMQP_SF_POLLOUT); + +start_select: + FD_ZERO(&fds); + FD_SET(fd, &fds); + + res = amqp_time_tv_until(deadline, &tv, &tvp); + if (res != AMQP_STATUS_OK) { + return res; + } + + switch (event) { + case AMQP_SF_POLLIN: + res = select(fd + 1, &fds, NULL, NULL, tvp); + break; + case AMQP_SF_POLLOUT: + res = select(fd + 1, NULL, &fds, NULL, tvp); + } + + if (0 < res) { + return AMQP_STATUS_OK; + } else if (0 == res) { + return AMQP_STATUS_TIMEOUT; + } else { + switch (amqp_os_socket_error()) { + case EINTR: + goto start_select; + default: + return AMQP_STATUS_SOCKET_ERROR; + } + } + return AMQP_STATUS_OK; +#else +# error "poll() or select() is needed to compile rabbitmq-c" +#endif } static ssize_t do_poll(amqp_connection_state_t state, ssize_t res, diff --git a/m4/ax_have_poll.m4 b/m4/ax_have_poll.m4 new file mode 100644 index 0000000..14d3d4b --- /dev/null +++ b/m4/ax_have_poll.m4 @@ -0,0 +1,72 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_have_poll.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_HAVE_POLL([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# AX_HAVE_PPOLL([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# DESCRIPTION +# +# This macro determines whether the system supports the poll I/O event +# interface. A neat usage example would be: +# +# AX_HAVE_POLL( +# [AX_CONFIG_FEATURE_ENABLE(poll)], +# [AX_CONFIG_FEATURE_DISABLE(poll)]) +# AX_CONFIG_FEATURE( +# [poll], [This platform supports poll(7)], +# [HAVE_POLL], [This platform supports poll(7).]) +# +# Some systems -- most notably Linux kernel 2.6.16 and later -- also have +# the variant ppoll(). The availability of that function can be tested +# with the second macro. Generally speaking, it is safe to assume that +# AX_HAVE_POLL would succeed if AX_HAVE_PPOLL has, but not the other way +# round. +# +# LICENSE +# +# Copyright (c) 2009 Peter Simons +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +AC_DEFUN([AX_HAVE_POLL], [dnl + AC_MSG_CHECKING([for poll(2)]) + AC_CACHE_VAL([ax_cv_have_poll], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM( + [#include ], + [int rc; rc = poll((struct pollfd *)(0), 0, 0);])], + [ax_cv_have_poll=yes], + [ax_cv_have_poll=no])]) + AS_IF([test "${ax_cv_have_poll}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +])dnl + +AC_DEFUN([AX_HAVE_PPOLL], [dnl + AC_MSG_CHECKING([for ppoll(2)]) + AC_CACHE_VAL([ax_cv_have_ppoll], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM( + [dnl +#include +#include ], + [dnl +int rc; +rc = poll((struct pollfd *)(0), 0, 0); +rc = ppoll((struct pollfd *)(0), 0, (struct timespec const *)(0), (sigset_t const *)(0));])], + [ax_cv_have_ppoll=yes], + [ax_cv_have_ppoll=no])]) + AS_IF([test "${ax_cv_have_ppoll}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +]) diff --git a/m4/ax_have_select.m4 b/m4/ax_have_select.m4 new file mode 100644 index 0000000..4024212 --- /dev/null +++ b/m4/ax_have_select.m4 @@ -0,0 +1,71 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_have_select.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_HAVE_SELECT([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# AX_HAVE_PSELECT([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# DESCRIPTION +# +# This macro determines whether the system supports the select I/O event +# interface. A neat usage example would be: +# +# AX_HAVE_SELECT( +# [AX_CONFIG_FEATURE_ENABLE(select)], +# [AX_CONFIG_FEATURE_DISABLE(select)]) +# AX_CONFIG_FEATURE( +# [select], [This platform supports select(7)], +# [HAVE_SELECT], [This platform supports select(7).]) +# +# Some systems also have the variant pselect(). The availability of that +# function can be tested with the second macro. Generally speaking, it is +# safe to assume that AX_HAVE_SELECT would succeed if AX_HAVE_SELECT_PWAIT +# has, but not the other way round. +# +# LICENSE +# +# Copyright (c) 2009 Peter Simons +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +AC_DEFUN([AX_HAVE_SELECT], [dnl + AC_MSG_CHECKING([for select(2)]) + AC_CACHE_VAL([ax_cv_have_select], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM( + [#include ], + [int rc; rc = select(0, (fd_set *)(0), (fd_set *)(0), (fd_set *)(0), (struct timeval *)(0));])], + [ax_cv_have_select=yes], + [ax_cv_have_select=no])]) + AS_IF([test "${ax_cv_have_select}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +])dnl + +AC_DEFUN([AX_HAVE_PSELECT], [dnl + AC_MSG_CHECKING([for pselect(2)]) + AC_CACHE_VAL([ax_cv_have_pselect], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM( + [dnl +#include +#include ], + [dnl +int rc; +rc = select(0, (fd_set *)(0), (fd_set *)(0), (fd_set *)(0), (struct timeval *)(0)); +rc = pselect(0, (fd_set *)(0), (fd_set *)(0), (fd_set *)(0), (struct timespec const *)(0), (sigset_t const *)(0));])], + [ax_cv_have_pselect=yes], + [ax_cv_have_pselect=no])]) + AS_IF([test "${ax_cv_have_pselect}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +])dnl -- cgit v1.2.1