diff --git a/configure.ac b/configure.ac index 810c437b4..3c7151ae1 100644 --- a/configure.ac +++ b/configure.ac @@ -88,6 +88,38 @@ AC_MSG_RESULT($enable_expensive) AM_CONDITIONAL([HAVE_EXPENSIVE_TESTS], [test "x$enable_expensive" = "xyes"]) +AC_ARG_ENABLE([[epoll]], + [AS_HELP_STRING([[--enable-epoll[=ARG]]], [enable epoll support (yes, no, auto) [auto]])], + [enable_epoll=${enableval}], + [enable_epoll='auto'] + ) + +AS_IF([test "$enable_epoll" != "no"], + [AX_HAVE_EPOLL + AS_IF([test "${ax_cv_have_epoll}" = "yes"], + [AC_DEFINE([[EPOLL_SUPPORT]],[[1]],[Define to 1 to enable epoll support]) + enable_epoll='yes'], + [AS_IF([test "$enable_epoll" = "yes"], + AC_MSG_ERROR([[Support for epoll was explicitly requested but cannot be enabled on this platform.]])) + enable_epoll='no'])]) + +AM_CONDITIONAL([MHD_HAVE_EPOLL], [[test "x$enable_epoll" = xyes]]) + +AS_IF([test "x$enable_epoll" = "xyes"], + AC_CACHE_CHECK([for epoll_create1()], + [mhd_cv_have_epoll_create1], [ + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ +#include + ]], [[ +int fd; +fd = epoll_create1(EPOLL_CLOEXEC);]])], + [mhd_cv_have_epoll_create1=yes], + [mhd_cv_have_epoll_create1=no])]) + AS_IF([test "x$mhd_cv_have_epoll_create1" = "xyes"],[ + AC_DEFINE([[HAVE_EPOLL_CREATE1]], [[1]], [Define if you have epoll_create1 function.])])) + + if test "$wallet_only" != yes then diff --git a/m4/ax_have_epoll.m4 b/m4/ax_have_epoll.m4 new file mode 100644 index 000000000..9d9bc8736 --- /dev/null +++ b/m4/ax_have_epoll.m4 @@ -0,0 +1,104 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_have_epoll.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_HAVE_EPOLL([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# AX_HAVE_EPOLL_PWAIT([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# DESCRIPTION +# +# This macro determines whether the system supports the epoll I/O event +# interface. A neat usage example would be: +# +# AX_HAVE_EPOLL( +# [AX_CONFIG_FEATURE_ENABLE(epoll)], +# [AX_CONFIG_FEATURE_DISABLE(epoll)]) +# AX_CONFIG_FEATURE( +# [epoll], [This platform supports epoll(7)], +# [HAVE_EPOLL], [This platform supports epoll(7).]) +# +# The epoll interface was added to the Linux kernel in version 2.5.45, and +# the macro verifies that a kernel newer than this is installed. This +# check is somewhat unreliable if doesn't match the +# running kernel, but it is necessary regardless, because glibc comes with +# stubs for the epoll_create(), epoll_wait(), etc. that allow programs to +# compile and link even if the kernel is too old; the problem would then +# be detected only at runtime. +# +# Linux kernel version 2.6.19 adds the epoll_pwait() call in addition to +# epoll_wait(). The availability of that function can be tested with the +# second macro. Generally speaking, it is safe to assume that +# AX_HAVE_EPOLL would succeed if AX_HAVE_EPOLL_PWAIT has, but not the +# other way round. +# +# LICENSE +# +# Copyright (c) 2008 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 11 + +AC_DEFUN([AX_HAVE_EPOLL], [dnl + ax_have_epoll_cppflags="${CPPFLAGS}" + AC_CHECK_HEADER([linux/version.h], [CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"]) + AC_MSG_CHECKING([for Linux epoll(7) interface]) + AC_CACHE_VAL([ax_cv_have_epoll], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM([dnl +#include +#ifdef HAVE_LINUX_VERSION_H +# include +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45) +# error linux kernel version is too old to have epoll +# endif +#endif +], [dnl +int fd, rc; +struct epoll_event ev; +fd = epoll_create(128); +rc = epoll_wait(fd, &ev, 1, 0);])], + [ax_cv_have_epoll=yes], + [ax_cv_have_epoll=no])]) + CPPFLAGS="${ax_have_epoll_cppflags}" + AS_IF([test "${ax_cv_have_epoll}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +])dnl + +AC_DEFUN([AX_HAVE_EPOLL_PWAIT], [dnl + ax_have_epoll_cppflags="${CPPFLAGS}" + AC_CHECK_HEADER([linux/version.h], + [CPPFLAGS="${CPPFLAGS} -DHAVE_LINUX_VERSION_H"]) + AC_MSG_CHECKING([for Linux epoll(7) interface with signals extension]) + AC_CACHE_VAL([ax_cv_have_epoll_pwait], [dnl + AC_LINK_IFELSE([dnl + AC_LANG_PROGRAM([dnl +#ifdef HAVE_LINUX_VERSION_H +# include +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +# error linux kernel version is too old to have epoll_pwait +# endif +#endif +#include +#include +], [dnl +int fd, rc; +struct epoll_event ev; +fd = epoll_create(128); +rc = epoll_wait(fd, &ev, 1, 0); +rc = epoll_pwait(fd, &ev, 1, 0, (sigset_t const *)(0));])], + [ax_cv_have_epoll_pwait=yes], + [ax_cv_have_epoll_pwait=no])]) + CPPFLAGS="${ax_have_epoll_cppflags}" + AS_IF([test "${ax_cv_have_epoll_pwait}" = "yes"], + [AC_MSG_RESULT([yes]) +$1],[AC_MSG_RESULT([no]) +$2]) +])dnl diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index 2a8164684..6f9959ab8 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2016, 2017 Inria and GNUnet e.V. + (C) 2016, 2017, 2018 Inria and GNUnet e.V. TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,7 +19,6 @@ * @brief library that fakes being a Taler bank for testcases * @author Christian Grothoff */ - #include "platform.h" #include "taler_fakebank_lib.h" #include "taler_bank_service.h" @@ -125,6 +124,18 @@ struct TALER_FAKEBANK_Handle * Number of transactions. */ uint64_t serial_counter; + +#if EPOLL_SUPPORT + /** + * Boxed @e mhd_fd. + */ + struct GNUNET_NETWORK_Handle *mhd_rfd; + + /** + * File descriptor to use to wait for MHD. + */ + int mhd_fd; +#endif }; @@ -328,6 +339,9 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h) GNUNET_SCHEDULER_cancel (h->mhd_task); h->mhd_task = NULL; } +#if EPOLL_SUPPORT + GNUNET_NETWORK_socket_free_memory_only_ (h->mhd_rfd); +#endif if (NULL != h->mhd_bank) { MHD_stop_daemon (h->mhd_bank); @@ -976,10 +990,42 @@ static void run_mhd (void *cls); +#if EPOLL_SUPPORT /** * Schedule MHD. This function should be called initially when an * MHD is first getting its client socket, and will then automatically * always be called later whenever there is work to be done. + * + * @param h fakebank handle to schedule MHD for + */ +static void +schedule_httpd (struct TALER_FAKEBANK_Handle *h) +{ + int haveto; + MHD_UNSIGNED_LONG_LONG timeout; + struct GNUNET_TIME_Relative tv; + + haveto = MHD_get_timeout (h->mhd_bank, + &timeout); + if (MHD_YES == haveto) + tv.rel_value_us = (uint64_t) timeout * 1000LL; + else + tv = GNUNET_TIME_UNIT_FOREVER_REL; + if (NULL != h->mhd_task) + GNUNET_SCHEDULER_cancel (h->mhd_task); + h->mhd_task = + GNUNET_SCHEDULER_add_read_net (tv, + h->mhd_rfd, + &run_mhd, + h); +} +#else +/** + * Schedule MHD. This function should be called initially when an + * MHD is first getting its client socket, and will then automatically + * always be called later whenever there is work to be done. + * + * @param h fakebank handle to schedule MHD for */ static void schedule_httpd (struct TALER_FAKEBANK_Handle *h) @@ -1033,6 +1079,7 @@ schedule_httpd (struct TALER_FAKEBANK_Handle *h) if (NULL != wws) GNUNET_NETWORK_fdset_destroy (wws); } +#endif /** @@ -1063,7 +1110,11 @@ TALER_FAKEBANK_start (uint16_t port) struct TALER_FAKEBANK_Handle *h; h = GNUNET_new (struct TALER_FAKEBANK_Handle); - h->mhd_bank = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_DUAL_STACK, + h->mhd_bank = MHD_start_daemon (MHD_USE_DEBUG +#if EPOLL_SUPPORT + | MHD_USE_EPOLL +#endif + | MHD_USE_DUAL_STACK, port, NULL, NULL, &handle_mhd_request, h, @@ -1075,6 +1126,11 @@ TALER_FAKEBANK_start (uint16_t port) GNUNET_free (h); return NULL; } +#if EPOLL_SUPPORT + h->mhd_fd = MHD_get_daemon_info (h->mhd_bank, + MHD_DAEMON_INFO_EPOLL_FD)->epoll_fd; + h->mhd_rfd = GNUNET_NETWORK_socket_box_native (h->mhd_fd); +#endif schedule_httpd (h); return h; }