add suspend_resume_epoll example (from mailinglist)

This commit is contained in:
Christian Grothoff
2018-03-14 05:31:09 +01:00
parent 7d7ccbcdbd
commit 8abd74f3dc
6 changed files with 239 additions and 51 deletions
+1
View File
@@ -46,3 +46,4 @@ po/POTFILES
po/configargs.stamp
**~
doc/libmicrohttpd.log
src/examples/suspend_resume_epoll
+1
View File
@@ -57,6 +57,7 @@ Denis Dowling <denis.dowling@hsd.com.au>
Louis Benoit <louisbenoit@videotron.ca>
Flavio Coelin <flavio.ceolin@intel.com>
Silvio Clecio <silvioprog@gmail.com>
Robert D Kosisko <rkocisko@gmail.com>
Documentation contributions also came from:
Marco Maggi <marco.maggi-ipsu@poste.it>
+2
View File
@@ -735,6 +735,8 @@ if test "$enable_epoll" != "no"; then
fi
fi
AM_CONDITIONAL([MHD_HAVE_EPOLL], [[test "x$enable_epoll" = xyes]])
if test "x$enable_epoll" = "xyes"; then
AC_CACHE_CHECK([for epoll_create1()], [mhd_cv_have_epoll_create1], [
AC_LINK_IFELSE([
+21 -51
View File
@@ -1,19 +1,20 @@
# Makefile for PO directory in any package using GNU gettext.
# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
#
# 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.
# This file can be copied and used freely without restrictions. It can
# be used in projects which are not available under the GNU General Public
# License but which still want to provide support for the GNU gettext
# functionality.
# Please note that the actual code of GNU gettext is covered by the GNU
# General Public License and is *not* in the public domain.
#
# Origin: gettext-0.19.8
GETTEXT_MACRO_VERSION = 0.19
# Origin: gettext-0.18.2
GETTEXT_MACRO_VERSION = 0.18
PACKAGE = @PACKAGE@
VERSION = @VERSION@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
SED = @SED@
SHELL = /bin/sh
@SET_MAKE@
@@ -43,11 +44,6 @@ install_sh = $(SHELL) @install_sh@
MKDIR_P = @MKDIR_P@
mkdir_p = @mkdir_p@
# When building gettext-tools, we prefer to use the built programs
# rather than installed programs. However, we can't do that when we
# are cross compiling.
CROSS_COMPILING = @CROSS_COMPILING@
GMSGFMT_ = @GMSGFMT@
GMSGFMT_no = @GMSGFMT@
GMSGFMT_yes = @GMSGFMT_015@
@@ -80,16 +76,6 @@ POTFILES = \
CATALOGS = @CATALOGS@
POFILESDEPS_ = $(srcdir)/$(DOMAIN).pot
POFILESDEPS_yes = $(POFILESDEPS_)
POFILESDEPS_no =
POFILESDEPS = $(POFILESDEPS_$(PO_DEPENDS_ON_POT))
DISTFILESDEPS_ = update-po
DISTFILESDEPS_yes = $(DISTFILESDEPS_)
DISTFILESDEPS_no =
DISTFILESDEPS = $(DISTFILESDEPS_$(DIST_DEPENDS_ON_UPDATE_PO))
# Makevars gets inserted here. (Don't remove this line!)
.SUFFIXES:
@@ -156,25 +142,15 @@ stamp-po: $(srcdir)/$(DOMAIN).pot
# heuristic whether some file in the top level directory mentions "GNU xyz".
# If GNU 'find' is available, we avoid grepping through monster files.
$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed
package_gnu="$(PACKAGE_GNU)"; \
test -n "$$package_gnu" || { \
if { if (LC_ALL=C find --version) 2>/dev/null | grep GNU >/dev/null; then \
LC_ALL=C find -L $(top_srcdir) -maxdepth 1 -type f \
-size -10000000c -exec grep 'GNU @PACKAGE@' \
/dev/null '{}' ';' 2>/dev/null; \
else \
LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null; \
fi; \
} | grep -v 'libtool:' >/dev/null; then \
package_gnu=yes; \
else \
package_gnu=no; \
fi; \
}; \
if test "$$package_gnu" = "yes"; then \
package_prefix='GNU '; \
if { if (LC_ALL=C find --version) 2>/dev/null | grep GNU >/dev/null; then \
LC_ALL=C find -L $(top_srcdir) -maxdepth 1 -type f -size -10000000c -exec grep 'GNU @PACKAGE@' /dev/null '{}' ';' 2>/dev/null; \
else \
LC_ALL=C grep 'GNU @PACKAGE@' $(top_srcdir)/* 2>/dev/null; \
fi; \
} | grep -v 'libtool:' >/dev/null; then \
package_gnu='GNU '; \
else \
package_prefix=''; \
package_gnu=''; \
fi; \
if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \
msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \
@@ -194,17 +170,12 @@ $(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed
--add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) @XGETTEXT_EXTRA_OPTIONS@ \
--files-from=$(srcdir)/POTFILES.in \
--copyright-holder='$(COPYRIGHT_HOLDER)' \
--package-name="$${package_prefix}@PACKAGE@" \
--package-name="$${package_gnu}@PACKAGE@" \
--package-version='@VERSION@' \
--msgid-bugs-address="$$msgid_bugs_address" \
;; \
esac
test ! -f $(DOMAIN).po || { \
if test -f $(srcdir)/$(DOMAIN).pot-header; then \
sed -e '1,/^#$$/d' < $(DOMAIN).po > $(DOMAIN).1po && \
cat $(srcdir)/$(DOMAIN).pot-header $(DOMAIN).1po > $(DOMAIN).po; \
rm -f $(DOMAIN).1po; \
fi; \
if test -f $(srcdir)/$(DOMAIN).pot; then \
sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \
sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \
@@ -227,14 +198,13 @@ $(srcdir)/$(DOMAIN).pot:
# This target rebuilds a PO file if $(DOMAIN).pot has changed.
# Note that a PO file is not touched if it doesn't need to be changed.
$(POFILES): $(POFILESDEPS)
$(POFILES): $(srcdir)/$(DOMAIN).pot
@lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
if test -f "$(srcdir)/$${lang}.po"; then \
test -f $(srcdir)/$(DOMAIN).pot || $(MAKE) $(srcdir)/$(DOMAIN).pot; \
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \
cd $(srcdir) \
&& { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
&& { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \
*) \
@@ -391,7 +361,7 @@ maintainer-clean: distclean
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
dist distdir:
test -z "$(DISTFILESDEPS)" || $(MAKE) $(DISTFILESDEPS)
$(MAKE) update-po
@$(MAKE) dist2
# This is a separate target because 'update-po' must be executed before.
dist2: stamp-po $(DISTFILES)
@@ -435,7 +405,7 @@ update-po: Makefile
.nop.po-update:
@lang=`echo $@ | sed -e 's/\.po-update$$//'`; \
if test "$(PACKAGE)" = "gettext-tools" && test "$(CROSS_COMPILING)" != "yes"; then PATH=`pwd`/../src:$$PATH; fi; \
if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \
tmpdir=`pwd`; \
echo "$$lang:"; \
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
+12
View File
@@ -29,6 +29,11 @@ noinst_PROGRAMS = \
fileserver_example_external_select \
refuse_post_example
if MHD_HAVE_EPOLL
noinst_PROGRAMS += \
suspend_resume_epoll
endif
EXTRA_DIST = msgs_i18n.c
noinst_EXTRA_DIST = msgs_i18n.c
@@ -123,6 +128,13 @@ benchmark_CPPFLAGS = \
benchmark_LDADD = \
$(top_builddir)/src/microhttpd/libmicrohttpd.la
suspend_resume_epoll_SOURCES = \
suspend_resume_epoll.c
suspend_resume_epoll_CPPFLAGS = \
$(AM_CPPFLAGS) $(CPU_COUNT_DEF)
suspend_resume_epoll_LDADD = \
$(top_builddir)/src/microhttpd/libmicrohttpd.la
benchmark_https_SOURCES = \
benchmark_https.c
benchmark_https_CPPFLAGS = \
+202
View File
@@ -0,0 +1,202 @@
/*
This file is part of libmicrohttpd
Copyright (C) 2018 Christian Grothoff (and other contributing authors)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file suspend_resume_epoll.c
* @brief example for how to use libmicrohttpd with epoll() and
* resume a suspended connection
* @author Robert D Kocisko
* @author Christian Grothoff
*/
#include "platform.h"
#include <microhttpd.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <limits.h>
#define TIMEOUT_INFINITE -1
struct Request {
struct MHD_Connection *connection;
int timerfd;
};
static int epfd;
static struct epoll_event evt;
static int
ahc_echo (void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *version,
const char *upload_data, size_t *upload_data_size, void **ptr)
{
struct MHD_Response *response;
int ret;
struct Request* req;
struct itimerspec ts;
(void)url; /* Unused. Silence compiler warning. */
(void)version; /* Unused. Silence compiler warning. */
(void)upload_data; /* Unused. Silence compiler warning. */
(void)upload_data_size; /* Unused. Silence compiler warning. */
req = *ptr;
if (!req)
{
req = malloc(sizeof(struct Request));
req->connection = connection;
req->timerfd = 0;
*ptr = req;
return MHD_YES;
}
if (req->timerfd)
{
// send response (echo request url)
response = MHD_create_response_from_buffer (strlen (url),
(void *) url,
MHD_RESPMEM_MUST_COPY);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
return ret;
}
else
{
// create timer and suspend connection
req->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (-1 == req->timerfd)
{
printf("timerfd_create: %s", strerror(errno));
return MHD_NO;
}
evt.events = EPOLLIN;
evt.data.ptr = req;
if (-1 == epoll_ctl(epfd, EPOLL_CTL_ADD, req->timerfd, &evt))
{
printf("epoll_ctl: %s", strerror(errno));
return MHD_NO;
}
ts.it_value.tv_sec = 1;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
if (-1 == timerfd_settime(req->timerfd, 0, &ts, NULL))
{
printf("timerfd_settime: %s", strerror(errno));
return MHD_NO;
}
MHD_suspend_connection(connection);
return MHD_YES;
}
}
static int
connection_done(struct MHD_Connection *connection,
void **con_cls,
enum MHD_RequestTerminationCode toe)
{
free(*con_cls);
}
int
main (int argc,
char *const *argv)
{
struct MHD_Daemon *d;
const union MHD_DaemonInfo * info;
int current_event_count;
struct epoll_event events_list[1];
struct Request *req;
uint64_t timer_expirations;
if (argc != 2)
{
printf ("%s PORT\n", argv[0]);
return 1;
}
d = MHD_start_daemon (MHD_USE_EPOLL | MHD_ALLOW_SUSPEND_RESUME,
atoi (argv[1]),
NULL, NULL, &ahc_echo, NULL,
MHD_OPTION_NOTIFY_COMPLETED, &connection_done, NULL,
MHD_OPTION_END);
if (d == NULL)
return 1;
info = MHD_get_daemon_info(d, MHD_DAEMON_INFO_EPOLL_FD);
if (info == NULL)
return 1;
epfd = epoll_create1(EPOLL_CLOEXEC);
if (-1 == epfd)
return 1;
evt.events = EPOLLIN;
evt.data.ptr = NULL;
if (-1 == epoll_ctl(epfd, EPOLL_CTL_ADD, info->epoll_fd, &evt))
return 1;
while (1)
{
int timeout;
MHD_UNSIGNED_LONG_LONG to;
if (MHD_YES !=
MHD_get_timeout (d,
&to))
timeout = TIMEOUT_INFINITE;
else
timeout = (to < INT_MAX - 1) ? (int) to : (INT_MAX - 1);
current_event_count = epoll_wait(epfd, events_list, 1, timeout);
if (1 == current_event_count)
{
if (events_list[0].data.ptr)
{
// A timer has timed out
req = events_list[0].data.ptr;
// read from the fd so the system knows we heard the notice
if (-1 == read(req->timerfd, &timer_expirations, sizeof(timer_expirations)))
{
return 1;
}
// Now resume the connection
MHD_resume_connection(req->connection);
}
}
else if (0 == current_event_count)
{
// no events: continue
}
else
{
// error
return 1;
}
if (! MHD_run(d))
return 1;
}
return 0;
}